From d7a74be09b3c3d5ad015be31c51208260aa85007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 4 Sep 2018 10:41:33 -0700 Subject: [PATCH 01/28] Fix incorrect outer function type parameter message --- src/librustc_resolve/lib.rs | 9 ++++++++- src/test/ui/error-codes/E0401.stderr | 7 ++++--- src/test/ui/issues/issue-12796.stderr | 7 ++++--- src/test/ui/use-self-in-inner-fn.rs | 24 ++++++++++++++++++++++++ src/test/ui/use-self-in-inner-fn.stderr | 15 +++++++++++++++ 5 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/use-self-in-inner-fn.rs create mode 100644 src/test/ui/use-self-in-inner-fn.stderr diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0f6a974230917..19a4fdae48596 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -197,6 +197,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, err.span_label(span, "use of type variable from outer function"); let cm = resolver.session.source_map(); + let mut is_self = false; match outer_def { Def::SelfTy(_, maybe_impl_defid) => { if let Some(impl_span) = maybe_impl_defid.map_or(None, @@ -204,6 +205,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, err.span_label(reduce_impl_span_to_impl_keyword(cm, impl_span), "`Self` type implicitly declared here, on the `impl`"); } + is_self = true; }, Def::TyParam(typaram_defid) => { if let Some(typaram_span) = resolver.definitions.opt_span(typaram_defid) { @@ -219,7 +221,12 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, // Try to retrieve the span of the function signature and generate a new message with // a local type parameter let sugg_msg = "try using a local type parameter instead"; - if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) { + if is_self { + // Suggest using the actual type + err.span_label(span, "use a materialized type here instead"); + } else if let Some( + (sugg_span, new_snippet), + ) = cm.generate_local_type_param_snippet(span) { // Suggest the modification to the user err.span_suggestion_with_applicability( sugg_span, diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr index b088e8330e998..90e8d2d2479da 100644 --- a/src/test/ui/error-codes/E0401.stderr +++ b/src/test/ui/error-codes/E0401.stderr @@ -27,9 +27,10 @@ LL | impl Iterator for A { | ---- `Self` type implicitly declared here, on the `impl` ... LL | fn helper(sel: &Self) -> u8 { //~ ERROR E0401 - | ------ ^^^^ use of type variable from outer function - | | - | help: try using a local type parameter instead: `helper` + | ^^^^ + | | + | use of type variable from outer function + | use a materialized type here instead error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-12796.stderr b/src/test/ui/issues/issue-12796.stderr index c8bedd3853c68..078c1db5de594 100644 --- a/src/test/ui/issues/issue-12796.stderr +++ b/src/test/ui/issues/issue-12796.stderr @@ -2,9 +2,10 @@ error[E0401]: can't use type parameters from outer function --> $DIR/issue-12796.rs:13:22 | LL | fn inner(_: &Self) { - | ----- ^^^^ use of type variable from outer function - | | - | help: try using a local type parameter instead: `inner` + | ^^^^ + | | + | use of type variable from outer function + | use a materialized type here instead error: aborting due to previous error diff --git a/src/test/ui/use-self-in-inner-fn.rs b/src/test/ui/use-self-in-inner-fn.rs new file mode 100644 index 0000000000000..a1183854eb50a --- /dev/null +++ b/src/test/ui/use-self-in-inner-fn.rs @@ -0,0 +1,24 @@ +// 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. + +struct A; + +impl A { +//~^ NOTE `Self` type implicitly declared here, on the `impl` + fn banana(&mut self) { + fn peach(this: &Self) { + //~^ ERROR can't use type parameters from outer function + //~| NOTE use of type variable from outer function + //~| NOTE use a materialized type here instead + } + } +} + +fn main() {} diff --git a/src/test/ui/use-self-in-inner-fn.stderr b/src/test/ui/use-self-in-inner-fn.stderr new file mode 100644 index 0000000000000..c14e4895d9930 --- /dev/null +++ b/src/test/ui/use-self-in-inner-fn.stderr @@ -0,0 +1,15 @@ +error[E0401]: can't use type parameters from outer function + --> $DIR/use-self-in-inner-fn.rs:16:25 + | +LL | impl A { + | ---- `Self` type implicitly declared here, on the `impl` +... +LL | fn peach(this: &Self) { + | ^^^^ + | | + | use of type variable from outer function + | use a materialized type here instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0401`. From 5238b523c3959e33add469af77b2ffa5a60b4cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 26 Aug 2018 17:22:36 -0700 Subject: [PATCH 02/28] Reword un-closed delimiter label --- src/libsyntax/parse/lexer/tokentrees.rs | 4 ++-- src/test/ui/issue-10636-1.rs | 3 ++- src/test/ui/issue-10636-1.stderr | 8 ++++---- src/test/ui/parser-recovery-1.rs | 9 +++++---- src/test/ui/parser-recovery-1.stderr | 17 +++++++---------- src/test/ui/parser-recovery-2.stderr | 2 +- .../ui/resolve/token-error-correct-2.stderr | 2 +- .../ui/resolve/token-error-correct-3.stderr | 2 +- src/test/ui/resolve/token-error-correct.stderr | 2 +- src/test/ui/token/issue-10636-2.stderr | 2 +- 10 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index e2fd7faf90387..e8404adec0f89 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -49,7 +49,7 @@ impl<'a> StringReader<'a> { let msg = "this file contains an un-closed delimiter"; let mut err = self.sess.span_diagnostic.struct_span_err(self.span, msg); for &(_, sp) in &self.open_braces { - err.span_help(sp, "did you mean to close this delimiter?"); + err.span_label(sp, "un-closed delimiter"); } Err(err) @@ -94,7 +94,7 @@ impl<'a> StringReader<'a> { // delimiter. The previous unclosed delimiters could actually be // closed! The parser just hasn't gotten to them yet. if let Some(&(_, sp)) = self.open_braces.last() { - err.span_label(sp, "unclosed delimiter"); + err.span_label(sp, "un-closed delimiter"); }; err.emit(); } diff --git a/src/test/ui/issue-10636-1.rs b/src/test/ui/issue-10636-1.rs index fdd50773593a8..375b951ee1585 100644 --- a/src/test/ui/issue-10636-1.rs +++ b/src/test/ui/issue-10636-1.rs @@ -10,7 +10,8 @@ // compile-flags: -Z parse-only -struct Obj { //~ NOTE: unclosed delimiter +struct Obj { + //~^ NOTE: un-closed delimiter member: usize ) //~^ ERROR incorrect close delimiter diff --git a/src/test/ui/issue-10636-1.stderr b/src/test/ui/issue-10636-1.stderr index af80e259fbd25..49b6d08aff505 100644 --- a/src/test/ui/issue-10636-1.stderr +++ b/src/test/ui/issue-10636-1.stderr @@ -1,9 +1,9 @@ error: incorrect close delimiter: `)` - --> $DIR/issue-10636-1.rs:15:1 + --> $DIR/issue-10636-1.rs:16:1 | -LL | struct Obj { //~ NOTE: unclosed delimiter - | - unclosed delimiter -LL | member: usize +LL | struct Obj { + | - un-closed delimiter +... LL | ) | ^ incorrect close delimiter diff --git a/src/test/ui/parser-recovery-1.rs b/src/test/ui/parser-recovery-1.rs index 9fb4d6facddab..f51bcb9e70cad 100644 --- a/src/test/ui/parser-recovery-1.rs +++ b/src/test/ui/parser-recovery-1.rs @@ -14,11 +14,12 @@ trait Foo { fn bar() { - let x = foo(); //~ ERROR cannot find function `foo` in this scope - + let x = foo(); + //~^ ERROR cannot find function `foo` in this scope } fn main() { - let x = y.; //~ ERROR unexpected token - //~^ ERROR cannot find value `y` in this scope + let x = y.; + //~^ ERROR unexpected token + //~| ERROR cannot find value `y` in this scope } //~ ERROR this file contains an un-closed delimiter diff --git a/src/test/ui/parser-recovery-1.stderr b/src/test/ui/parser-recovery-1.stderr index bf4070682fbb3..7d2f80148de33 100644 --- a/src/test/ui/parser-recovery-1.stderr +++ b/src/test/ui/parser-recovery-1.stderr @@ -1,31 +1,28 @@ error: this file contains an un-closed delimiter - --> $DIR/parser-recovery-1.rs:24:55 + --> $DIR/parser-recovery-1.rs:25:55 | +LL | trait Foo { + | - un-closed delimiter +... LL | } //~ ERROR this file contains an un-closed delimiter | ^ - | -help: did you mean to close this delimiter? - --> $DIR/parser-recovery-1.rs:15:11 - | -LL | trait Foo { - | ^ error: unexpected token: `;` --> $DIR/parser-recovery-1.rs:22:15 | -LL | let x = y.; //~ ERROR unexpected token +LL | let x = y.; | ^ error[E0425]: cannot find function `foo` in this scope --> $DIR/parser-recovery-1.rs:17:17 | -LL | let x = foo(); //~ ERROR cannot find function `foo` in this scope +LL | let x = foo(); | ^^^ not found in this scope error[E0425]: cannot find value `y` in this scope --> $DIR/parser-recovery-1.rs:22:13 | -LL | let x = y.; //~ ERROR unexpected token +LL | let x = y.; | ^ not found in this scope error[E0601]: `main` function not found in crate `parser_recovery_1` diff --git a/src/test/ui/parser-recovery-2.stderr b/src/test/ui/parser-recovery-2.stderr index 1025dad3af773..2965e4eb58124 100644 --- a/src/test/ui/parser-recovery-2.stderr +++ b/src/test/ui/parser-recovery-2.stderr @@ -2,7 +2,7 @@ error: incorrect close delimiter: `)` --> $DIR/parser-recovery-2.rs:18:5 | LL | fn bar() { - | - unclosed delimiter + | - un-closed delimiter LL | let x = foo(); //~ ERROR cannot find function `foo` in this scope LL | ) //~ ERROR incorrect close delimiter: `)` | ^ incorrect close delimiter diff --git a/src/test/ui/resolve/token-error-correct-2.stderr b/src/test/ui/resolve/token-error-correct-2.stderr index fcd4b4888b0ad..6965c864569c1 100644 --- a/src/test/ui/resolve/token-error-correct-2.stderr +++ b/src/test/ui/resolve/token-error-correct-2.stderr @@ -2,7 +2,7 @@ error: incorrect close delimiter: `)` --> $DIR/token-error-correct-2.rs:16:5 | LL | if foo { - | - unclosed delimiter + | - un-closed delimiter LL | //~^ ERROR: cannot find value `foo` LL | ) //~ ERROR: incorrect close delimiter: `)` | ^ incorrect close delimiter diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index a546c2704d915..b6946f62388a7 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -2,7 +2,7 @@ error: incorrect close delimiter: `}` --> $DIR/token-error-correct-3.rs:30:9 | LL | callback(path.as_ref(); //~ ERROR expected one of - | - unclosed delimiter + | - un-closed delimiter ... LL | } else { //~ ERROR: incorrect close delimiter: `}` | ^ incorrect close delimiter diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index 1e246b6f085bd..7081a5976294d 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -2,7 +2,7 @@ error: incorrect close delimiter: `}` --> $DIR/token-error-correct.rs:16:1 | LL | foo(bar(; - | - unclosed delimiter + | - un-closed delimiter LL | //~^ ERROR: expected expression, found `;` LL | } | ^ incorrect close delimiter diff --git a/src/test/ui/token/issue-10636-2.stderr b/src/test/ui/token/issue-10636-2.stderr index 634191bb5ef4e..10dc5f655698e 100644 --- a/src/test/ui/token/issue-10636-2.stderr +++ b/src/test/ui/token/issue-10636-2.stderr @@ -2,7 +2,7 @@ error: incorrect close delimiter: `}` --> $DIR/issue-10636-2.rs:18:1 | LL | option.map(|some| 42; - | - unclosed delimiter + | - un-closed delimiter ... LL | } //~ ERROR: incorrect close delimiter | ^ incorrect close delimiter From 008aa5a24e152691d852bd9f0a2990b6e4377397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 4 Sep 2018 08:09:49 -0700 Subject: [PATCH 03/28] Provide more context for unenclosed delimiters * When encountering EOF, point at the last opening brace that does not have the same indentation level as its close delimiter. * When encountering the wrong type of close delimiter, point at the likely correct open delimiter to give a better idea of what went wrong. --- src/libsyntax/parse/lexer/mod.rs | 5 +++ src/libsyntax/parse/lexer/tokentrees.rs | 40 ++++++++++++++++++- src/libsyntax/source_map.rs | 32 ++++++++++----- src/test/ui/parser-recovery-1.stderr | 5 +++ src/test/ui/parser/unclosed-braces.rs | 32 +++++++++++++++ src/test/ui/parser/unclosed-braces.stderr | 17 ++++++++ .../ui/resolve/token-error-correct-3.stderr | 2 + .../ui/resolve/token-error-correct.stderr | 2 + src/test/ui/token/issue-10636-2.stderr | 2 + 9 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/parser/unclosed-braces.rs create mode 100644 src/test/ui/parser/unclosed-braces.stderr diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 96584a580f175..b7e8a880e7e50 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -66,6 +66,10 @@ pub struct StringReader<'a> { /// The raw source span which *does not* take `override_span` into account span_src_raw: Span, open_braces: Vec<(token::DelimToken, Span)>, + /// The type and spans for all braces that have different indentation. + /// + /// Used only for error recovery when arriving to EOF with mismatched braces. + suspicious_open_spans: Vec<(token::DelimToken, Span, Span)>, crate override_span: Option, last_unclosed_found_span: Option, } @@ -216,6 +220,7 @@ impl<'a> StringReader<'a> { span: syntax_pos::DUMMY_SP, span_src_raw: syntax_pos::DUMMY_SP, open_braces: Vec::new(), + suspicious_open_spans: Vec::new(), override_span, last_unclosed_found_span: None, } diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index e8404adec0f89..2999e65ae4aea 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -52,6 +52,20 @@ impl<'a> StringReader<'a> { err.span_label(sp, "un-closed delimiter"); } + if let Some((delim, _)) = self.open_braces.last() { + if let Some((d, open_sp, close_sp)) = self.suspicious_open_spans.iter() + .filter(|(d, _, _)| delim == d) + .next() // these are in reverse order as they get inserted on close, but + { // we want the last open/first close + if d == delim { + err.span_label(*open_sp, "this might be the culprit..."); + err.span_label( + *close_sp, + "...as it matches this but it has different indentation", + ); + } + } + } Err(err) }, token::OpenDelim(delim) => { @@ -70,11 +84,20 @@ impl<'a> StringReader<'a> { // Expand to cover the entire delimited token tree let span = pre_span.with_hi(self.span.hi()); + let sm = self.sess.source_map(); match self.token { // Correct delimiter. token::CloseDelim(d) if d == delim => { - self.open_braces.pop().unwrap(); - + let (open_brace, open_brace_span) = self.open_braces.pop().unwrap(); + if let Some(current_padding) = sm.span_to_margin(self.span) { + if let Some(padding) = sm.span_to_margin(open_brace_span) { + if current_padding != padding { + self.suspicious_open_spans.push( + (open_brace, open_brace_span, self.span), + ); + } + } + } // Parse the close delimiter. self.real_token(); } @@ -96,6 +119,19 @@ impl<'a> StringReader<'a> { if let Some(&(_, sp)) = self.open_braces.last() { err.span_label(sp, "un-closed delimiter"); }; + if let Some(current_padding) = sm.span_to_margin(self.span) { + for (brace, brace_span) in &self.open_braces { + if let Some(padding) = sm.span_to_margin(*brace_span) { + // high likelihood of these two corresponding + if current_padding == padding && brace == &other { + err.span_label( + *brace_span, + "close delimiter possibly meant for this", + ); + } + } + } + } err.emit(); } self.open_braces.pop().unwrap(); diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs index 8f91db8efa71a..a33090ff41b7a 100644 --- a/src/libsyntax/source_map.rs +++ b/src/libsyntax/source_map.rs @@ -251,17 +251,18 @@ impl SourceMap { /// crate. The source code of such an "imported source_file" is not available, /// but we still know enough to generate accurate debuginfo location /// information for things inlined from other crates. - pub fn new_imported_source_file(&self, - filename: FileName, - name_was_remapped: bool, - crate_of_origin: u32, - src_hash: u128, - name_hash: u128, - source_len: usize, - mut file_local_lines: Vec, - mut file_local_multibyte_chars: Vec, - mut file_local_non_narrow_chars: Vec) - -> Lrc { + pub fn new_imported_source_file( + &self, + filename: FileName, + name_was_remapped: bool, + crate_of_origin: u32, + src_hash: u128, + name_hash: u128, + source_len: usize, + mut file_local_lines: Vec, + mut file_local_multibyte_chars: Vec, + mut file_local_non_narrow_chars: Vec, + ) -> Lrc { let start_pos = self.next_start_pos(); let end_pos = Pos::from_usize(start_pos + source_len); @@ -578,6 +579,15 @@ impl SourceMap { .to_string()) } + pub fn span_to_margin(&self, sp: Span) -> Option { + match self.span_to_prev_source(sp) { + Err(_) => None, + Ok(source) => source.split('\n').last().map(|last_line| { + last_line.len() - last_line.trim_left().len() + }) + } + } + /// Return the source snippet as `String` before the given `Span` pub fn span_to_prev_source(&self, sp: Span) -> Result { self.span_to_source(sp, |src, start_index, _| src[..start_index].to_string()) diff --git a/src/test/ui/parser-recovery-1.stderr b/src/test/ui/parser-recovery-1.stderr index 7d2f80148de33..d0247b86ac372 100644 --- a/src/test/ui/parser-recovery-1.stderr +++ b/src/test/ui/parser-recovery-1.stderr @@ -3,6 +3,11 @@ error: this file contains an un-closed delimiter | LL | trait Foo { | - un-closed delimiter +LL | fn bar() { + | - this might be the culprit... +... +LL | } + | - ...as it matches this but it has different indentation ... LL | } //~ ERROR this file contains an un-closed delimiter | ^ diff --git a/src/test/ui/parser/unclosed-braces.rs b/src/test/ui/parser/unclosed-braces.rs new file mode 100644 index 0000000000000..640894475846e --- /dev/null +++ b/src/test/ui/parser/unclosed-braces.rs @@ -0,0 +1,32 @@ +// 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. + +struct S { + x: [usize; 3], +} + +fn foo() { + { + { + println!("hi"); + } + } +} + +fn main() { +//~^ NOTE un-closed delimiter + { + { + //~^ NOTE this might be the culprit... + foo(); + } + //~^ NOTE ...as it matches this but it has different indentation +} +//~ ERROR this file contains an un-closed delimiter diff --git a/src/test/ui/parser/unclosed-braces.stderr b/src/test/ui/parser/unclosed-braces.stderr new file mode 100644 index 0000000000000..5d5ff24faa6dd --- /dev/null +++ b/src/test/ui/parser/unclosed-braces.stderr @@ -0,0 +1,17 @@ +error: this file contains an un-closed delimiter + --> $DIR/unclosed-braces.rs:32:53 + | +LL | fn main() { + | - un-closed delimiter +... +LL | { + | - this might be the culprit... +... +LL | } + | - ...as it matches this but it has different indentation +... +LL | //~ ERROR this file contains an un-closed delimiter + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index b6946f62388a7..b87a59d219655 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -1,6 +1,8 @@ error: incorrect close delimiter: `}` --> $DIR/token-error-correct-3.rs:30:9 | +LL | if !is_directory(path.as_ref()) { //~ ERROR: cannot find function `is_directory` + | - close delimiter possibly meant for this LL | callback(path.as_ref(); //~ ERROR expected one of | - un-closed delimiter ... diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index 7081a5976294d..b69098407323a 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -1,6 +1,8 @@ error: incorrect close delimiter: `}` --> $DIR/token-error-correct.rs:16:1 | +LL | fn main() { + | - close delimiter possibly meant for this LL | foo(bar(; | - un-closed delimiter LL | //~^ ERROR: expected expression, found `;` diff --git a/src/test/ui/token/issue-10636-2.stderr b/src/test/ui/token/issue-10636-2.stderr index 10dc5f655698e..9800b0c5e3f05 100644 --- a/src/test/ui/token/issue-10636-2.stderr +++ b/src/test/ui/token/issue-10636-2.stderr @@ -1,6 +1,8 @@ error: incorrect close delimiter: `}` --> $DIR/issue-10636-2.rs:18:1 | +LL | pub fn trace_option(option: Option) { + | - close delimiter possibly meant for this LL | option.map(|some| 42; | - un-closed delimiter ... From b2d2d837235d0b06e56bb3191aff7ae358ac6018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 5 Sep 2018 07:03:02 -0700 Subject: [PATCH 04/28] Fix existing test --- src/test/{parse-fail => ui}/issue-2354.rs | 4 +++- src/test/ui/issue-2354.stderr | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) rename src/test/{parse-fail => ui}/issue-2354.rs (82%) create mode 100644 src/test/ui/issue-2354.stderr diff --git a/src/test/parse-fail/issue-2354.rs b/src/test/ui/issue-2354.rs similarity index 82% rename from src/test/parse-fail/issue-2354.rs rename to src/test/ui/issue-2354.rs index 2e799a72c81af..418f30df22bf7 100644 --- a/src/test/parse-fail/issue-2354.rs +++ b/src/test/ui/issue-2354.rs @@ -10,11 +10,13 @@ // compile-flags: -Z parse-only -fn foo() { //~ HELP did you mean to close this delimiter? +fn foo() { //~ NOTE un-closed delimiter match Some(x) { + //~^ NOTE this might be the culprit... Some(y) => { panic!(); } None => { panic!(); } } +//~^ NOTE ...as it matches this but it has different indentation fn bar() { let mut i = 0; diff --git a/src/test/ui/issue-2354.stderr b/src/test/ui/issue-2354.stderr new file mode 100644 index 0000000000000..720f37da9d389 --- /dev/null +++ b/src/test/ui/issue-2354.stderr @@ -0,0 +1,16 @@ +error: this file contains an un-closed delimiter + --> $DIR/issue-2354.rs:26:66 + | +LL | fn foo() { //~ NOTE un-closed delimiter + | - un-closed delimiter +LL | match Some(x) { + | - this might be the culprit... +... +LL | } + | - ...as it matches this but it has different indentation +... +LL | fn main() {} //~ ERROR this file contains an un-closed delimiter + | ^ + +error: aborting due to previous error + From 3192d3dc0c4417a6e360018b341c07d32f3f3d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 5 Sep 2018 07:33:29 -0700 Subject: [PATCH 05/28] Change wording of unclosed delimiter label --- src/libsyntax/parse/lexer/tokentrees.rs | 5 ++++- src/test/ui/issue-2354.rs | 2 +- src/test/ui/issue-2354.stderr | 2 +- src/test/ui/parser-recovery-1.stderr | 2 +- src/test/ui/parser/unclosed-braces.rs | 2 +- src/test/ui/parser/unclosed-braces.stderr | 2 +- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index 2999e65ae4aea..e6ad3b9203ea7 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -58,7 +58,10 @@ impl<'a> StringReader<'a> { .next() // these are in reverse order as they get inserted on close, but { // we want the last open/first close if d == delim { - err.span_label(*open_sp, "this might be the culprit..."); + err.span_label( + *open_sp, + "this delimiter might not be properly closed...", + ); err.span_label( *close_sp, "...as it matches this but it has different indentation", diff --git a/src/test/ui/issue-2354.rs b/src/test/ui/issue-2354.rs index 418f30df22bf7..35fddcb0de442 100644 --- a/src/test/ui/issue-2354.rs +++ b/src/test/ui/issue-2354.rs @@ -12,7 +12,7 @@ fn foo() { //~ NOTE un-closed delimiter match Some(x) { - //~^ NOTE this might be the culprit... + //~^ NOTE this delimiter might not be properly closed... Some(y) => { panic!(); } None => { panic!(); } } diff --git a/src/test/ui/issue-2354.stderr b/src/test/ui/issue-2354.stderr index 720f37da9d389..9cf569b685b11 100644 --- a/src/test/ui/issue-2354.stderr +++ b/src/test/ui/issue-2354.stderr @@ -4,7 +4,7 @@ error: this file contains an un-closed delimiter LL | fn foo() { //~ NOTE un-closed delimiter | - un-closed delimiter LL | match Some(x) { - | - this might be the culprit... + | - this delimiter might not be properly closed... ... LL | } | - ...as it matches this but it has different indentation diff --git a/src/test/ui/parser-recovery-1.stderr b/src/test/ui/parser-recovery-1.stderr index d0247b86ac372..5ba96e1a5dd8f 100644 --- a/src/test/ui/parser-recovery-1.stderr +++ b/src/test/ui/parser-recovery-1.stderr @@ -4,7 +4,7 @@ error: this file contains an un-closed delimiter LL | trait Foo { | - un-closed delimiter LL | fn bar() { - | - this might be the culprit... + | - this delimiter might not be properly closed... ... LL | } | - ...as it matches this but it has different indentation diff --git a/src/test/ui/parser/unclosed-braces.rs b/src/test/ui/parser/unclosed-braces.rs index 640894475846e..802133ae6b98b 100644 --- a/src/test/ui/parser/unclosed-braces.rs +++ b/src/test/ui/parser/unclosed-braces.rs @@ -24,7 +24,7 @@ fn main() { //~^ NOTE un-closed delimiter { { - //~^ NOTE this might be the culprit... + //~^ NOTE this delimiter might not be properly closed... foo(); } //~^ NOTE ...as it matches this but it has different indentation diff --git a/src/test/ui/parser/unclosed-braces.stderr b/src/test/ui/parser/unclosed-braces.stderr index 5d5ff24faa6dd..4f865bc9b39cb 100644 --- a/src/test/ui/parser/unclosed-braces.stderr +++ b/src/test/ui/parser/unclosed-braces.stderr @@ -5,7 +5,7 @@ LL | fn main() { | - un-closed delimiter ... LL | { - | - this might be the culprit... + | - this delimiter might not be properly closed... ... LL | } | - ...as it matches this but it has different indentation From 941b2e32ade695f7987c229eb1344c35119d6354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 5 Sep 2018 08:39:50 -0700 Subject: [PATCH 06/28] slight rewording of labels --- src/librustc_resolve/lib.rs | 32 +++++++++++++++---------- src/test/ui/error-codes/E0401.stderr | 2 +- src/test/ui/issues/issue-12796.stderr | 2 +- src/test/ui/use-self-in-inner-fn.rs | 2 +- src/test/ui/use-self-in-inner-fn.stderr | 2 +- 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 19a4fdae48596..449b395c00401 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -197,15 +197,26 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, err.span_label(span, "use of type variable from outer function"); let cm = resolver.session.source_map(); - let mut is_self = false; match outer_def { - Def::SelfTy(_, maybe_impl_defid) => { - if let Some(impl_span) = maybe_impl_defid.map_or(None, - |def_id| resolver.definitions.opt_span(def_id)) { - err.span_label(reduce_impl_span_to_impl_keyword(cm, impl_span), - "`Self` type implicitly declared here, on the `impl`"); + Def::SelfTy(maybe_trait_defid, maybe_impl_defid) => { + if let Some(impl_span) = maybe_impl_defid.and_then(|def_id| { + resolver.definitions.opt_span(def_id) + }) { + err.span_label( + reduce_impl_span_to_impl_keyword(cm, impl_span), + "`Self` type implicitly declared here, on the `impl`", + ); + } + match (maybe_trait_defid, maybe_impl_defid) { + (Some(_), None) => { + err.span_label(span, "can't use `Self` here"); + } + (_, Some(_)) => { + err.span_label(span, "use a type here instead"); + } + (None, None) => bug!("`impl` without trait nor type?"), } - is_self = true; + return err; }, Def::TyParam(typaram_defid) => { if let Some(typaram_span) = resolver.definitions.opt_span(typaram_defid) { @@ -221,12 +232,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, // Try to retrieve the span of the function signature and generate a new message with // a local type parameter let sugg_msg = "try using a local type parameter instead"; - if is_self { - // Suggest using the actual type - err.span_label(span, "use a materialized type here instead"); - } else if let Some( - (sugg_span, new_snippet), - ) = cm.generate_local_type_param_snippet(span) { + if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) { // Suggest the modification to the user err.span_suggestion_with_applicability( sugg_span, diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr index 90e8d2d2479da..66cc8795fba20 100644 --- a/src/test/ui/error-codes/E0401.stderr +++ b/src/test/ui/error-codes/E0401.stderr @@ -30,7 +30,7 @@ LL | fn helper(sel: &Self) -> u8 { //~ ERROR E0401 | ^^^^ | | | use of type variable from outer function - | use a materialized type here instead + | use a type here instead error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-12796.stderr b/src/test/ui/issues/issue-12796.stderr index 078c1db5de594..0c369c6ab9717 100644 --- a/src/test/ui/issues/issue-12796.stderr +++ b/src/test/ui/issues/issue-12796.stderr @@ -5,7 +5,7 @@ LL | fn inner(_: &Self) { | ^^^^ | | | use of type variable from outer function - | use a materialized type here instead + | can't use `Self` here error: aborting due to previous error diff --git a/src/test/ui/use-self-in-inner-fn.rs b/src/test/ui/use-self-in-inner-fn.rs index a1183854eb50a..380cb7a2aa270 100644 --- a/src/test/ui/use-self-in-inner-fn.rs +++ b/src/test/ui/use-self-in-inner-fn.rs @@ -16,7 +16,7 @@ impl A { fn peach(this: &Self) { //~^ ERROR can't use type parameters from outer function //~| NOTE use of type variable from outer function - //~| NOTE use a materialized type here instead + //~| NOTE use a type here instead } } } diff --git a/src/test/ui/use-self-in-inner-fn.stderr b/src/test/ui/use-self-in-inner-fn.stderr index c14e4895d9930..26082e5e01b22 100644 --- a/src/test/ui/use-self-in-inner-fn.stderr +++ b/src/test/ui/use-self-in-inner-fn.stderr @@ -8,7 +8,7 @@ LL | fn peach(this: &Self) { | ^^^^ | | | use of type variable from outer function - | use a materialized type here instead + | use a type here instead error: aborting due to previous error From bebecf850ab2a8c9df298bd3ab3b12ca8ea83c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 5 Sep 2018 09:56:01 -0700 Subject: [PATCH 07/28] reword label as per review --- src/librustc_resolve/lib.rs | 2 +- src/test/ui/error-codes/E0401.stderr | 2 +- src/test/ui/use-self-in-inner-fn.rs | 2 +- src/test/ui/use-self-in-inner-fn.stderr | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 449b395c00401..f5ac0a6647bda 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -204,7 +204,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, }) { err.span_label( reduce_impl_span_to_impl_keyword(cm, impl_span), - "`Self` type implicitly declared here, on the `impl`", + "`Self` type implicitly declared here, by this `impl`", ); } match (maybe_trait_defid, maybe_impl_defid) { diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr index 66cc8795fba20..53eeb3e9c1337 100644 --- a/src/test/ui/error-codes/E0401.stderr +++ b/src/test/ui/error-codes/E0401.stderr @@ -24,7 +24,7 @@ error[E0401]: can't use type parameters from outer function --> $DIR/E0401.rs:32:25 | LL | impl Iterator for A { - | ---- `Self` type implicitly declared here, on the `impl` + | ---- `Self` type implicitly declared here, by this `impl` ... LL | fn helper(sel: &Self) -> u8 { //~ ERROR E0401 | ^^^^ diff --git a/src/test/ui/use-self-in-inner-fn.rs b/src/test/ui/use-self-in-inner-fn.rs index 380cb7a2aa270..fea6958d7eb09 100644 --- a/src/test/ui/use-self-in-inner-fn.rs +++ b/src/test/ui/use-self-in-inner-fn.rs @@ -11,7 +11,7 @@ struct A; impl A { -//~^ NOTE `Self` type implicitly declared here, on the `impl` +//~^ NOTE `Self` type implicitly declared here, by this `impl` fn banana(&mut self) { fn peach(this: &Self) { //~^ ERROR can't use type parameters from outer function diff --git a/src/test/ui/use-self-in-inner-fn.stderr b/src/test/ui/use-self-in-inner-fn.stderr index 26082e5e01b22..cef030aec460c 100644 --- a/src/test/ui/use-self-in-inner-fn.stderr +++ b/src/test/ui/use-self-in-inner-fn.stderr @@ -2,7 +2,7 @@ error[E0401]: can't use type parameters from outer function --> $DIR/use-self-in-inner-fn.rs:16:25 | LL | impl A { - | ---- `Self` type implicitly declared here, on the `impl` + | ---- `Self` type implicitly declared here, by this `impl` ... LL | fn peach(this: &Self) { | ^^^^ From 308d19738a1b70eb6284c59cfde8b347d9898011 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 6 Sep 2018 13:07:14 +0200 Subject: [PATCH 08/28] Log when buffering a diagnostic. This is useful in debugging when and where errors are emitted in logs. --- src/Cargo.lock | 1 + src/librustc_errors/Cargo.toml | 1 + src/librustc_errors/diagnostic_builder.rs | 3 +++ src/librustc_errors/lib.rs | 2 ++ 4 files changed, 7 insertions(+) diff --git a/src/Cargo.lock b/src/Cargo.lock index a4f9082c284cd..ebab4013e3e12 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2161,6 +2161,7 @@ name = "rustc_errors" version = "0.0.0" dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index 101ca0650c8a4..b24f8ddf4d9f7 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -9,6 +9,7 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] +log = "0.4" serialize = { path = "../libserialize" } syntax_pos = { path = "../libsyntax_pos" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 1b34898b99084..9e09a7f80f1f9 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -98,6 +98,9 @@ impl<'a> DiagnosticBuilder<'a> { diagnostic = ::std::ptr::read(&self.diagnostic); ::std::mem::forget(self); }; + // Logging here is useful to help track down where in logs an error was + // actually emitted. + debug!("buffer: diagnostic={:?}", diagnostic); buffered_diagnostics.push(diagnostic); } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index d31db4b2d00ac..f1873ec79044c 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -24,6 +24,8 @@ extern crate atty; extern crate termcolor; #[cfg(unix)] extern crate libc; +#[macro_use] +extern crate log; extern crate rustc_data_structures; extern crate serialize as rustc_serialize; extern crate syntax_pos; From b45648b124acbb645620f609660bc3f37561bc20 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 6 Sep 2018 15:48:33 +0200 Subject: [PATCH 09/28] De-duplicate moved variable errors. By introducing a new map that tracks the errors reported and the `Place`s that spawned those errors against the move out that the error was referring to, we are able to silence duplicate errors by emitting only the error which corresponds to the most specific `Place` (that which other `Place`s which reported errors are prefixes of). This generally is an improvement, however there is a case - `liveness-move-in-while` - where the output regresses. --- .../borrow_check/error_reporting.rs | 26 +++++++++-- src/librustc_mir/borrow_check/mod.rs | 28 +++++++++--- .../borrowck-multiple-captures.nll.stderr | 16 +++---- src/test/ui/borrowck/issue-41962.rs | 3 -- src/test/ui/borrowck/issue-41962.stderr | 33 +------------- src/test/ui/issues/issue-17385.nll.stderr | 43 +------------------ .../liveness-move-in-while.nll.stderr | 10 +---- src/test/ui/nll/issue-53807.nll.stderr | 11 +++++ src/test/ui/nll/issue-53807.rs | 17 ++++++++ src/test/ui/nll/issue-53807.stderr | 21 +++++++++ src/test/ui/no-capture-arc.nll.stderr | 15 +------ src/test/ui/no-reuse-move-arc.nll.stderr | 15 +------ 12 files changed, 108 insertions(+), 130 deletions(-) create mode 100644 src/test/ui/nll/issue-53807.nll.stderr create mode 100644 src/test/ui/nll/issue-53807.rs create mode 100644 src/test/ui/nll/issue-53807.stderr diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index a0b0aabf73e02..692460aad2900 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -38,6 +38,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { (place, span): (&Place<'tcx>, Span), mpi: MovePathIndex, ) { + debug!( + "report_use_of_moved_or_uninitialized: context={:?} desired_action={:?} place={:?} \ + span={:?} mpi={:?}", + context, desired_action, place, span, mpi + ); + let use_spans = self .move_spans(place, context.loc) .or_else(|| self.borrow_spans(span, context.loc)); @@ -49,7 +55,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if mois.is_empty() { let root_place = self.prefixes(&place, PrefixSet::All).last().unwrap(); - if self.moved_error_reported.contains(&root_place.clone()) { + if self.uninitialized_error_reported.contains(&root_place.clone()) { debug!( "report_use_of_moved_or_uninitialized place: error about {:?} suppressed", root_place @@ -57,7 +63,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { return; } - self.moved_error_reported.insert(root_place.clone()); + self.uninitialized_error_reported.insert(root_place.clone()); let item_msg = match self.describe_place_with_options(place, IncludingDowncast(true)) { Some(name) => format!("`{}`", name), @@ -80,6 +86,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { err.buffer(&mut self.errors_buffer); } else { + if let Some((reported_place, _)) = self.move_error_reported.get(&mois) { + if self.prefixes(&reported_place, PrefixSet::All).any(|p| p == place) { + debug!("report_use_of_moved_or_uninitialized place: error suppressed \ + mois={:?}", mois); + return; + } + } + let msg = ""; //FIXME: add "partially " or "collaterally " let mut err = self.tcx.cannot_act_on_moved_value( @@ -167,7 +181,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } - err.buffer(&mut self.errors_buffer); + if let Some((_, mut old_err)) = self.move_error_reported.insert( + mois, + (place.clone(), err) + ) { + // Cancel the old error so it doesn't ICE. + old_err.cancel(); + } } } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 3536947b25ebf..df730447698cc 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -27,7 +27,7 @@ use rustc::ty::{self, ParamEnv, TyCtxt, Ty}; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level}; use rustc_data_structures::graph::dominators::Dominators; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_set::IdxSet; use rustc_data_structures::indexed_vec::Idx; use smallvec::SmallVec; @@ -38,6 +38,7 @@ use syntax_pos::Span; use dataflow::indexes::BorrowIndex; use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MoveError, MovePathIndex}; +use dataflow::move_paths::indexes::MoveOutIndex; use dataflow::Borrows; use dataflow::DataflowResultsConsumer; use dataflow::FlowAtLocation; @@ -247,7 +248,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( }, access_place_error_reported: FxHashSet(), reservation_error_reported: FxHashSet(), - moved_error_reported: FxHashSet(), + move_error_reported: FxHashMap(), + uninitialized_error_reported: FxHashSet(), errors_buffer, nonlexical_regioncx: regioncx, used_mut: FxHashSet(), @@ -325,6 +327,11 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( } } + // Buffer any move errors that we collected and de-duplicated. + for (_, (_, diag)) in mbcx.move_error_reported.drain() { + diag.buffer(&mut mbcx.errors_buffer); + } + if mbcx.errors_buffer.len() > 0 { mbcx.errors_buffer.sort_by_key(|diag| diag.span.primary_span()); @@ -400,9 +407,20 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { /// but it is currently inconvenient to track down the BorrowIndex /// at the time we detect and report a reservation error. reservation_error_reported: FxHashSet>, - /// This field keeps track of errors reported in the checking of moved variables, + /// This field keeps track of move errors that are to be reported for given move indicies. + /// + /// There are situations where many errors can be reported for a single move out (see #53807) + /// and we want only the best of those errors. + /// + /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the + /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the + /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once + /// all move errors have been reported, any diagnostics in this map are added to the buffer + /// to be emitted. + move_error_reported: FxHashMap, (Place<'tcx>, DiagnosticBuilder<'cx>)>, + /// This field keeps track of errors reported in the checking of uninitialized variables, /// so that we don't report seemingly duplicate errors. - moved_error_reported: FxHashSet>, + uninitialized_error_reported: FxHashSet>, /// Errors to be reported buffer errors_buffer: Vec, /// This field keeps track of all the local variables that are declared mut and are mutated. @@ -793,7 +811,7 @@ enum LocalMutationIsAllowed { No, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] enum InitializationRequiringAction { Update, Borrow, diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr b/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr index ce1880c584a6e..79cfbc5a36022 100644 --- a/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr +++ b/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr @@ -26,31 +26,31 @@ LL | drop(x2); //~ ERROR cannot move `x2` into closure because it is bor LL | borrow(&*p2); | ---- borrow later used here -error[E0382]: use of moved value: `x1` +error[E0382]: use of moved value: `x2` --> $DIR/borrowck-multiple-captures.rs:35:19 | -LL | drop(x1); +LL | drop(x2); | -- value moved here -... LL | thread::spawn(move|| { | ^^^^^^ value used here after move LL | drop(x1); //~ ERROR capture of moved value: `x1` +LL | drop(x2); //~ ERROR capture of moved value: `x2` | -- use occurs due to use in closure | - = note: move occurs because `x1` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x2` has type `std::boxed::Box`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `x2` +error[E0382]: use of moved value: `x1` --> $DIR/borrowck-multiple-captures.rs:35:19 | -LL | drop(x2); +LL | drop(x1); | -- value moved here +... LL | thread::spawn(move|| { | ^^^^^^ value used here after move LL | drop(x1); //~ ERROR capture of moved value: `x1` -LL | drop(x2); //~ ERROR capture of moved value: `x2` | -- use occurs due to use in closure | - = note: move occurs because `x2` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x1` has type `std::boxed::Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x` --> $DIR/borrowck-multiple-captures.rs:46:14 diff --git a/src/test/ui/borrowck/issue-41962.rs b/src/test/ui/borrowck/issue-41962.rs index 2a94e05016d4e..9431ef5f13dc8 100644 --- a/src/test/ui/borrowck/issue-41962.rs +++ b/src/test/ui/borrowck/issue-41962.rs @@ -18,9 +18,6 @@ pub fn main(){ } //~^^ ERROR use of partially moved value: `maybe` (Ast) [E0382] //~| ERROR use of moved value: `(maybe as std::prelude::v1::Some).0` (Ast) [E0382] - //~| ERROR use of moved value: `maybe` (Mir) [E0382] - //~| ERROR use of moved value: `maybe` (Mir) [E0382] //~| ERROR use of moved value (Mir) [E0382] - //~| ERROR borrow of moved value: `maybe` (Mir) [E0382] } } diff --git a/src/test/ui/borrowck/issue-41962.stderr b/src/test/ui/borrowck/issue-41962.stderr index b6e005a6673eb..957ccfe45dd01 100644 --- a/src/test/ui/borrowck/issue-41962.stderr +++ b/src/test/ui/borrowck/issue-41962.stderr @@ -16,17 +16,6 @@ LL | if let Some(thing) = maybe { | = note: move occurs because the value has type `std::vec::Vec`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `maybe` (Mir) - --> $DIR/issue-41962.rs:17:16 - | -LL | if let Some(thing) = maybe { - | ^^^^^-----^ - | | | - | | value moved here - | value used here after move - | - = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait - error[E0382]: use of moved value (Mir) --> $DIR/issue-41962.rs:17:21 | @@ -35,26 +24,6 @@ LL | if let Some(thing) = maybe { | = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `maybe` (Mir) - --> $DIR/issue-41962.rs:17:30 - | -LL | if let Some(thing) = maybe { - | ----- ^^^^^ value used here after move - | | - | value moved here - | - = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait - -error[E0382]: borrow of moved value: `maybe` (Mir) - --> $DIR/issue-41962.rs:17:30 - | -LL | if let Some(thing) = maybe { - | ----- ^^^^^ value borrowed here after move - | | - | value moved here - | - = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait - -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/issues/issue-17385.nll.stderr b/src/test/ui/issues/issue-17385.nll.stderr index 85924a7526168..c7b0b57000f5e 100644 --- a/src/test/ui/issues/issue-17385.nll.stderr +++ b/src/test/ui/issues/issue-17385.nll.stderr @@ -1,23 +1,3 @@ -error[E0382]: use of moved value: `foo` - --> $DIR/issue-17385.rs:28:11 - | -LL | drop(foo); - | --- value moved here -LL | match foo { //~ ERROR use of moved value - | ^^^ value used here after move - | - = note: move occurs because `foo` has type `X`, which does not implement the `Copy` trait - -error[E0382]: borrow of moved value: `foo` - --> $DIR/issue-17385.rs:28:11 - | -LL | drop(foo); - | --- value moved here -LL | match foo { //~ ERROR use of moved value - | ^^^ value borrowed here after move - | - = note: move occurs because `foo` has type `X`, which does not implement the `Copy` trait - error[E0382]: use of moved value: `foo.0` --> $DIR/issue-17385.rs:29:11 | @@ -39,27 +19,6 @@ LL | match e { //~ ERROR use of moved value | = note: move occurs because `e` has type `Enum`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `e` - --> $DIR/issue-17385.rs:35:11 - | -LL | drop(e); - | - value moved here -LL | match e { //~ ERROR use of moved value - | ^ value borrowed here after move - | - = note: move occurs because `e` has type `Enum`, which does not implement the `Copy` trait - -error[E0382]: use of moved value: `e` - --> $DIR/issue-17385.rs:36:9 - | -LL | drop(e); - | - value moved here -LL | match e { //~ ERROR use of moved value -LL | Enum::Variant1 => unreachable!(), - | ^^^^^^^^^^^^^^ value used here after move - | - = note: move occurs because `e` has type `Enum`, which does not implement the `Copy` trait - -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/liveness/liveness-move-in-while.nll.stderr b/src/test/ui/liveness/liveness-move-in-while.nll.stderr index 5ca5dc647090d..9f1ffd91518b3 100644 --- a/src/test/ui/liveness/liveness-move-in-while.nll.stderr +++ b/src/test/ui/liveness/liveness-move-in-while.nll.stderr @@ -8,14 +8,6 @@ LL | while true { while true { while true { x = y; x.clone(); } } } | = note: move occurs because `y` has type `std::boxed::Box`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `y` - --> $DIR/liveness-move-in-while.rs:18:52 - | -LL | while true { while true { while true { x = y; x.clone(); } } } - | ^ value moved here in previous iteration of loop - | - = note: move occurs because `y` has type `std::boxed::Box`, which does not implement the `Copy` trait - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/nll/issue-53807.nll.stderr b/src/test/ui/nll/issue-53807.nll.stderr new file mode 100644 index 0000000000000..0c019a4ec3cdc --- /dev/null +++ b/src/test/ui/nll/issue-53807.nll.stderr @@ -0,0 +1,11 @@ +error[E0382]: use of moved value + --> $DIR/issue-53807.rs:14:21 + | +LL | if let Some(thing) = maybe { + | ^^^^^ value moved here in previous iteration of loop + | + = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/nll/issue-53807.rs b/src/test/ui/nll/issue-53807.rs new file mode 100644 index 0000000000000..791dee2fb3183 --- /dev/null +++ b/src/test/ui/nll/issue-53807.rs @@ -0,0 +1,17 @@ +// 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. + +pub fn main(){ + let maybe = Some(vec![true, true]); + loop { + if let Some(thing) = maybe { + } + } +} diff --git a/src/test/ui/nll/issue-53807.stderr b/src/test/ui/nll/issue-53807.stderr new file mode 100644 index 0000000000000..7056899d0a48a --- /dev/null +++ b/src/test/ui/nll/issue-53807.stderr @@ -0,0 +1,21 @@ +error[E0382]: use of partially moved value: `maybe` + --> $DIR/issue-53807.rs:14:30 + | +LL | if let Some(thing) = maybe { + | ----- ^^^^^ value used here after move + | | + | value moved here + | + = note: move occurs because the value has type `std::vec::Vec`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `(maybe as std::prelude::v1::Some).0` + --> $DIR/issue-53807.rs:14:21 + | +LL | if let Some(thing) = maybe { + | ^^^^^ value moved here in previous iteration of loop + | + = note: move occurs because the value has type `std::vec::Vec`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/no-capture-arc.nll.stderr b/src/test/ui/no-capture-arc.nll.stderr index a58d5ad6fa723..31dba18338ab7 100644 --- a/src/test/ui/no-capture-arc.nll.stderr +++ b/src/test/ui/no-capture-arc.nll.stderr @@ -11,19 +11,6 @@ LL | assert_eq!((*arc_v)[2], 3); | = note: move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `arc_v` - --> $DIR/no-capture-arc.rs:26:23 - | -LL | thread::spawn(move|| { - | ------ value moved into closure here -LL | assert_eq!((*arc_v)[3], 4); - | ----- variable moved due to use in closure -... -LL | println!("{:?}", *arc_v); - | ^^^^^ value borrowed here after move - | - = note: move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/no-reuse-move-arc.nll.stderr b/src/test/ui/no-reuse-move-arc.nll.stderr index 902affc80462c..bffcae6e2f50a 100644 --- a/src/test/ui/no-reuse-move-arc.nll.stderr +++ b/src/test/ui/no-reuse-move-arc.nll.stderr @@ -11,19 +11,6 @@ LL | assert_eq!((*arc_v)[2], 3); //~ ERROR use of moved value: `arc_v` | = note: move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `arc_v` - --> $DIR/no-reuse-move-arc.rs:24:23 - | -LL | thread::spawn(move|| { - | ------ value moved into closure here -LL | assert_eq!((*arc_v)[3], 4); - | ----- variable moved due to use in closure -... -LL | println!("{:?}", *arc_v); //~ ERROR use of moved value: `arc_v` - | ^^^^^ value borrowed here after move - | - = note: move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0382`. From b9e7574bf2d760fc011cc90890f3280c474746e4 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 6 Sep 2018 18:42:15 +0300 Subject: [PATCH 10/28] rustc_codegen_llvm: don't assume offsets are always aligned. --- src/librustc_codegen_llvm/mir/place.rs | 9 ++++++--- src/librustc_codegen_llvm/type_of.rs | 22 +++++++++++++--------- src/librustc_target/abi/mod.rs | 18 ++++++++++++++++++ src/test/run-pass/issue-53728.rs | 26 ++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 12 deletions(-) create mode 100644 src/test/run-pass/issue-53728.rs diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs index 833dca8c75fd5..05cee034d3f61 100644 --- a/src/librustc_codegen_llvm/mir/place.rs +++ b/src/librustc_codegen_llvm/mir/place.rs @@ -174,7 +174,10 @@ impl PlaceRef<'ll, 'tcx> { let cx = bx.cx; let field = self.layout.field(cx, ix); let offset = self.layout.fields.offset(ix); - let align = self.align.min(self.layout.align).min(field.align); + let effective_field_align = self.align + .min(self.layout.align) + .min(field.align) + .restrict_for_offset(offset); let simple = || { // Unions and newtypes only use an offset of 0. @@ -196,7 +199,7 @@ impl PlaceRef<'ll, 'tcx> { None }, layout: field, - align, + align: effective_field_align, } }; @@ -269,7 +272,7 @@ impl PlaceRef<'ll, 'tcx> { llval: bx.pointercast(byte_ptr, ll_fty.ptr_to()), llextra: self.llextra, layout: field, - align, + align: effective_field_align, } } diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index e6907030ae635..6eec0b0b68c55 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -122,25 +122,29 @@ fn struct_llfields<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let mut packed = false; let mut offset = Size::ZERO; - let mut prev_align = layout.align; + let mut prev_effective_align = layout.align; let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2); for i in layout.fields.index_by_increasing_offset() { - let field = layout.field(cx, i); - packed |= layout.align.abi() < field.align.abi(); - let target_offset = layout.fields.offset(i as usize); - debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?}", - i, field, offset, target_offset); + let field = layout.field(cx, i); + let effective_field_align = layout.align + .min(field.align) + .restrict_for_offset(target_offset); + packed |= effective_field_align.abi() < field.align.abi(); + + debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?} \ + effective_field_align: {}", + i, field, offset, target_offset, effective_field_align.abi()); assert!(target_offset >= offset); let padding = target_offset - offset; - let padding_align = layout.align.min(prev_align).min(field.align); + let padding_align = prev_effective_align.min(effective_field_align); assert_eq!(offset.abi_align(padding_align) + padding, target_offset); result.push(Type::padding_filler(cx, padding, padding_align)); debug!(" padding before: {:?}", padding); result.push(field.llvm_type(cx)); offset = target_offset + field.size; - prev_align = field.align; + prev_effective_align = effective_field_align; } if !layout.is_unsized() && field_count > 0 { if offset > layout.size { @@ -148,7 +152,7 @@ fn struct_llfields<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, layout, layout.size, offset); } let padding = layout.size - offset; - let padding_align = layout.align.min(prev_align); + let padding_align = prev_effective_align; assert_eq!(offset.abi_align(padding_align) + padding, layout.size); debug!("struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}", padding, offset, layout.size); diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 16b5241b29aa5..5c4cd849f89bc 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -416,6 +416,24 @@ impl Align { pref_pow2: cmp::max(self.pref_pow2, other.pref_pow2), } } + + /// Compute the best alignment possible for the given offset + /// (the largest power of two that the offset is a multiple of). + /// + /// NB: for an offset of `0`, this happens to return `2^64`. + pub fn max_for_offset(offset: Size) -> Align { + let pow2 = offset.bytes().trailing_zeros() as u8; + Align { + abi_pow2: pow2, + pref_pow2: pow2, + } + } + + /// Lower the alignment, if necessary, such that the given offset + /// is aligned to it (the offset is a multiple of the aligment). + pub fn restrict_for_offset(self, offset: Size) -> Align { + self.min(Align::max_for_offset(offset)) + } } /// Integers, also used for enum discriminants. diff --git a/src/test/run-pass/issue-53728.rs b/src/test/run-pass/issue-53728.rs new file mode 100644 index 0000000000000..f9cb5da29a7d0 --- /dev/null +++ b/src/test/run-pass/issue-53728.rs @@ -0,0 +1,26 @@ +// 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. + +#[repr(u16)] +enum DeviceKind { + Nil = 0, +} + +#[repr(packed)] +struct DeviceInfo { + endianness: u8, + device_kind: DeviceKind, +} + +fn main() { + let _x = None::<(DeviceInfo, u8)>; + let _y = None::<(DeviceInfo, u16)>; + let _z = None::<(DeviceInfo, u64)>; +} From 4088a385a70e2aa8d98a5c235a3bc13397fa82df Mon Sep 17 00:00:00 2001 From: Jakub Kozlowski Date: Thu, 6 Sep 2018 19:01:49 +0100 Subject: [PATCH 11/28] Allow named lifetimes in async functions. - Fixes #53174 --- src/librustc/hir/map/def_collector.rs | 59 +++++++++++++++++---------- src/test/run-pass/async-await.rs | 53 +++++++++++++++++++++++- 2 files changed, 90 insertions(+), 22 deletions(-) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index cab620aeec548..b80c7445624e5 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -76,23 +76,38 @@ impl<'a> DefCollector<'a> { fn visit_async_fn( &mut self, id: NodeId, - async_node_id: NodeId, - return_impl_trait_id: NodeId, name: Name, span: Span, - visit_fn: impl FnOnce(&mut DefCollector<'a>) + header: &FnHeader, + generics: &'a Generics, + decl: &'a FnDecl, + body: &'a Block, ) { + let (closure_id, return_impl_trait_id) = match header.asyncness { + IsAsync::Async { + closure_id, + return_impl_trait_id, + } => (closure_id, return_impl_trait_id), + _ => unreachable!(), + }; + // For async functions, we need to create their inner defs inside of a // closure to match their desugared representation. let fn_def_data = DefPathData::ValueNs(name.as_interned_str()); let fn_def = self.create_def(id, fn_def_data, ITEM_LIKE_SPACE, span); return self.with_parent(fn_def, |this| { this.create_def(return_impl_trait_id, DefPathData::ImplTrait, REGULAR_SPACE, span); - let closure_def = this.create_def(async_node_id, + + visit::walk_generics(this, generics); + visit::walk_fn_decl(this, decl); + + let closure_def = this.create_def(closure_id, DefPathData::ClosureExpr, REGULAR_SPACE, span); - this.with_parent(closure_def, visit_fn) + this.with_parent(closure_def, |this| { + visit::walk_block(this, body); + }) }) } @@ -122,17 +137,20 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => { return visit::walk_item(self, i); } - ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async { - closure_id, - return_impl_trait_id, - }, .. }, ..) => { + ItemKind::Fn( + ref decl, + ref header @ FnHeader { asyncness: IsAsync::Async { .. }, .. }, + ref generics, + ref body, + ) => { return self.visit_async_fn( i.id, - closure_id, - return_impl_trait_id, i.ident.name, i.span, - |this| visit::walk_item(this, i) + header, + generics, + decl, + body, ) } ItemKind::Mod(..) => DefPathData::Module(i.ident.as_interned_str()), @@ -233,18 +251,17 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_impl_item(&mut self, ii: &'a ImplItem) { let def_data = match ii.node { ImplItemKind::Method(MethodSig { - header: FnHeader { asyncness: IsAsync::Async { - closure_id, - return_impl_trait_id, - }, .. }, .. - }, ..) => { + header: ref header @ FnHeader { asyncness: IsAsync::Async { .. }, .. }, + ref decl, + }, ref body) => { return self.visit_async_fn( ii.id, - closure_id, - return_impl_trait_id, ii.ident.name, ii.span, - |this| visit::walk_impl_item(this, ii) + header, + &ii.generics, + decl, + body, ) } ImplItemKind::Method(..) | ImplItemKind::Const(..) => @@ -341,4 +358,4 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { } } } -} +} \ No newline at end of file diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs index 46f228459079a..9d004ea4574ba 100644 --- a/src/test/run-pass/async-await.rs +++ b/src/test/run-pass/async-await.rs @@ -67,6 +67,13 @@ fn async_block(x: u8) -> impl Future { } } +fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future + 'a { + async move { + await!(wake_and_yield_once()); + *x + } +} + fn async_nonmove_block(x: u8) -> impl Future { async move { let future = async { @@ -94,6 +101,23 @@ async fn async_fn_with_borrow(x: &u8) -> u8 { *x } +async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 { + await!(wake_and_yield_once()); + *x +} + +fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future + 'a { + async move { + await!(wake_and_yield_once()); + *x + } +} + +async fn async_fn_with_named_lifetime_multiple_args<'a>(x: &'a u8, _y: &'a u8) -> u8 { + await!(wake_and_yield_once()); + *x +} + fn async_fn_with_internal_borrow(y: u8) -> impl Future { async move { await!(async_fn_with_borrow(&y)) @@ -138,16 +162,43 @@ where fn main() { macro_rules! test { - ($($fn_name:ident,)*) => { $( + ($($fn_name:expr,)*) => { $( test_future_yields_once_then_returns($fn_name); )* } } + macro_rules! test_with_borrow { + ($($fn_name:expr,)*) => { $( + test_future_yields_once_then_returns(|x| { + async move { + await!($fn_name(&x)) + } + }); + )* } + } + test! { async_block, async_nonmove_block, async_closure, async_fn, async_fn_with_internal_borrow, + |x| { + async move { + unsafe { await!(unsafe_async_fn(x)) } + } + }, + } + + test_with_borrow! { + async_block_with_borrow_named_lifetime, + async_fn_with_borrow, + async_fn_with_borrow_named_lifetime, + async_fn_with_impl_future_named_lifetime, + |x| { + async move { + await!(async_fn_with_named_lifetime_multiple_args(x, x)) + } + }, } } From 4b7f2eb947b62974d72f9d14738c784a8a1a2095 Mon Sep 17 00:00:00 2001 From: Jakub Kozlowski Date: Thu, 6 Sep 2018 22:18:39 +0100 Subject: [PATCH 12/28] Fixup whitespace --- src/librustc/hir/map/def_collector.rs | 2 +- src/test/run-pass/async-await.rs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index b80c7445624e5..cf832aee534d4 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -358,4 +358,4 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { } } } -} \ No newline at end of file +} diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs index 9d004ea4574ba..f692f57abb9c3 100644 --- a/src/test/run-pass/async-await.rs +++ b/src/test/run-pass/async-await.rs @@ -71,7 +71,7 @@ fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future impl Future { @@ -115,7 +115,7 @@ fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future(x: &'a u8, _y: &'a u8) -> u8 { await!(wake_and_yield_once()); - *x + *x } fn async_fn_with_internal_borrow(y: u8) -> impl Future { @@ -169,7 +169,7 @@ fn main() { macro_rules! test_with_borrow { ($($fn_name:expr,)*) => { $( - test_future_yields_once_then_returns(|x| { + test_future_yields_once_then_returns(|x| { async move { await!($fn_name(&x)) } @@ -183,11 +183,11 @@ fn main() { async_closure, async_fn, async_fn_with_internal_borrow, - |x| { - async move { - unsafe { await!(unsafe_async_fn(x)) } - } - }, + |x| { + async move { + unsafe { await!(unsafe_async_fn(x)) } + } + }, } test_with_borrow! { @@ -195,7 +195,7 @@ fn main() { async_fn_with_borrow, async_fn_with_borrow_named_lifetime, async_fn_with_impl_future_named_lifetime, - |x| { + |x| { async move { await!(async_fn_with_named_lifetime_multiple_args(x, x)) } From 0c89243fd33a7f9f0ef4ddc9796047c646e9a688 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 7 Sep 2018 00:27:20 -0700 Subject: [PATCH 13/28] Fix compiling some rustc crates to wasm I was dabbling recently seeing what it would take to compile `rustfmt` to the `wasm32-unknown-unknown` target and it turns out not much effort is needed! Currently `rustfmt` depends on a few rustc crates published to crates.io, so this commit touches up those crates to compile for wasm themselves. Notably: * The `rustc_data_structures` crate's `flock` implementation is stubbed out to unconditionally return errors on unsupported platforms. * The `rustc_errors` crate is extended to not do any locking for all non-windows platforms. In both of these cases if we port the compiler to new platforms the functionality isn't critical but will be discovered over time as it comes up, so this hopefully doesn't make it too too hard to compile to new platforms! --- src/librustc_data_structures/flock.rs | 590 +++++++++++++------------- src/librustc_errors/lock.rs | 2 +- 2 files changed, 299 insertions(+), 293 deletions(-) diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index f10a9a68bed5b..38ce331051fec 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -15,345 +15,351 @@ //! librustdoc, it is not production quality at all. #![allow(non_camel_case_types)] -use std::path::Path; - -pub use self::imp::Lock; +#![allow(nonstandard_style)] -#[cfg(unix)] -mod imp { - use std::ffi::{CString, OsStr}; - use std::os::unix::prelude::*; - use std::path::Path; - use std::io; - use libc; +use std::io; +use std::path::Path; - #[cfg(any(target_os = "linux", target_os = "android"))] - mod os { +cfg_if! { + if #[cfg(unix)] { + use std::ffi::{CString, OsStr}; + use std::os::unix::prelude::*; use libc; - #[repr(C)] - pub struct flock { - pub l_type: libc::c_short, - pub l_whence: libc::c_short, - pub l_start: libc::off_t, - pub l_len: libc::off_t, - pub l_pid: libc::pid_t, - - // not actually here, but brings in line with freebsd - pub l_sysid: libc::c_int, - } + #[cfg(any(target_os = "linux", target_os = "android"))] + mod os { + use libc; - pub const F_RDLCK: libc::c_short = 0; - pub const F_WRLCK: libc::c_short = 1; - pub const F_UNLCK: libc::c_short = 2; - pub const F_SETLK: libc::c_int = 6; - pub const F_SETLKW: libc::c_int = 7; - } + #[repr(C)] + pub struct flock { + pub l_type: libc::c_short, + pub l_whence: libc::c_short, + pub l_start: libc::off_t, + pub l_len: libc::off_t, + pub l_pid: libc::pid_t, - #[cfg(target_os = "freebsd")] - mod os { - use libc; + // not actually here, but brings in line with freebsd + pub l_sysid: libc::c_int, + } - #[repr(C)] - pub struct flock { - pub l_start: libc::off_t, - pub l_len: libc::off_t, - pub l_pid: libc::pid_t, - pub l_type: libc::c_short, - pub l_whence: libc::c_short, - pub l_sysid: libc::c_int, + pub const F_RDLCK: libc::c_short = 0; + pub const F_WRLCK: libc::c_short = 1; + pub const F_UNLCK: libc::c_short = 2; + pub const F_SETLK: libc::c_int = 6; + pub const F_SETLKW: libc::c_int = 7; } - pub const F_RDLCK: libc::c_short = 1; - pub const F_UNLCK: libc::c_short = 2; - pub const F_WRLCK: libc::c_short = 3; - pub const F_SETLK: libc::c_int = 12; - pub const F_SETLKW: libc::c_int = 13; - } - - #[cfg(any(target_os = "dragonfly", - target_os = "bitrig", - target_os = "netbsd", - target_os = "openbsd"))] - mod os { - use libc; + #[cfg(target_os = "freebsd")] + mod os { + use libc; + + #[repr(C)] + pub struct flock { + pub l_start: libc::off_t, + pub l_len: libc::off_t, + pub l_pid: libc::pid_t, + pub l_type: libc::c_short, + pub l_whence: libc::c_short, + pub l_sysid: libc::c_int, + } - #[repr(C)] - pub struct flock { - pub l_start: libc::off_t, - pub l_len: libc::off_t, - pub l_pid: libc::pid_t, - pub l_type: libc::c_short, - pub l_whence: libc::c_short, - - // not actually here, but brings in line with freebsd - pub l_sysid: libc::c_int, + pub const F_RDLCK: libc::c_short = 1; + pub const F_UNLCK: libc::c_short = 2; + pub const F_WRLCK: libc::c_short = 3; + pub const F_SETLK: libc::c_int = 12; + pub const F_SETLKW: libc::c_int = 13; } - pub const F_RDLCK: libc::c_short = 1; - pub const F_UNLCK: libc::c_short = 2; - pub const F_WRLCK: libc::c_short = 3; - pub const F_SETLK: libc::c_int = 8; - pub const F_SETLKW: libc::c_int = 9; - } - - #[cfg(target_os = "haiku")] - mod os { - use libc; + #[cfg(any(target_os = "dragonfly", + target_os = "bitrig", + target_os = "netbsd", + target_os = "openbsd"))] + mod os { + use libc; + + #[repr(C)] + pub struct flock { + pub l_start: libc::off_t, + pub l_len: libc::off_t, + pub l_pid: libc::pid_t, + pub l_type: libc::c_short, + pub l_whence: libc::c_short, + + // not actually here, but brings in line with freebsd + pub l_sysid: libc::c_int, + } - #[repr(C)] - pub struct flock { - pub l_type: libc::c_short, - pub l_whence: libc::c_short, - pub l_start: libc::off_t, - pub l_len: libc::off_t, - pub l_pid: libc::pid_t, - - // not actually here, but brings in line with freebsd - pub l_sysid: libc::c_int, + pub const F_RDLCK: libc::c_short = 1; + pub const F_UNLCK: libc::c_short = 2; + pub const F_WRLCK: libc::c_short = 3; + pub const F_SETLK: libc::c_int = 8; + pub const F_SETLKW: libc::c_int = 9; } - pub const F_RDLCK: libc::c_short = 0x0040; - pub const F_UNLCK: libc::c_short = 0x0200; - pub const F_WRLCK: libc::c_short = 0x0400; - pub const F_SETLK: libc::c_int = 0x0080; - pub const F_SETLKW: libc::c_int = 0x0100; - } + #[cfg(target_os = "haiku")] + mod os { + use libc; - #[cfg(any(target_os = "macos", target_os = "ios"))] - mod os { - use libc; + #[repr(C)] + pub struct flock { + pub l_type: libc::c_short, + pub l_whence: libc::c_short, + pub l_start: libc::off_t, + pub l_len: libc::off_t, + pub l_pid: libc::pid_t, - #[repr(C)] - pub struct flock { - pub l_start: libc::off_t, - pub l_len: libc::off_t, - pub l_pid: libc::pid_t, - pub l_type: libc::c_short, - pub l_whence: libc::c_short, - - // not actually here, but brings in line with freebsd - pub l_sysid: libc::c_int, + // not actually here, but brings in line with freebsd + pub l_sysid: libc::c_int, + } + + pub const F_RDLCK: libc::c_short = 0x0040; + pub const F_UNLCK: libc::c_short = 0x0200; + pub const F_WRLCK: libc::c_short = 0x0400; + pub const F_SETLK: libc::c_int = 0x0080; + pub const F_SETLKW: libc::c_int = 0x0100; } - pub const F_RDLCK: libc::c_short = 1; - pub const F_UNLCK: libc::c_short = 2; - pub const F_WRLCK: libc::c_short = 3; - pub const F_SETLK: libc::c_int = 8; - pub const F_SETLKW: libc::c_int = 9; - } + #[cfg(any(target_os = "macos", target_os = "ios"))] + mod os { + use libc; - #[cfg(target_os = "solaris")] - mod os { - use libc; + #[repr(C)] + pub struct flock { + pub l_start: libc::off_t, + pub l_len: libc::off_t, + pub l_pid: libc::pid_t, + pub l_type: libc::c_short, + pub l_whence: libc::c_short, - #[repr(C)] - pub struct flock { - pub l_type: libc::c_short, - pub l_whence: libc::c_short, - pub l_start: libc::off_t, - pub l_len: libc::off_t, - pub l_sysid: libc::c_int, - pub l_pid: libc::pid_t, + // not actually here, but brings in line with freebsd + pub l_sysid: libc::c_int, + } + + pub const F_RDLCK: libc::c_short = 1; + pub const F_UNLCK: libc::c_short = 2; + pub const F_WRLCK: libc::c_short = 3; + pub const F_SETLK: libc::c_int = 8; + pub const F_SETLKW: libc::c_int = 9; } - pub const F_RDLCK: libc::c_short = 1; - pub const F_WRLCK: libc::c_short = 2; - pub const F_UNLCK: libc::c_short = 3; - pub const F_SETLK: libc::c_int = 6; - pub const F_SETLKW: libc::c_int = 7; - } + #[cfg(target_os = "solaris")] + mod os { + use libc; + + #[repr(C)] + pub struct flock { + pub l_type: libc::c_short, + pub l_whence: libc::c_short, + pub l_start: libc::off_t, + pub l_len: libc::off_t, + pub l_sysid: libc::c_int, + pub l_pid: libc::pid_t, + } - #[derive(Debug)] - pub struct Lock { - fd: libc::c_int, - } + pub const F_RDLCK: libc::c_short = 1; + pub const F_WRLCK: libc::c_short = 2; + pub const F_UNLCK: libc::c_short = 3; + pub const F_SETLK: libc::c_int = 6; + pub const F_SETLKW: libc::c_int = 7; + } - impl Lock { - pub fn new(p: &Path, - wait: bool, - create: bool, - exclusive: bool) - -> io::Result { - let os: &OsStr = p.as_ref(); - let buf = CString::new(os.as_bytes()).unwrap(); - let open_flags = if create { - libc::O_RDWR | libc::O_CREAT - } else { - libc::O_RDWR - }; - - let fd = unsafe { - libc::open(buf.as_ptr(), open_flags, - libc::S_IRWXU as libc::c_int) - }; - - if fd < 0 { - return Err(io::Error::last_os_error()); - } + #[derive(Debug)] + pub struct Lock { + fd: libc::c_int, + } - let lock_type = if exclusive { - os::F_WRLCK - } else { - os::F_RDLCK - }; - - let flock = os::flock { - l_start: 0, - l_len: 0, - l_pid: 0, - l_whence: libc::SEEK_SET as libc::c_short, - l_type: lock_type, - l_sysid: 0, - }; - let cmd = if wait { os::F_SETLKW } else { os::F_SETLK }; - let ret = unsafe { - libc::fcntl(fd, cmd, &flock) - }; - if ret == -1 { - let err = io::Error::last_os_error(); - unsafe { libc::close(fd); } - Err(err) - } else { - Ok(Lock { fd: fd }) + impl Lock { + pub fn new(p: &Path, + wait: bool, + create: bool, + exclusive: bool) + -> io::Result { + let os: &OsStr = p.as_ref(); + let buf = CString::new(os.as_bytes()).unwrap(); + let open_flags = if create { + libc::O_RDWR | libc::O_CREAT + } else { + libc::O_RDWR + }; + + let fd = unsafe { + libc::open(buf.as_ptr(), open_flags, + libc::S_IRWXU as libc::c_int) + }; + + if fd < 0 { + return Err(io::Error::last_os_error()); + } + + let lock_type = if exclusive { + os::F_WRLCK + } else { + os::F_RDLCK + }; + + let flock = os::flock { + l_start: 0, + l_len: 0, + l_pid: 0, + l_whence: libc::SEEK_SET as libc::c_short, + l_type: lock_type, + l_sysid: 0, + }; + let cmd = if wait { os::F_SETLKW } else { os::F_SETLK }; + let ret = unsafe { + libc::fcntl(fd, cmd, &flock) + }; + if ret == -1 { + let err = io::Error::last_os_error(); + unsafe { libc::close(fd); } + Err(err) + } else { + Ok(Lock { fd: fd }) + } } } - } - impl Drop for Lock { - fn drop(&mut self) { - let flock = os::flock { - l_start: 0, - l_len: 0, - l_pid: 0, - l_whence: libc::SEEK_SET as libc::c_short, - l_type: os::F_UNLCK, - l_sysid: 0, - }; - unsafe { - libc::fcntl(self.fd, os::F_SETLK, &flock); - libc::close(self.fd); + impl Drop for Lock { + fn drop(&mut self) { + let flock = os::flock { + l_start: 0, + l_len: 0, + l_pid: 0, + l_whence: libc::SEEK_SET as libc::c_short, + l_type: os::F_UNLCK, + l_sysid: 0, + }; + unsafe { + libc::fcntl(self.fd, os::F_SETLK, &flock); + libc::close(self.fd); + } } } - } -} + } else if #[cfg(windows)] { + use std::mem; + use std::os::windows::prelude::*; + use std::os::windows::raw::HANDLE; + use std::fs::{File, OpenOptions}; + use std::os::raw::{c_ulong, c_int}; -#[cfg(windows)] -#[allow(nonstandard_style)] -mod imp { - use std::io; - use std::mem; - use std::os::windows::prelude::*; - use std::os::windows::raw::HANDLE; - use std::path::Path; - use std::fs::{File, OpenOptions}; - use std::os::raw::{c_ulong, c_int}; - - type DWORD = c_ulong; - type BOOL = c_int; - type ULONG_PTR = usize; - - type LPOVERLAPPED = *mut OVERLAPPED; - const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x0000_0002; - const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x0000_0001; - - const FILE_SHARE_DELETE: DWORD = 0x4; - const FILE_SHARE_READ: DWORD = 0x1; - const FILE_SHARE_WRITE: DWORD = 0x2; - - #[repr(C)] - struct OVERLAPPED { - Internal: ULONG_PTR, - InternalHigh: ULONG_PTR, - Offset: DWORD, - OffsetHigh: DWORD, - hEvent: HANDLE, - } + type DWORD = c_ulong; + type BOOL = c_int; + type ULONG_PTR = usize; - extern "system" { - fn LockFileEx(hFile: HANDLE, - dwFlags: DWORD, - dwReserved: DWORD, - nNumberOfBytesToLockLow: DWORD, - nNumberOfBytesToLockHigh: DWORD, - lpOverlapped: LPOVERLAPPED) -> BOOL; - } + type LPOVERLAPPED = *mut OVERLAPPED; + const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x0000_0002; + const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x0000_0001; - #[derive(Debug)] - pub struct Lock { - _file: File, - } + const FILE_SHARE_DELETE: DWORD = 0x4; + const FILE_SHARE_READ: DWORD = 0x1; + const FILE_SHARE_WRITE: DWORD = 0x2; - impl Lock { - pub fn new(p: &Path, - wait: bool, - create: bool, - exclusive: bool) - -> io::Result { - assert!(p.parent().unwrap().exists(), - "Parent directory of lock-file must exist: {}", - p.display()); - - let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; - - let mut open_options = OpenOptions::new(); - open_options.read(true) - .share_mode(share_mode); - - if create { - open_options.create(true) - .write(true); - } + #[repr(C)] + struct OVERLAPPED { + Internal: ULONG_PTR, + InternalHigh: ULONG_PTR, + Offset: DWORD, + OffsetHigh: DWORD, + hEvent: HANDLE, + } - debug!("Attempting to open lock file `{}`", p.display()); - let file = match open_options.open(p) { - Ok(file) => { - debug!("Lock file opened successfully"); - file - } - Err(err) => { - debug!("Error opening lock file: {}", err); - return Err(err) - } - }; + extern "system" { + fn LockFileEx(hFile: HANDLE, + dwFlags: DWORD, + dwReserved: DWORD, + nNumberOfBytesToLockLow: DWORD, + nNumberOfBytesToLockHigh: DWORD, + lpOverlapped: LPOVERLAPPED) -> BOOL; + } - let ret = unsafe { - let mut overlapped: OVERLAPPED = mem::zeroed(); + #[derive(Debug)] + pub struct Lock { + _file: File, + } - let mut dwFlags = 0; - if !wait { - dwFlags |= LOCKFILE_FAIL_IMMEDIATELY; + impl Lock { + pub fn new(p: &Path, + wait: bool, + create: bool, + exclusive: bool) + -> io::Result { + assert!(p.parent().unwrap().exists(), + "Parent directory of lock-file must exist: {}", + p.display()); + + let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; + + let mut open_options = OpenOptions::new(); + open_options.read(true) + .share_mode(share_mode); + + if create { + open_options.create(true) + .write(true); } - if exclusive { - dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; + debug!("Attempting to open lock file `{}`", p.display()); + let file = match open_options.open(p) { + Ok(file) => { + debug!("Lock file opened successfully"); + file + } + Err(err) => { + debug!("Error opening lock file: {}", err); + return Err(err) + } + }; + + let ret = unsafe { + let mut overlapped: OVERLAPPED = mem::zeroed(); + + let mut dwFlags = 0; + if !wait { + dwFlags |= LOCKFILE_FAIL_IMMEDIATELY; + } + + if exclusive { + dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; + } + + debug!("Attempting to acquire lock on lock file `{}`", + p.display()); + LockFileEx(file.as_raw_handle(), + dwFlags, + 0, + 0xFFFF_FFFF, + 0xFFFF_FFFF, + &mut overlapped) + }; + if ret == 0 { + let err = io::Error::last_os_error(); + debug!("Failed acquiring file lock: {}", err); + Err(err) + } else { + debug!("Successfully acquired lock."); + Ok(Lock { _file: file }) } + } + } - debug!("Attempting to acquire lock on lock file `{}`", - p.display()); - LockFileEx(file.as_raw_handle(), - dwFlags, - 0, - 0xFFFF_FFFF, - 0xFFFF_FFFF, - &mut overlapped) - }; - if ret == 0 { - let err = io::Error::last_os_error(); - debug!("Failed acquiring file lock: {}", err); - Err(err) - } else { - debug!("Successfully acquired lock."); - Ok(Lock { _file: file }) + // Note that we don't need a Drop impl on the Windows: The file is unlocked + // automatically when it's closed. + } else { + #[derive(Debug)] + pub struct Lock(()); + + impl Lock { + pub fn new(_p: &Path, _wait: bool, _create: bool, _exclusive: bool) + -> io::Result + { + let msg = "file locks not supported on this platform"; + Err(io::Error::new(io::ErrorKind::Other, msg)) } } } - - // Note that we don't need a Drop impl on the Windows: The file is unlocked - // automatically when it's closed. } -impl imp::Lock { +impl Lock { pub fn panicking_new(p: &Path, wait: bool, create: bool, diff --git a/src/librustc_errors/lock.rs b/src/librustc_errors/lock.rs index e5baf93b00064..ff323073c6235 100644 --- a/src/librustc_errors/lock.rs +++ b/src/librustc_errors/lock.rs @@ -109,7 +109,7 @@ pub fn acquire_global_lock(name: &str) -> Box { } } -#[cfg(unix)] +#[cfg(not(windows))] pub fn acquire_global_lock(_name: &str) -> Box { Box::new(()) } From d14a9c5619743f6676a99b9f2b7a8a88084ea0fe Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 31 Aug 2018 13:50:14 +0200 Subject: [PATCH 14/28] Don't promote const fn calls with arguments unless `#[rustc_promotable]` is added to the function --- src/libcore/num/mod.rs | 1 + src/libcore/ops/range.rs | 1 + src/libcore/ptr.rs | 1 + src/libcore/time.rs | 4 + src/librustc/dep_graph/dep_node.rs | 1 + src/librustc/ich/impls_syntax.rs | 1 + src/librustc/middle/stability.rs | 1 + src/librustc/ty/constness.rs | 101 +++++++++++ src/librustc/ty/context.rs | 31 ---- src/librustc/ty/mod.rs | 2 + src/librustc/ty/query/config.rs | 2 +- src/librustc/ty/query/mod.rs | 19 +- src/librustc/ty/query/plumbing.rs | 3 +- src/librustc_metadata/cstore_impl.rs | 16 +- src/librustc_metadata/decoder.rs | 2 +- src/librustc_mir/const_eval.rs | 6 - src/librustc_mir/transform/qualify_consts.rs | 167 ++++++++++-------- src/librustc_passes/rvalue_promotion.rs | 61 ++----- src/libsyntax/attr/builtin.rs | 23 ++- src/libsyntax/diagnostic_list.rs | 1 + src/test/run-pass/invalid_const_promotion2.rs | 62 +++++++ src/test/ui/consts/const-call.rs | 1 - src/test/ui/consts/const-call.stderr | 11 +- .../dont_promote_unstable_const_fn.nll.stderr | 2 +- .../dont_promote_unstable_const_fn.rs | 2 +- .../dont_promote_unstable_const_fn.stderr | 2 +- .../ui/consts/const-eval/issue-52443.stderr | 23 ++- src/test/ui/consts/const-fn-error.stderr | 23 ++- src/test/ui/issues/issue-39559-2.rs | 2 - src/test/ui/issues/issue-39559-2.stderr | 21 +-- src/test/ui/issues/issue-43105.rs | 1 - src/test/ui/issues/issue-43105.stderr | 14 +- src/test/ui/run-pass/issues/issue-49955-2.rs | 4 +- 33 files changed, 381 insertions(+), 231 deletions(-) create mode 100644 src/librustc/ty/constness.rs create mode 100644 src/test/run-pass/invalid_const_promotion2.rs diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 5ae984a4b155b..31952e9e49d38 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -69,6 +69,7 @@ assert_eq!(size_of::>(), size_of::<", st /// The value must not be zero. #[stable(feature = "nonzero", since = "1.28.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const unsafe fn new_unchecked(n: $Int) -> Self { $Ty(NonZero(n)) } diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 9c635678d7aa0..1c06f8b9e0573 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -391,6 +391,7 @@ impl RangeInclusive { /// ``` #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn new(start: Idx, end: Idx) -> Self { Self { start, end, is_empty: None } } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 57351822cc3cf..77eccb5cd249c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2865,6 +2865,7 @@ impl NonNull { /// /// `ptr` must be non-null. #[stable(feature = "nonnull", since = "1.25.0")] + #[cfg_attr(not(stage0), rustc_promotable)] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { NonNull { pointer: NonZero(ptr as _) } } diff --git a/src/libcore/time.rs b/src/libcore/time.rs index b58920224eb70..3aeb8417a1422 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -108,6 +108,7 @@ impl Duration { /// ``` #[stable(feature = "duration", since = "1.3.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn from_secs(secs: u64) -> Duration { Duration { secs, nanos: 0 } } @@ -126,6 +127,7 @@ impl Duration { /// ``` #[stable(feature = "duration", since = "1.3.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn from_millis(millis: u64) -> Duration { Duration { secs: millis / MILLIS_PER_SEC, @@ -147,6 +149,7 @@ impl Duration { /// ``` #[stable(feature = "duration_from_micros", since = "1.27.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn from_micros(micros: u64) -> Duration { Duration { secs: micros / MICROS_PER_SEC, @@ -168,6 +171,7 @@ impl Duration { /// ``` #[stable(feature = "duration_extras", since = "1.27.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn from_nanos(nanos: u64) -> Duration { Duration { secs: nanos / (NANOS_PER_SEC as u64), diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index dfe0a395ca140..cbba802be78ee 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -515,6 +515,7 @@ define_dep_nodes!( <'tcx> [] ItemVarianceConstraints(DefId), [] ItemVariances(DefId), [] IsConstFn(DefId), + [] IsPromotableConstFn(DefId), [] IsForeignItem(DefId), [] TypeParamPredicates { item_id: DefId, param_id: DefId }, [] SizedConstraint(DefId), diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index a15411c7d8369..4be467c01aac1 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -130,6 +130,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr, + promotable, const_stability }); diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index f237c5b397bd5..3ef3cae45d8f4 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -441,6 +441,7 @@ impl<'a, 'tcx> Index<'tcx> { feature: Symbol::intern("rustc_private"), rustc_depr: None, const_stability: None, + promotable: false, }); annotator.parent_stab = Some(stability); } diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs new file mode 100644 index 0000000000000..9ef2bec6dd917 --- /dev/null +++ b/src/librustc/ty/constness.rs @@ -0,0 +1,101 @@ +use ty::query::Providers; +use hir::def_id::DefId; +use hir; +use ty::TyCtxt; +use syntax_pos::symbol::Symbol; +use hir::map::blocks::FnLikeNode; +use syntax::attr; +use rustc_target::spec::abi; + +impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { + /// Whether the `def_id` counts as const fn in your current crate, considering all active + /// feature gates + pub fn is_const_fn(self, def_id: DefId) -> bool { + self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) { + Some(stab) => match stab.const_stability { + // has a `rustc_const_unstable` attribute, check whether the user enabled the + // corresponding feature gate + Some(feature_name) => self.features() + .declared_lib_features + .iter() + .any(|&(sym, _)| sym == feature_name), + // the function has no stability attribute, it is stable as const fn or the user + // nees to use feature gates to use the function at all + None => true, + }, + // functions without stability are either stable user written const fn or the user is + // using feature gates and we thus don't care what they do + None => true, + } + } + + /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it + pub fn is_unstable_const_fn(self, def_id: DefId) -> Option { + if self.is_const_fn_raw(def_id) { + self.lookup_stability(def_id)?.const_stability + } else { + None + } + } + + /// Returns true if this function must conform to `min_const_fn` + pub fn is_min_const_fn(self, def_id: DefId) -> bool { + if self.features().staged_api { + // some intrinsics are waved through if called inside the + // standard library. Users never need to call them directly + if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() { + assert!(!self.is_const_fn(def_id)); + match &self.item_name(def_id).as_str()[..] { + | "size_of" + | "min_align_of" + => return true, + _ => {}, + } + } + // in order for a libstd function to be considered min_const_fn + // it needs to be stable and have no `rustc_const_unstable` attribute + match self.lookup_stability(def_id) { + // stable functions with unstable const fn aren't `min_const_fn` + Some(&attr::Stability { const_stability: Some(_), .. }) => false, + // unstable functions don't need to conform + Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false, + // everything else needs to conform, because it would be callable from + // other `min_const_fn` functions + _ => true, + } + } else { + // users enabling the `const_fn` can do what they want + !self.sess.features_untracked().const_fn + } + } +} + + +pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { + /// only checks whether the function has a `const` modifier + fn is_const_fn_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { + let node_id = tcx.hir.as_local_node_id(def_id) + .expect("Non-local call to local provider is_const_fn"); + + if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) { + fn_like.constness() == hir::Constness::Const + } else { + false + } + } + + fn is_promotable_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { + tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) { + Some(stab) => stab.promotable, + // const fns without the promotable attribute may still be promoted if they have no + // arguments, as in that case they are semantically equivalent to constants. + None => tcx.fn_sig(def_id).skip_binder().inputs().is_empty(), + } + } + + *providers = Providers { + is_const_fn_raw, + is_promotable_const_fn, + ..*providers + }; +} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6981d92f05f00..de50598c42c9d 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1099,37 +1099,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { local as usize == global as usize } - /// Returns true if this function must conform to `min_const_fn` - pub fn is_min_const_fn(self, def_id: DefId) -> bool { - if self.features().staged_api { - // some intrinsics are waved through if called inside the - // standard library. Users never need to call them directly - if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() { - assert!(!self.is_const_fn(def_id)); - match &self.item_name(def_id).as_str()[..] { - | "size_of" - | "min_align_of" - => return true, - _ => {}, - } - } - // in order for a libstd function to be considered min_const_fn - // it needs to be stable and have no `rustc_const_unstable` attribute - match self.lookup_stability(def_id) { - // stable functions with unstable const fn aren't `min_const_fn` - Some(&attr::Stability { const_stability: Some(_), .. }) => false, - // unstable functions don't need to conform - Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false, - // everything else needs to conform, because it would be callable from - // other `min_const_fn` functions - _ => true, - } - } else { - // users enabling the `const_fn` can do what they want - !self.sess.features_untracked().const_fn - } - } - /// Create a type context and call the closure with a `TyCtxt` reference /// to the context. The closure enforces that the type context and any interned /// value (types, substs, etc.) can only be used while `ty::tls` has a valid diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5e2093d03566a..26818f43dd719 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -94,6 +94,7 @@ pub mod binding; pub mod cast; #[macro_use] pub mod codec; +mod constness; pub mod error; mod erase_regions; pub mod fast_reject; @@ -3034,6 +3035,7 @@ pub fn provide(providers: &mut ty::query::Providers) { erase_regions::provide(providers); layout::provide(providers); util::provide(providers); + constness::provide(providers); *providers = ty::query::Providers { associated_item, associated_item_def_ids, diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index 837354bfcaf36..c2993919b669b 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -434,7 +434,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::is_object_safe<'tcx> { } } -impl<'tcx> QueryDescription<'tcx> for queries::is_const_fn<'tcx> { +impl<'tcx> QueryDescription<'tcx> for queries::is_const_fn_raw<'tcx> { fn describe(tcx: TyCtxt, def_id: DefId) -> String { format!("checking if item is const fn: `{}`", tcx.item_path_str(def_id)) } diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 993ba2fd13d0d..6b9d8690702a6 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -160,8 +160,23 @@ define_queries! { <'tcx> DefId ) -> Result, NoSolution>, - /// True if this is a const fn - [] fn is_const_fn: IsConstFn(DefId) -> bool, + /// True if this is a const fn, use the `is_const_fn` to know whether your crate actually + /// sees it as const fn (e.g. the const-fn-ness might be unstable and you might not have + /// the feature gate active) + /// + /// DO NOT CALL MANUALLY, it is only meant to cache the base data for the `is_const_fn` + /// function + [] fn is_const_fn_raw: IsConstFn(DefId) -> bool, + + + /// Returns true if calls to the function may be promoted + /// + /// This is either because the function is e.g. a tuple-struct or tuple-variant constructor, + /// or because it has the `#[rustc_promotable]` attribute. The attribute should be removed + /// in the future in favour of some form of check which figures out whether the function + /// does not inspect the bits of any of its arguments (so is essentially just a constructor + /// function) + [] fn is_promotable_const_fn: IsPromotableConstFn(DefId) -> bool, /// True if this is a foreign item (i.e., linked via `extern { ... }`). [] fn is_foreign_item: IsForeignItem(DefId) -> bool, diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 215fba54499b7..9c77dfd062c37 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -1125,7 +1125,8 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::FnSignature => { force!(fn_sig, def_id!()); } DepKind::CoerceUnsizedInfo => { force!(coerce_unsized_info, def_id!()); } DepKind::ItemVariances => { force!(variances_of, def_id!()); } - DepKind::IsConstFn => { force!(is_const_fn, def_id!()); } + DepKind::IsConstFn => { force!(is_const_fn_raw, def_id!()); } + DepKind::IsPromotableConstFn => { force!(is_promotable_const_fn, def_id!()); } DepKind::IsForeignItem => { force!(is_foreign_item, def_id!()); } DepKind::SizedConstraint => { force!(adt_sized_constraint, def_id!()); } DepKind::DtorckConstraint => { force!(adt_dtorck_constraint, def_id!()); } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 5aa05270a2a0b..7eb75ca76c388 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -26,7 +26,6 @@ use rustc::ty::{self, TyCtxt}; use rustc::ty::query::Providers; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; use rustc::hir::map::{DefKey, DefPath, DefPathHash}; -use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::definitions::DefPathTable; use rustc::util::nodemap::DefIdMap; use rustc_data_structures::svh::Svh; @@ -43,7 +42,6 @@ use syntax::parse::source_file_to_stream; use syntax::symbol::Symbol; use syntax_pos::{Span, NO_EXPANSION, FileName}; use rustc_data_structures::indexed_set::IdxSet; -use rustc::hir; macro_rules! provide { (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, @@ -145,7 +143,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, } fn_sig => { cdata.fn_sig(def_id.index, tcx) } inherent_impls => { Lrc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } - is_const_fn => { cdata.is_const_fn(def_id.index) } + is_const_fn_raw => { cdata.is_const_fn_raw(def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) } describe_def => { cdata.get_def(def_id.index) } def_span => { cdata.get_span(def_id.index, &tcx.sess) } @@ -269,22 +267,10 @@ provide! { <'tcx> tcx, def_id, other, cdata, } pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { - fn is_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { - let node_id = tcx.hir.as_local_node_id(def_id) - .expect("Non-local call to local provider is_const_fn"); - - if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) { - fn_like.constness() == hir::Constness::Const - } else { - false - } - } - // FIXME(#44234) - almost all of these queries have no sub-queries and // therefore no actual inputs, they're just reading tables calculated in // resolve! Does this work? Unsure! That's what the issue is about *providers = Providers { - is_const_fn, is_dllimport_foreign_item: |tcx, id| { tcx.native_library_kind(id) == Some(NativeLibraryKind::NativeUnknown) }, diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 9907df7ed0240..84a5a05329ea2 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1077,7 +1077,7 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn is_const_fn(&self, id: DefIndex) -> bool { + crate fn is_const_fn_raw(&self, id: DefIndex) -> bool { let constness = match self.entry(id).kind { EntryKind::Method(data) => data.decode(self).fn_data.constness, EntryKind::Fn(data) => data.decode(self).constness, diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 92ddd8777f733..6c79585b23339 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -201,7 +201,6 @@ impl_stable_hash_for!(struct CompileTimeEvaluator {}); #[derive(Clone, Debug)] enum ConstEvalError { NeedsRfc(String), - NotConst(String), } impl fmt::Display for ConstEvalError { @@ -215,7 +214,6 @@ impl fmt::Display for ConstEvalError { msg ) } - NotConst(ref msg) => write!(f, "{}", msg), } } } @@ -225,7 +223,6 @@ impl Error for ConstEvalError { use self::ConstEvalError::*; match *self { NeedsRfc(_) => "this feature needs an rfc before being allowed inside constants", - NotConst(_) => "this feature is not compatible with constant evaluation", } } @@ -255,9 +252,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator { ecx.goto_block(ret)?; // fully evaluated and done return Ok(None); } - return Err( - ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(), - ); } // This is a const fn. Call it. Ok(Some(match ecx.load_mir(instance.def) { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 050901b9b508a..f328296eee18b 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -30,7 +30,6 @@ use rustc::mir::traversal::ReversePostorder; use rustc::mir::visit::{PlaceContext, Visitor}; use rustc::middle::lang_items; use rustc_target::spec::abi::Abi; -use syntax::attr; use syntax::ast::LitKind; use syntax::feature_gate::{UnstableFeatures, feature_err, emit_feature_err, GateIssue}; use syntax_pos::{Span, DUMMY_SP}; @@ -814,7 +813,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { let fn_ty = func.ty(self.mir, self.tcx); let mut callee_def_id = None; - let (mut is_shuffle, mut is_const_fn) = (false, None); + let (mut is_shuffle, mut is_const_fn) = (false, false); if let ty::FnDef(def_id, _) = fn_ty.sty { callee_def_id = Some(def_id); match self.tcx.fn_sig(def_id).abi() { @@ -839,10 +838,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { | "unchecked_shr" | "add_with_overflow" | "sub_with_overflow" - | "mul_with_overflow" => is_const_fn = Some(def_id), + | "mul_with_overflow" + // no need to check feature gates, intrinsics are only callable from the + // libstd or with forever unstable feature gates + => is_const_fn = true, + // special intrinsic that can be called diretly without an intrinsic + // feature gate needs a language feature gate "transmute" => { + // never promote transmute calls if self.mode != Mode::Fn { - is_const_fn = Some(def_id); + is_const_fn = true; + // const eval transmute calls only with the feature gate if !self.tcx.sess.features_untracked().const_transmute { emit_feature_err( &self.tcx.sess.parse_sess, "const_transmute", @@ -861,8 +867,81 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } _ => { - if self.tcx.is_const_fn(def_id) || self.is_const_panic_fn(def_id) { - is_const_fn = Some(def_id); + // in normal functions we only care about promotion + if self.mode == Mode::Fn { + // never promote const fn calls of + // functions without #[rustc_promotable] + if self.tcx.is_promotable_const_fn(def_id) { + is_const_fn = true; + } + } else { + // stable const fn or unstable const fns with their feature gate + // active + if self.tcx.is_const_fn(def_id) { + is_const_fn = true; + } else if self.is_const_panic_fn(def_id) { + // check the const_panic feature gate + // FIXME: cannot allow this inside `allow_internal_unstable` because + // that would make `panic!` insta stable in constants, since the + // macro is marked with the attr + if self.tcx.sess.features_untracked().const_panic { + is_const_fn = true; + } else { + // don't allow panics in constants without the feature gate + emit_feature_err( + &self.tcx.sess.parse_sess, + "const_panic", + self.span, + GateIssue::Language, + &format!("panicking in {}s is unstable", self.mode), + ); + } + } else if let Some(feature) = self.tcx.is_unstable_const_fn(def_id) { + // check `#[unstable]` const fns or `#[rustc_const_unstable]` + // functions without the feature gate active in this crate to report + // a better error message than the one below + if self.span.allows_unstable() { + // `allow_internal_unstable` can make such calls stable + is_const_fn = true; + } else { + let mut err = self.tcx.sess.struct_span_err(self.span, + &format!("`{}` is not yet stable as a const fn", + self.tcx.item_path_str(def_id))); + help!(&mut err, + "in Nightly builds, add `#![feature({})]` \ + to the crate attributes to enable", + feature); + err.emit(); + } + } else { + // FIXME(#24111) Remove this check when const fn stabilizes + let (msg, note) = if let UnstableFeatures::Disallow = + self.tcx.sess.opts.unstable_features { + (format!("calls in {}s are limited to \ + tuple structs and tuple variants", + self.mode), + Some("a limited form of compile-time function \ + evaluation is available on a nightly \ + compiler via `const fn`")) + } else { + (format!("calls in {}s are limited \ + to constant functions, \ + tuple structs and tuple variants", + self.mode), + None) + }; + let mut err = struct_span_err!( + self.tcx.sess, + self.span, + E0015, + "{}", + msg, + ); + if let Some(note) = note { + err.span_note(self.span, note); + } + err.emit(); + } } } } @@ -905,78 +984,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { }); } - // Const fn calls. - if let Some(def_id) = is_const_fn { - // check the const_panic feature gate or - // find corresponding rustc_const_unstable feature - // FIXME: cannot allow this inside `allow_internal_unstable` because that would make - // `panic!` insta stable in constants, since the macro is marked with the attr - if self.is_const_panic_fn(def_id) { - if self.mode == Mode::Fn { - // never promote panics - self.qualif = Qualif::NOT_CONST; - } else if !self.tcx.sess.features_untracked().const_panic { - // don't allow panics in constants without the feature gate - emit_feature_err( - &self.tcx.sess.parse_sess, - "const_panic", - self.span, - GateIssue::Language, - &format!("panicking in {}s is unstable", self.mode), - ); - } - } else if let Some(&attr::Stability { - const_stability: Some(ref feature_name), - .. }) = self.tcx.lookup_stability(def_id) { - if - // feature-gate is not enabled, - !self.tcx.features() - .declared_lib_features - .iter() - .any(|&(ref sym, _)| sym == feature_name) && - - // this doesn't come from a macro that has #[allow_internal_unstable] - !self.span.allows_unstable() - { - self.qualif = Qualif::NOT_CONST; - if self.mode != Mode::Fn { - // inside a constant environment, not having the feature gate is - // an error - let mut err = self.tcx.sess.struct_span_err(self.span, - &format!("`{}` is not yet stable as a const fn", - self.tcx.item_path_str(def_id))); - help!(&mut err, - "in Nightly builds, add `#![feature({})]` \ - to the crate attributes to enable", - feature_name); - err.emit(); - } - } - } - } else { + // non-const fn calls. + if !is_const_fn { self.qualif = Qualif::NOT_CONST; if self.mode != Mode::Fn { - // FIXME(#24111) Remove this check when const fn stabilizes - let (msg, note) = if let UnstableFeatures::Disallow = - self.tcx.sess.opts.unstable_features { - (format!("calls in {}s are limited to \ - tuple structs and tuple variants", - self.mode), - Some("a limited form of compile-time function \ - evaluation is available on a nightly \ - compiler via `const fn`")) - } else { - (format!("calls in {}s are limited \ - to constant functions, \ - tuple structs and tuple variants", - self.mode), - None) - }; - let mut err = struct_span_err!(self.tcx.sess, self.span, E0015, "{}", msg); - if let Some(note) = note { - err.span_note(self.span, note); - } - err.emit(); + self.tcx.sess.delay_span_bug( + self.span, + "should have reported an error about non-const fn calls in constants", + ) } } diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index ea4fba3e12481..e20afa2ab09d8 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -27,7 +27,6 @@ use rustc::ty::cast::CastKind; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; -use rustc::hir::map::blocks::FnLikeNode; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; @@ -38,7 +37,6 @@ use rustc::util::nodemap::{ItemLocalSet, NodeSet}; use rustc::hir; use rustc_data_structures::sync::Lrc; use syntax::ast; -use syntax::attr; use syntax_pos::{Span, DUMMY_SP}; use self::Promotability::*; use std::ops::{BitAnd, BitOr}; @@ -159,41 +157,15 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { } } - fn handle_const_fn_call(&mut self, def_id: DefId, - ret_ty: Ty<'gcx>, span: Span) -> Promotability { - if let NotPromotable = self.type_promotability(ret_ty) { - return NotPromotable; - } - - let node_check = if let Some(fn_id) = self.tcx.hir.as_local_node_id(def_id) { - FnLikeNode::from_node(self.tcx.hir.get(fn_id)).map_or(false, |fn_like| { - fn_like.constness() == hir::Constness::Const - }) + fn handle_const_fn_call( + &mut self, + def_id: DefId, + ) -> Promotability { + if self.tcx.is_promotable_const_fn(def_id) { + Promotable } else { - self.tcx.is_const_fn(def_id) - }; - - if !node_check { - return NotPromotable - } - - if let Some(&attr::Stability { - const_stability: Some(ref feature_name), - .. }) = self.tcx.lookup_stability(def_id) { - let stable_check = - // feature-gate is enabled, - self.tcx.features() - .declared_lib_features - .iter() - .any(|&(ref sym, _)| sym == feature_name) || - - // this comes from a macro that has #[allow_internal_unstable] - span.allows_unstable(); - if !stable_check { - return NotPromotable + NotPromotable } - }; - Promotable } /// While the `ExprUseVisitor` walks, we will identify which @@ -446,14 +418,10 @@ fn check_expr_kind<'a, 'tcx>( let def_result = match def { Def::StructCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Fn) => Promotable, - Def::Fn(did) => { - v.handle_const_fn_call(did, node_ty, e.span) - } + Def::Fn(did) => v.handle_const_fn_call(did), Def::Method(did) => { match v.tcx.associated_item(did).container { - ty::ImplContainer(_) => { - v.handle_const_fn_call(did, node_ty, e.span) - } + ty::ImplContainer(_) => v.handle_const_fn_call(did), ty::TraitContainer(_) => NotPromotable, } } @@ -469,16 +437,13 @@ fn check_expr_kind<'a, 'tcx>( if let Some(def) = v.tables.type_dependent_defs().get(e.hir_id) { let def_id = def.def_id(); match v.tcx.associated_item(def_id).container { - ty::ImplContainer(_) => { - method_call_result = method_call_result - & v.handle_const_fn_call(def_id, node_ty, e.span); - } - ty::TraitContainer(_) => return NotPromotable, - }; + ty::ImplContainer(_) => method_call_result & v.handle_const_fn_call(def_id), + ty::TraitContainer(_) => NotPromotable, + } } else { v.tcx.sess.delay_span_bug(e.span, "no type-dependent def for method call"); + NotPromotable } - method_call_result } hir::ExprKind::Struct(ref _qpath, ref hirvec, ref option_expr) => { let mut struct_result = Promotable; diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 3eecdf14a4e50..0cd103e7908ed 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -112,6 +112,8 @@ pub struct Stability { /// `Some` contains the feature gate required to be able to use the function /// as const fn pub const_stability: Option, + /// whether the function has a `#[rustc_promotable]` attribute + pub promotable: bool, } /// The available stability levels. @@ -176,6 +178,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut stab: Option = None; let mut rustc_depr: Option = None; let mut rustc_const_unstable: Option = None; + let mut promotable = false; 'outer: for attr in attrs_iter { if ![ @@ -183,6 +186,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, "rustc_const_unstable", "unstable", "stable", + "rustc_promotable", ].iter().any(|&s| attr.path == s) { continue // not a stability level } @@ -190,8 +194,12 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, mark_used(attr); let meta = attr.meta(); + + if attr.path == "rustc_promotable" { + promotable = true; + } // attributes with data - if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta { + else if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta { let meta = meta.as_ref().unwrap(); let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { @@ -329,6 +337,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, feature, rustc_depr: None, const_stability: None, + promotable: false, }) } (None, _, _) => { @@ -378,6 +387,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, feature, rustc_depr: None, const_stability: None, + promotable: false, }) } (None, _) => { @@ -420,6 +430,17 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, } } + // Merge the const-unstable info into the stability info + if promotable { + if let Some(ref mut stab) = stab { + stab.promotable = true; + } else { + span_err!(diagnostic, item_sp, E0713, + "rustc_promotable attribute must be paired with \ + either stable or unstable attribute"); + } + } + stab } diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 23ce7fc6a6568..b5818036acdde 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -413,4 +413,5 @@ register_diagnostics! { E0694, // an unknown tool name found in scoped attributes E0703, // invalid ABI E0704, // incorrect visibility restriction + E0713, // rustc_promotable without stability attribute } diff --git a/src/test/run-pass/invalid_const_promotion2.rs b/src/test/run-pass/invalid_const_promotion2.rs new file mode 100644 index 0000000000000..6fa7eb6104d48 --- /dev/null +++ b/src/test/run-pass/invalid_const_promotion2.rs @@ -0,0 +1,62 @@ +// 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. + +// ignore-wasm32 +// ignore-emscripten + +// compile-flags: -C debug_assertions=yes + +#![feature(const_fn, libc)] +#![allow(const_err)] + +extern crate libc; + +use std::env; +use std::process::{Command, Stdio}; + +union Foo { + x: &'static u8, + y: usize, +} +const FOO: usize = unsafe { Foo { x: &1 }.y }; + +fn foo() { + let x: &'static _ = &(FOO * 2); +} + +#[cfg(unix)] +fn check_status(status: std::process::ExitStatus) +{ + use libc; + use std::os::unix::process::ExitStatusExt; + + assert!(status.signal() == Some(libc::SIGILL) + || status.signal() == Some(libc::SIGABRT)); +} + +#[cfg(not(unix))] +fn check_status(status: std::process::ExitStatus) +{ + assert!(!status.success()); +} + +fn main() { + let args: Vec = env::args().collect(); + if args.len() > 1 && args[1] == "test" { + foo(); + return; + } + + let mut p = Command::new(&args[0]) + .stdout(Stdio::piped()) + .stdin(Stdio::piped()) + .arg("test").output().unwrap(); + check_status(p.status); +} diff --git a/src/test/ui/consts/const-call.rs b/src/test/ui/consts/const-call.rs index 02264228a6bf6..18476494300b2 100644 --- a/src/test/ui/consts/const-call.rs +++ b/src/test/ui/consts/const-call.rs @@ -15,5 +15,4 @@ fn f(x: usize) -> usize { fn main() { let _ = [0; f(2)]; //~^ ERROR calls in constants are limited to constant functions - //~| E0080 } diff --git a/src/test/ui/consts/const-call.stderr b/src/test/ui/consts/const-call.stderr index efc3c58c6813b..81be93e916e8b 100644 --- a/src/test/ui/consts/const-call.stderr +++ b/src/test/ui/consts/const-call.stderr @@ -4,13 +4,6 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | let _ = [0; f(2)]; | ^^^^ -error[E0080]: could not evaluate repeat length - --> $DIR/const-call.rs:16:17 - | -LL | let _ = [0; f(2)]; - | ^^^^ calling non-const fn `f` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0015, E0080. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr index ed3e38486baf6..c3ec7825fff05 100644 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr @@ -11,7 +11,7 @@ error[E0597]: borrowed value does not live long enough | LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -LL | //~^ does not live long enough +LL | //~^ ERROR does not live long enough LL | } | - temporary value only lives until here | diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs index 623e99480a70a..a371d5485e146 100644 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs @@ -31,5 +31,5 @@ fn a() { fn main() { let _: &'static u32 = &meh(); //~ ERROR does not live long enough let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); - //~^ does not live long enough + //~^ ERROR does not live long enough } diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr index b9856d37b0ee1..b3d7ba3e5c47a 100644 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr @@ -32,7 +32,7 @@ error[E0597]: borrowed value does not live long enough | LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -LL | //~^ does not live long enough +LL | //~^ ERROR does not live long enough LL | } | - temporary value only lives until here | diff --git a/src/test/ui/consts/const-eval/issue-52443.stderr b/src/test/ui/consts/const-eval/issue-52443.stderr index 3a145ba78d9b1..8c6beda6fb918 100644 --- a/src/test/ui/consts/const-eval/issue-52443.stderr +++ b/src/test/ui/consts/const-eval/issue-52443.stderr @@ -43,7 +43,28 @@ error[E0080]: could not evaluate repeat length LL | [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions | ^^^^^^^^^^^--------^^^^^^^ | | - | calling non-const fn `>::into_iter` + | inside call to `std::iter::range::>::next` + | + ::: $SRC_DIR/libcore/ptr.rs:LL:COL + | +LL | let z = read(x); + | ------- inside call to `std::ptr::read::` +... +LL | let mut tmp: T = mem::uninitialized(); + | -------------------- inside call to `std::mem::uninitialized::` + | + ::: $SRC_DIR/libcore/iter/range.rs:LL:COL + | +LL | mem::swap(&mut n, &mut self.start); + | ---------------------------------- inside call to `std::mem::swap::` + | + ::: $SRC_DIR/libcore/mem.rs:LL:COL + | +LL | intrinsics::uninit() + | -------------------- "calling intrinsic `uninit`" needs an rfc before being allowed inside constants +... +LL | ptr::swap_nonoverlapping_one(x, y); + | ---------------------------------- inside call to `std::ptr::swap_nonoverlapping_one::` error: aborting due to 6 previous errors diff --git a/src/test/ui/consts/const-fn-error.stderr b/src/test/ui/consts/const-fn-error.stderr index cdbf86f42ecc0..439493a1e8058 100644 --- a/src/test/ui/consts/const-fn-error.stderr +++ b/src/test/ui/consts/const-fn-error.stderr @@ -30,12 +30,33 @@ error[E0080]: could not evaluate constant expression --> $DIR/const-fn-error.rs:29:13 | LL | for i in 0..x { - | ---- calling non-const fn `>::into_iter` + | ---- inside call to `std::iter::range::>::next` ... LL | let a : [i32; f(X)]; //~ ERROR E0080 | ^^^^^^----^ | | | inside call to `f` + | + ::: $SRC_DIR/libcore/ptr.rs:LL:COL + | +LL | let z = read(x); + | ------- inside call to `std::ptr::read::` +... +LL | let mut tmp: T = mem::uninitialized(); + | -------------------- inside call to `std::mem::uninitialized::` + | + ::: $SRC_DIR/libcore/iter/range.rs:LL:COL + | +LL | mem::swap(&mut n, &mut self.start); + | ---------------------------------- inside call to `std::mem::swap::` + | + ::: $SRC_DIR/libcore/mem.rs:LL:COL + | +LL | intrinsics::uninit() + | -------------------- "calling intrinsic `uninit`" needs an rfc before being allowed inside constants +... +LL | ptr::swap_nonoverlapping_one(x, y); + | ---------------------------------- inside call to `std::ptr::swap_nonoverlapping_one::` error: aborting due to 5 previous errors diff --git a/src/test/ui/issues/issue-39559-2.rs b/src/test/ui/issues/issue-39559-2.rs index f01fd1fd8f144..2e480a29774ce 100644 --- a/src/test/ui/issues/issue-39559-2.rs +++ b/src/test/ui/issues/issue-39559-2.rs @@ -23,8 +23,6 @@ impl Dim for Dim3 { fn main() { let array: [usize; Dim3::dim()] //~^ ERROR E0015 - //~| ERROR E0080 = [0; Dim3::dim()]; //~^ ERROR E0015 - //~| ERROR E0080 } diff --git a/src/test/ui/issues/issue-39559-2.stderr b/src/test/ui/issues/issue-39559-2.stderr index 91520a7ec0867..ca9da096b6c16 100644 --- a/src/test/ui/issues/issue-39559-2.stderr +++ b/src/test/ui/issues/issue-39559-2.stderr @@ -5,26 +5,11 @@ LL | let array: [usize; Dim3::dim()] | ^^^^^^^^^^^ error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants - --> $DIR/issue-39559-2.rs:27:15 + --> $DIR/issue-39559-2.rs:26:15 | LL | = [0; Dim3::dim()]; | ^^^^^^^^^^^ -error[E0080]: could not evaluate repeat length - --> $DIR/issue-39559-2.rs:27:15 - | -LL | = [0; Dim3::dim()]; - | ^^^^^^^^^^^ calling non-const fn `::dim` - -error[E0080]: could not evaluate constant expression - --> $DIR/issue-39559-2.rs:24:16 - | -LL | let array: [usize; Dim3::dim()] - | ^^^^^^^^-----------^ - | | - | calling non-const fn `::dim` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0015, E0080. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/issues/issue-43105.rs b/src/test/ui/issues/issue-43105.rs index 8a0471135afc4..2bddc443d5baf 100644 --- a/src/test/ui/issues/issue-43105.rs +++ b/src/test/ui/issues/issue-43105.rs @@ -16,7 +16,6 @@ const NUM: u8 = xyz(); fn main() { match 1 { NUM => unimplemented!(), - //~^ ERROR could not evaluate constant pattern _ => unimplemented!(), } } diff --git a/src/test/ui/issues/issue-43105.stderr b/src/test/ui/issues/issue-43105.stderr index 18da9310503ea..67a6008cd8ebc 100644 --- a/src/test/ui/issues/issue-43105.stderr +++ b/src/test/ui/issues/issue-43105.stderr @@ -4,16 +4,6 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | const NUM: u8 = xyz(); | ^^^^^ -error[E0080]: could not evaluate constant pattern - --> $DIR/issue-43105.rs:18:9 - | -LL | const NUM: u8 = xyz(); - | ----- calling non-const fn `xyz` -... -LL | NUM => unimplemented!(), - | ^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0015, E0080. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/run-pass/issues/issue-49955-2.rs b/src/test/ui/run-pass/issues/issue-49955-2.rs index 40827b0162202..88883821073d3 100644 --- a/src/test/ui/run-pass/issues/issue-49955-2.rs +++ b/src/test/ui/run-pass/issues/issue-49955-2.rs @@ -13,13 +13,15 @@ use std::cell::Cell; +const FIVE: Cell = Cell::new(5); + #[inline(never)] fn tuple_field() -> &'static u32 { // This test is MIR-borrowck-only because the old borrowck // doesn't agree that borrows of "frozen" (i.e. without any // interior mutability) fields of non-frozen temporaries, // should be promoted, while MIR promotion does promote them. - &(Cell::new(5), 42).1 + &(FIVE, 42).1 } fn main() { From 6a7175ff1d2612f93f3789f1f06a90c534787316 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 4 Sep 2018 13:33:35 +0200 Subject: [PATCH 15/28] Check that min_const_fn doesn't promote functions with arguments --- src/test/ui/consts/min_const_fn/promotion.rs | 9 +++++++++ src/test/ui/consts/min_const_fn/promotion.stderr | 13 +++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/consts/min_const_fn/promotion.rs create mode 100644 src/test/ui/consts/min_const_fn/promotion.stderr diff --git a/src/test/ui/consts/min_const_fn/promotion.rs b/src/test/ui/consts/min_const_fn/promotion.rs new file mode 100644 index 0000000000000..cf86537444d1d --- /dev/null +++ b/src/test/ui/consts/min_const_fn/promotion.rs @@ -0,0 +1,9 @@ +#![feature(min_const_fn)] + +const fn foo1() {} +const fn foo2(x: i32) -> i32 { x } + +fn main() { + let x: &'static () = &foo1(); + let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough +} \ No newline at end of file diff --git a/src/test/ui/consts/min_const_fn/promotion.stderr b/src/test/ui/consts/min_const_fn/promotion.stderr new file mode 100644 index 0000000000000..0d8ef422ea643 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/promotion.stderr @@ -0,0 +1,13 @@ +error[E0597]: borrowed value does not live long enough + --> $DIR/promotion.rs:8:28 + | +LL | let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough + | ^^^^^^^^ temporary value does not live long enough +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From 9876ff6ab64b61044df708c0efb97de13c778f99 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 4 Sep 2018 13:52:39 +0200 Subject: [PATCH 16/28] Some `Sync` tests --- .../consts/min_const_fn/promotion.nll.stderr | 46 +++++++++++++++++++ src/test/ui/consts/min_const_fn/promotion.rs | 12 ++++- .../ui/consts/min_const_fn/promotion.stderr | 3 +- 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/consts/min_const_fn/promotion.nll.stderr diff --git a/src/test/ui/consts/min_const_fn/promotion.nll.stderr b/src/test/ui/consts/min_const_fn/promotion.nll.stderr new file mode 100644 index 0000000000000..7492ee5da1861 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/promotion.nll.stderr @@ -0,0 +1,46 @@ +error[E0597]: borrowed value does not live long enough + --> $DIR/promotion.rs:14:28 + | +LL | let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough + | ^^^^^^^^ temporary value does not live long enough +... +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/promotion.rs:16:34 + | +LL | let a: &'static Cell = &foo4(); + | ^^^^^^ temporary value does not live long enough +... +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/promotion.rs:17:42 + | +LL | let a: &'static Option> = &foo5(); + | ^^^^^^ temporary value does not live long enough +LL | let a: &'static Option> = &foo6(); +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/promotion.rs:18:42 + | +LL | let a: &'static Option> = &foo6(); + | ^^^^^^ temporary value does not live long enough +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/consts/min_const_fn/promotion.rs b/src/test/ui/consts/min_const_fn/promotion.rs index cf86537444d1d..c0fc2f58c7fa7 100644 --- a/src/test/ui/consts/min_const_fn/promotion.rs +++ b/src/test/ui/consts/min_const_fn/promotion.rs @@ -1,9 +1,19 @@ #![feature(min_const_fn)] +use std::cell::Cell; + const fn foo1() {} const fn foo2(x: i32) -> i32 { x } +const fn foo3() -> i32 { 42 } +const fn foo4() -> Cell { Cell::new(42) } +const fn foo5() -> Option> { Some(Cell::new(42)) } +const fn foo6() -> Option> { None } fn main() { let x: &'static () = &foo1(); let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough -} \ No newline at end of file + let z: &'static i32 = &foo3(); + let a: &'static Cell = &foo4(); // doesn't error on HIR borrowck + let a: &'static Option> = &foo5(); // doesn't error on HIR borrowck + let a: &'static Option> = &foo6(); // doesn't error on HIR borrowck +} diff --git a/src/test/ui/consts/min_const_fn/promotion.stderr b/src/test/ui/consts/min_const_fn/promotion.stderr index 0d8ef422ea643..503c99f04df21 100644 --- a/src/test/ui/consts/min_const_fn/promotion.stderr +++ b/src/test/ui/consts/min_const_fn/promotion.stderr @@ -1,8 +1,9 @@ error[E0597]: borrowed value does not live long enough - --> $DIR/promotion.rs:8:28 + --> $DIR/promotion.rs:14:28 | LL | let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough | ^^^^^^^^ temporary value does not live long enough +... LL | } | - temporary value only lives until here | From 0a7a208c158bccbec9d960b65008c2492082b930 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 4 Sep 2018 14:58:05 +0200 Subject: [PATCH 17/28] Ban promoting user defined const fns --- src/librustc/ty/constness.rs | 5 +- src/test/run-pass/invalid_const_promotion.rs | 3 +- src/test/run-pass/invalid_const_promotion2.rs | 62 ------------------- .../const-eval/promoted_const_fn_fail.rs | 7 +-- .../const-eval/promoted_const_fn_fail.stderr | 14 +++++ .../consts/min_const_fn/promotion.nll.stderr | 46 -------------- src/test/ui/consts/min_const_fn/promotion.rs | 10 +-- .../ui/consts/min_const_fn/promotion.stderr | 56 ++++++++++++++++- src/test/ui/rustc-args-required-const.rs | 3 +- src/test/ui/rustc-args-required-const.stderr | 4 +- 10 files changed, 85 insertions(+), 125 deletions(-) delete mode 100644 src/test/run-pass/invalid_const_promotion2.rs create mode 100644 src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr delete mode 100644 src/test/ui/consts/min_const_fn/promotion.nll.stderr diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index 9ef2bec6dd917..cbde0995eb6f9 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -89,7 +89,10 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { Some(stab) => stab.promotable, // const fns without the promotable attribute may still be promoted if they have no // arguments, as in that case they are semantically equivalent to constants. - None => tcx.fn_sig(def_id).skip_binder().inputs().is_empty(), + // also only promote such const fns if they are defined in the standard library + None => { + tcx.fn_sig(def_id).skip_binder().inputs().is_empty() && tcx.features().staged_api + }, } } diff --git a/src/test/run-pass/invalid_const_promotion.rs b/src/test/run-pass/invalid_const_promotion.rs index a18d82fb7a4e7..10b868bf5aa99 100644 --- a/src/test/run-pass/invalid_const_promotion.rs +++ b/src/test/run-pass/invalid_const_promotion.rs @@ -13,7 +13,8 @@ // compile-flags: -C debug_assertions=yes -#![feature(const_fn, libc)] +#![stable(feature = "rustc", since = "1.0.0")] +#![feature(const_fn, libc, staged_api)] #![allow(const_err)] extern crate libc; diff --git a/src/test/run-pass/invalid_const_promotion2.rs b/src/test/run-pass/invalid_const_promotion2.rs deleted file mode 100644 index 6fa7eb6104d48..0000000000000 --- a/src/test/run-pass/invalid_const_promotion2.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-wasm32 -// ignore-emscripten - -// compile-flags: -C debug_assertions=yes - -#![feature(const_fn, libc)] -#![allow(const_err)] - -extern crate libc; - -use std::env; -use std::process::{Command, Stdio}; - -union Foo { - x: &'static u8, - y: usize, -} -const FOO: usize = unsafe { Foo { x: &1 }.y }; - -fn foo() { - let x: &'static _ = &(FOO * 2); -} - -#[cfg(unix)] -fn check_status(status: std::process::ExitStatus) -{ - use libc; - use std::os::unix::process::ExitStatusExt; - - assert!(status.signal() == Some(libc::SIGILL) - || status.signal() == Some(libc::SIGABRT)); -} - -#[cfg(not(unix))] -fn check_status(status: std::process::ExitStatus) -{ - assert!(!status.success()); -} - -fn main() { - let args: Vec = env::args().collect(); - if args.len() > 1 && args[1] == "test" { - foo(); - return; - } - - let mut p = Command::new(&args[0]) - .stdout(Stdio::piped()) - .stdin(Stdio::piped()) - .arg("test").output().unwrap(); - check_status(p.status); -} diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs index 19db07dd330ae..9b03ddd189168 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass - #![feature(const_fn, const_fn_union)] #![deny(const_err)] @@ -29,10 +27,7 @@ const fn bar() -> u8 { } fn main() { - // FIXME(oli-obk): this should panic at runtime - // this will actually compile, but then - // abort at runtime (not panic, hard abort). - let x: &'static u8 = &(bar() + 1); + let x: &'static u8 = &(bar() + 1); //~ ERROR does not live long enough let y = *x; unreachable!(); } diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr b/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr new file mode 100644 index 0000000000000..4d80f701bcf04 --- /dev/null +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr @@ -0,0 +1,14 @@ +error[E0597]: borrowed value does not live long enough + --> $DIR/promoted_const_fn_fail.rs:30:27 + | +LL | let x: &'static u8 = &(bar() + 1); //~ ERROR does not live long enough + | ^^^^^^^^^^^ temporary value does not live long enough +... +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/consts/min_const_fn/promotion.nll.stderr b/src/test/ui/consts/min_const_fn/promotion.nll.stderr deleted file mode 100644 index 7492ee5da1861..0000000000000 --- a/src/test/ui/consts/min_const_fn/promotion.nll.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error[E0597]: borrowed value does not live long enough - --> $DIR/promotion.rs:14:28 - | -LL | let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough - | ^^^^^^^^ temporary value does not live long enough -... -LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... - -error[E0597]: borrowed value does not live long enough - --> $DIR/promotion.rs:16:34 - | -LL | let a: &'static Cell = &foo4(); - | ^^^^^^ temporary value does not live long enough -... -LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... - -error[E0597]: borrowed value does not live long enough - --> $DIR/promotion.rs:17:42 - | -LL | let a: &'static Option> = &foo5(); - | ^^^^^^ temporary value does not live long enough -LL | let a: &'static Option> = &foo6(); -LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... - -error[E0597]: borrowed value does not live long enough - --> $DIR/promotion.rs:18:42 - | -LL | let a: &'static Option> = &foo6(); - | ^^^^^^ temporary value does not live long enough -LL | } - | - temporary value only lives until here - | - = note: borrowed value must be valid for the static lifetime... - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/consts/min_const_fn/promotion.rs b/src/test/ui/consts/min_const_fn/promotion.rs index c0fc2f58c7fa7..cb3bfd74711ca 100644 --- a/src/test/ui/consts/min_const_fn/promotion.rs +++ b/src/test/ui/consts/min_const_fn/promotion.rs @@ -10,10 +10,10 @@ const fn foo5() -> Option> { Some(Cell::new(42)) } const fn foo6() -> Option> { None } fn main() { - let x: &'static () = &foo1(); + let x: &'static () = &foo1(); //~ ERROR does not live long enough let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough - let z: &'static i32 = &foo3(); - let a: &'static Cell = &foo4(); // doesn't error on HIR borrowck - let a: &'static Option> = &foo5(); // doesn't error on HIR borrowck - let a: &'static Option> = &foo6(); // doesn't error on HIR borrowck + let z: &'static i32 = &foo3(); //~ ERROR does not live long enough + let a: &'static Cell = &foo4(); //~ ERROR does not live long enough + let a: &'static Option> = &foo5(); //~ ERROR does not live long enough + let a: &'static Option> = &foo6(); //~ ERROR does not live long enough } diff --git a/src/test/ui/consts/min_const_fn/promotion.stderr b/src/test/ui/consts/min_const_fn/promotion.stderr index 503c99f04df21..68d584658223f 100644 --- a/src/test/ui/consts/min_const_fn/promotion.stderr +++ b/src/test/ui/consts/min_const_fn/promotion.stderr @@ -1,3 +1,14 @@ +error[E0597]: borrowed value does not live long enough + --> $DIR/promotion.rs:13:27 + | +LL | let x: &'static () = &foo1(); //~ ERROR does not live long enough + | ^^^^^^ temporary value does not live long enough +... +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + error[E0597]: borrowed value does not live long enough --> $DIR/promotion.rs:14:28 | @@ -9,6 +20,49 @@ LL | } | = note: borrowed value must be valid for the static lifetime... -error: aborting due to previous error +error[E0597]: borrowed value does not live long enough + --> $DIR/promotion.rs:15:28 + | +LL | let z: &'static i32 = &foo3(); //~ ERROR does not live long enough + | ^^^^^^ temporary value does not live long enough +... +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/promotion.rs:16:34 + | +LL | let a: &'static Cell = &foo4(); //~ ERROR does not live long enough + | ^^^^^^ temporary value does not live long enough +... +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/promotion.rs:17:42 + | +LL | let a: &'static Option> = &foo5(); //~ ERROR does not live long enough + | ^^^^^^ temporary value does not live long enough +LL | let a: &'static Option> = &foo6(); //~ ERROR does not live long enough +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/promotion.rs:18:42 + | +LL | let a: &'static Option> = &foo6(); //~ ERROR does not live long enough + | ^^^^^^ temporary value does not live long enough +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/rustc-args-required-const.rs b/src/test/ui/rustc-args-required-const.rs index 35b43b4c460a4..15465ac52aa43 100644 --- a/src/test/ui/rustc-args-required-const.rs +++ b/src/test/ui/rustc-args-required-const.rs @@ -27,7 +27,8 @@ const fn baz() -> i32 { fn main() { foo(2); foo(2 + 3); - foo(baz()); + const BAZ: i32 = baz(); + foo(BAZ); let a = 4; foo(A); foo(a); //~ ERROR: argument 1 is required to be a constant diff --git a/src/test/ui/rustc-args-required-const.stderr b/src/test/ui/rustc-args-required-const.stderr index 07f2d880c82b4..efd4c58f152a7 100644 --- a/src/test/ui/rustc-args-required-const.stderr +++ b/src/test/ui/rustc-args-required-const.stderr @@ -1,11 +1,11 @@ error: argument 1 is required to be a constant - --> $DIR/rustc-args-required-const.rs:33:5 + --> $DIR/rustc-args-required-const.rs:34:5 | LL | foo(a); //~ ERROR: argument 1 is required to be a constant | ^^^^^^ error: argument 2 is required to be a constant - --> $DIR/rustc-args-required-const.rs:35:5 + --> $DIR/rustc-args-required-const.rs:36:5 | LL | bar(a, a); //~ ERROR: argument 2 is required to be a constant | ^^^^^^^^^ From 3abde0e3c688258a1766a40f58035f3af19aee81 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 5 Sep 2018 12:35:03 +0200 Subject: [PATCH 18/28] Don't autopromote const fns without arguments --- src/libcore/mem.rs | 2 ++ src/libcore/num/mod.rs | 2 ++ src/libcore/ptr.rs | 2 ++ src/librustc/ty/constness.rs | 7 +------ 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 1803adee3c18e..f52e24eec55fa 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -286,6 +286,7 @@ pub fn forget(t: T) { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(not(stage0))] +#[rustc_promotable] pub const fn size_of() -> usize { intrinsics::size_of::() } @@ -396,6 +397,7 @@ pub fn min_align_of_val(val: &T) -> usize { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(not(stage0))] +#[rustc_promotable] pub const fn align_of() -> usize { intrinsics::min_align_of::() } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 31952e9e49d38..d987641ac29d1 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -207,6 +207,7 @@ $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn min_value() -> Self { !0 ^ ((!0 as $UnsignedT) >> 1) as Self } @@ -225,6 +226,7 @@ $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn max_value() -> Self { !Self::min_value() } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 77eccb5cd249c..a16961032ce91 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -74,6 +74,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(stage0), rustc_promotable)] pub const fn null() -> *const T { 0 as *const T } /// Creates a null mutable raw pointer. @@ -88,6 +89,7 @@ pub const fn null() -> *const T { 0 as *const T } /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(stage0), rustc_promotable)] pub const fn null_mut() -> *mut T { 0 as *mut T } /// Swaps the values at two mutable locations of the same type, without diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index cbde0995eb6f9..0b89355a1404b 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -87,12 +87,7 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { fn is_promotable_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) { Some(stab) => stab.promotable, - // const fns without the promotable attribute may still be promoted if they have no - // arguments, as in that case they are semantically equivalent to constants. - // also only promote such const fns if they are defined in the standard library - None => { - tcx.fn_sig(def_id).skip_binder().inputs().is_empty() && tcx.features().staged_api - }, + None => false, } } From 6eced551456a927ce53b7ba6233e1c7108123045 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 5 Sep 2018 12:35:11 +0200 Subject: [PATCH 19/28] Indent fix --- src/librustc_passes/rvalue_promotion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index e20afa2ab09d8..292c0e8daf79b 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -165,7 +165,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { Promotable } else { NotPromotable - } + } } /// While the `ExprUseVisitor` walks, we will identify which From 0765eb1836d8a35f91aff4198c945f2e55675848 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 5 Sep 2018 13:38:53 +0200 Subject: [PATCH 20/28] Add a test for `rustc_promotable` --- src/test/run-pass/invalid_const_promotion.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/run-pass/invalid_const_promotion.rs b/src/test/run-pass/invalid_const_promotion.rs index 10b868bf5aa99..f90729ecc3aa1 100644 --- a/src/test/run-pass/invalid_const_promotion.rs +++ b/src/test/run-pass/invalid_const_promotion.rs @@ -14,7 +14,7 @@ // compile-flags: -C debug_assertions=yes #![stable(feature = "rustc", since = "1.0.0")] -#![feature(const_fn, libc, staged_api)] +#![feature(const_fn, libc, staged_api, rustc_attrs)] #![allow(const_err)] extern crate libc; @@ -23,6 +23,8 @@ use std::env; use std::process::{Command, Stdio}; // this will panic in debug mode and overflow in release mode +#[stable(feature = "rustc", since = "1.0.0")] +#[rustc_promotable] const fn bar() -> usize { 0 - 1 } fn foo() { From 408f307f0ea40d0ee0fb189c34280ee3b921543b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 5 Sep 2018 16:24:33 +0200 Subject: [PATCH 21/28] Do not promote calls to `NonZero*::new_unchecked` --- src/libcore/num/mod.rs | 1 - src/libcore/ptr.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index d987641ac29d1..b7e93490cf3b5 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -69,7 +69,6 @@ assert_eq!(size_of::>(), size_of::<", st /// The value must not be zero. #[stable(feature = "nonzero", since = "1.28.0")] #[inline] - #[cfg_attr(not(stage0), rustc_promotable)] pub const unsafe fn new_unchecked(n: $Int) -> Self { $Ty(NonZero(n)) } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index a16961032ce91..6bf0b3e4182b9 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2867,7 +2867,6 @@ impl NonNull { /// /// `ptr` must be non-null. #[stable(feature = "nonnull", since = "1.25.0")] - #[cfg_attr(not(stage0), rustc_promotable)] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { NonNull { pointer: NonZero(ptr as _) } } From 9da9ca5ae921168b9d8e47827e79d026a101c6b2 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 6 Sep 2018 09:43:23 +0200 Subject: [PATCH 22/28] Assert that no unsafe function is treated as promotable --- src/librustc/ty/constness.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index 0b89355a1404b..9f7fb7e044ea8 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -86,7 +86,18 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { fn is_promotable_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) { - Some(stab) => stab.promotable, + Some(stab) => { + if cfg!(debug_assertions) && stab.promotable { + let sig = tcx.fn_sig(def_id); + assert_eq!( + sig.unsafety(), + hir::Unsafety::Normal, + "don't mark const unsafe fns as promotable", + // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682 + ); + } + stab.promotable + }, None => false, } } From e0e7cf303ba2fd63763e6d99a9d67dced1fac8ab Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 6 Sep 2018 13:29:45 +0300 Subject: [PATCH 23/28] rustc_resolve: only prepend CrateRoot to a non-keyword segment. --- src/librustc_resolve/build_reduced_graph.rs | 78 +++++++++---------- .../crate-path-absolute.rs | 14 +++- 2 files changed, 49 insertions(+), 43 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 37868a83e3421..92a9057d96ebc 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -120,26 +120,48 @@ impl<'a, 'cl> Resolver<'a, 'cl> { use_tree: &ast::UseTree, id: NodeId, vis: ty::Visibility, - prefix: &ast::Path, + parent_prefix: &[Ident], mut uniform_paths_canary_emitted: bool, nested: bool, item: &Item, expansion: Mark, ) { - debug!("build_reduced_graph_for_use_tree(prefix={:?}, \ + debug!("build_reduced_graph_for_use_tree(parent_prefix={:?}, \ uniform_paths_canary_emitted={}, \ use_tree={:?}, nested={})", - prefix, uniform_paths_canary_emitted, use_tree, nested); + parent_prefix, uniform_paths_canary_emitted, use_tree, nested); let is_prelude = attr::contains_name(&item.attrs, "prelude_import"); - let path = &use_tree.prefix; + let uniform_paths = + self.session.rust_2018() && + self.session.features_untracked().uniform_paths; + + let prefix_iter = || parent_prefix.iter().cloned() + .chain(use_tree.prefix.segments.iter().map(|seg| seg.ident)); + let prefix_start = prefix_iter().nth(0); + let starts_with_non_keyword = prefix_start.map_or(false, |ident| { + !ident.is_path_segment_keyword() + }); + + // Imports are resolved as global by default, prepend `CrateRoot`, + // unless `#![feature(uniform_paths)]` is enabled. + let inject_crate_root = + !uniform_paths && + match use_tree.kind { + // HACK(eddyb) special-case `use *` to mean `use ::*`. + ast::UseTreeKind::Glob if prefix_start.is_none() => true, + _ => starts_with_non_keyword, + }; + let root = if inject_crate_root { + let span = use_tree.prefix.span.shrink_to_lo(); + Some(Ident::new(keywords::CrateRoot.name(), span)) + } else { + None + }; - let mut module_path: Vec<_> = prefix.segments.iter() - .chain(path.segments.iter()) - .map(|seg| seg.ident) - .collect(); + let prefix: Vec<_> = root.into_iter().chain(prefix_iter()).collect(); - debug!("build_reduced_graph_for_use_tree: module_path={:?}", module_path); + debug!("build_reduced_graph_for_use_tree: prefix={:?}", prefix); // `#[feature(uniform_paths)]` allows an unqualified import path, // e.g. `use x::...;` to resolve not just globally (`use ::x::...;`) @@ -172,15 +194,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> { // ergonomically unacceptable. let emit_uniform_paths_canary = !uniform_paths_canary_emitted && - module_path.get(0).map_or(false, |ident| { - !ident.is_path_segment_keyword() - }); + uniform_paths && + starts_with_non_keyword; if emit_uniform_paths_canary { - // Relative paths should only get here if the feature-gate is on. - assert!(self.session.rust_2018() && - self.session.features_untracked().uniform_paths); - - let source = module_path[0]; + let source = prefix_start.unwrap(); // HACK(eddyb) For `use x::{self, ...};`, use the ID of the // `self` nested import for the canary. This allows the @@ -256,6 +273,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { match use_tree.kind { ast::UseTreeKind::Simple(rename, ..) => { let mut ident = use_tree.ident(); + let mut module_path = prefix; let mut source = module_path.pop().unwrap(); let mut type_ns_only = false; @@ -354,7 +372,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { max_vis: Cell::new(ty::Visibility::Invisible), }; self.add_import_directive( - module_path, + prefix, subclass, use_tree.span, id, @@ -366,13 +384,6 @@ impl<'a, 'cl> Resolver<'a, 'cl> { ); } ast::UseTreeKind::Nested(ref items) => { - let prefix = ast::Path { - segments: module_path.into_iter() - .map(|ident| ast::PathSegment::from_ident(ident)) - .collect(), - span: path.span, - }; - // Ensure there is at most one `self` in the list let self_spans = items.iter().filter_map(|&(ref use_tree, _)| { if let ast::UseTreeKind::Simple(..) = use_tree.kind { @@ -422,28 +433,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> { match item.node { ItemKind::Use(ref use_tree) => { - let uniform_paths = - self.session.rust_2018() && - self.session.features_untracked().uniform_paths; - // Imports are resolved as global by default, add starting root segment. - let root = if !uniform_paths { - use_tree.prefix.make_root() - } else { - // Except when `#![feature(uniform_paths)]` is on. - None - }; - let prefix = ast::Path { - segments: root.into_iter().collect(), - span: use_tree.span, - }; - self.build_reduced_graph_for_use_tree( use_tree, item.id, use_tree, item.id, vis, - &prefix, + &[], false, // uniform_paths_canary_emitted false, item, diff --git a/src/test/ui/run-pass/rfcs/rfc-2126-crate-paths/crate-path-absolute.rs b/src/test/ui/run-pass/rfcs/rfc-2126-crate-paths/crate-path-absolute.rs index e44ab838cafa0..71904acae724d 100644 --- a/src/test/ui/run-pass/rfcs/rfc-2126-crate-paths/crate-path-absolute.rs +++ b/src/test/ui/run-pass/rfcs/rfc-2126-crate-paths/crate-path-absolute.rs @@ -23,8 +23,7 @@ mod m { pub(in crate::m) struct S; } -mod n -{ +mod n { use crate::m::f; use crate as root; pub fn check() { @@ -34,9 +33,20 @@ mod n } } +mod p { + use {super::f, crate::m::g, self::root::m::h}; + use crate as root; + pub fn check() { + assert_eq!(f(), 1); + assert_eq!(g(), 2); + assert_eq!(h(), 3); + } +} + fn main() { assert_eq!(f(), 1); assert_eq!(crate::m::g(), 2); assert_eq!(root::m::h(), 3); n::check(); + p::check(); } From 449516f036ea2b2bb7500ecc5998d5edff0bcd02 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 6 Sep 2018 22:45:26 +0300 Subject: [PATCH 24/28] rustc_resolve: inject `uniform_paths` canary always on Rust 2018. --- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/resolve_imports.rs | 24 +++++++++++--- .../ambiguity-macros-nested.rs | 29 +++++++++++++++++ .../ambiguity-macros-nested.stderr | 16 ++++++++++ .../ambiguity-macros.rs | 27 ++++++++++++++++ .../ambiguity-macros.stderr | 16 ++++++++++ .../ambiguity-nested.rs | 24 ++++++++++++++ .../ambiguity-nested.stderr | 16 ++++++++++ .../uniform-paths-forward-compat/ambiguity.rs | 20 ++++++++++++ .../ambiguity.stderr | 16 ++++++++++ .../block-scoped-shadow.rs | 21 +++++++++++++ .../block-scoped-shadow.stderr | 31 +++++++++++++++++++ 12 files changed, 236 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.rs create mode 100644 src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.stderr create mode 100644 src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.rs create mode 100644 src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.stderr create mode 100644 src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.rs create mode 100644 src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.stderr create mode 100644 src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.rs create mode 100644 src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.stderr create mode 100644 src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs create mode 100644 src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 92a9057d96ebc..a1e602efd0d5b 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -194,7 +194,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { // ergonomically unacceptable. let emit_uniform_paths_canary = !uniform_paths_canary_emitted && - uniform_paths && + self.session.rust_2018() && starts_with_non_keyword; if emit_uniform_paths_canary { let source = prefix_start.unwrap(); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 73c9af0d11c47..994ed39d6e639 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -708,6 +708,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { } } + let uniform_paths_feature = self.session.features_untracked().uniform_paths; for ((span, _), (name, results)) in uniform_paths_canaries { self.per_ns(|this, ns| { let results = &results[ns]; @@ -739,15 +740,24 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { suggestion_choices.push_str(" or "); } write!(suggestion_choices, "`self::{}`", name); - err.span_label(span, - format!("can refer to `self::{}`", name)); + if uniform_paths_feature { + err.span_label(span, + format!("can refer to `self::{}`", name)); + } else { + err.span_label(span, + format!("may refer to `self::{}` in the future", name)); + } } for &span in &results.block_scopes { err.span_label(span, format!("shadowed by block-scoped `{}`", name)); } err.help(&format!("write {} explicitly instead", suggestion_choices)); - err.note("relative `use` paths enabled by `#![feature(uniform_paths)]`"); + if uniform_paths_feature { + err.note("relative `use` paths enabled by `#![feature(uniform_paths)]`"); + } else { + err.note("in the future, `#![feature(uniform_paths)]` may become the default"); + } err.emit(); }); } @@ -933,11 +943,15 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { _ => unreachable!(), }; + // Do not record uses from canaries, to avoid interfering with other + // diagnostics or suggestions that rely on some items not being used. + let record_used = !directive.is_uniform_paths_canary; + let mut all_ns_err = true; self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { if let Ok(binding) = result[ns].get() { all_ns_err = false; - if this.record_use(ident, ns, binding, directive.span) { + if record_used && this.record_use(ident, ns, binding, directive.span) { if let ModuleOrUniformRoot::Module(module) = module { this.resolution(module, ident, ns).borrow_mut().binding = Some(this.dummy_binding); @@ -949,7 +963,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { if all_ns_err { let mut all_ns_failed = true; self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { - match this.resolve_ident_in_module(module, ident, ns, true, span) { + match this.resolve_ident_in_module(module, ident, ns, record_used, span) { Ok(_) => all_ns_failed = false, _ => {} } diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.rs new file mode 100644 index 0000000000000..590e83b07819a --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.rs @@ -0,0 +1,29 @@ +// 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. + +// edition:2018 + +// This test is similar to `ambiguity-macros.rs`, but nested in a module. + +mod foo { + pub use std::io; + //~^ ERROR `std` import is ambiguous + + macro_rules! m { + () => { + mod std { + pub struct io; + } + } + } + m!(); +} + +fn main() {} diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.stderr new file mode 100644 index 0000000000000..948043cff7614 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.stderr @@ -0,0 +1,16 @@ +error: `std` import is ambiguous + --> $DIR/ambiguity-macros-nested.rs:16:13 + | +LL | pub use std::io; + | ^^^ can refer to external crate `::std` +... +LL | / mod std { +LL | | pub struct io; +LL | | } + | |_____________- may refer to `self::std` in the future + | + = help: write `::std` or `self::std` explicitly instead + = note: in the future, `#![feature(uniform_paths)]` may become the default + +error: aborting due to previous error + diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.rs new file mode 100644 index 0000000000000..861efba14f80c --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.rs @@ -0,0 +1,27 @@ +// 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. + +// edition:2018 + +// This test is similar to `ambiguity.rs`, but with macros defining local items. + +use std::io; +//~^ ERROR `std` import is ambiguous + +macro_rules! m { + () => { + mod std { + pub struct io; + } + } +} +m!(); + +fn main() {} diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.stderr new file mode 100644 index 0000000000000..40cceea2440b9 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.stderr @@ -0,0 +1,16 @@ +error: `std` import is ambiguous + --> $DIR/ambiguity-macros.rs:15:5 + | +LL | use std::io; + | ^^^ can refer to external crate `::std` +... +LL | / mod std { +LL | | pub struct io; +LL | | } + | |_________- may refer to `self::std` in the future + | + = help: write `::std` or `self::std` explicitly instead + = note: in the future, `#![feature(uniform_paths)]` may become the default + +error: aborting due to previous error + diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.rs new file mode 100644 index 0000000000000..a69eb101917fa --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.rs @@ -0,0 +1,24 @@ +// 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. + +// edition:2018 + +// This test is similar to `ambiguity.rs`, but nested in a module. + +mod foo { + pub use std::io; + //~^ ERROR `std` import is ambiguous + + mod std { + pub struct io; + } +} + +fn main() {} diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.stderr new file mode 100644 index 0000000000000..7538d3d2d917a --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.stderr @@ -0,0 +1,16 @@ +error: `std` import is ambiguous + --> $DIR/ambiguity-nested.rs:16:13 + | +LL | pub use std::io; + | ^^^ can refer to external crate `::std` +... +LL | / mod std { +LL | | pub struct io; +LL | | } + | |_____- may refer to `self::std` in the future + | + = help: write `::std` or `self::std` explicitly instead + = note: in the future, `#![feature(uniform_paths)]` may become the default + +error: aborting due to previous error + diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.rs new file mode 100644 index 0000000000000..500e9f6c63ff8 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.rs @@ -0,0 +1,20 @@ +// 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. + +// edition:2018 + +use std::io; +//~^ ERROR `std` import is ambiguous + +mod std { + pub struct io; +} + +fn main() {} diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.stderr new file mode 100644 index 0000000000000..7b64b8f02464a --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.stderr @@ -0,0 +1,16 @@ +error: `std` import is ambiguous + --> $DIR/ambiguity.rs:13:5 + | +LL | use std::io; + | ^^^ can refer to external crate `::std` +... +LL | / mod std { +LL | | pub struct io; +LL | | } + | |_- may refer to `self::std` in the future + | + = help: write `::std` or `self::std` explicitly instead + = note: in the future, `#![feature(uniform_paths)]` may become the default + +error: aborting due to previous error + diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs new file mode 100644 index 0000000000000..ca488fec5162d --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs @@ -0,0 +1,21 @@ +// 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. + +// edition:2018 + +struct std; + +fn main() { + fn std() {} + enum std {} + use std as foo; + //~^ ERROR `std` import is ambiguous + //~| ERROR `std` import is ambiguous +} diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr new file mode 100644 index 0000000000000..27e0e88369127 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr @@ -0,0 +1,31 @@ +error: `std` import is ambiguous + --> $DIR/block-scoped-shadow.rs:18:9 + | +LL | struct std; + | ----------- may refer to `self::std` in the future +... +LL | enum std {} + | ----------- shadowed by block-scoped `std` +LL | use std as foo; + | ^^^ can refer to external crate `::std` + | + = help: write `::std` or `self::std` explicitly instead + = note: in the future, `#![feature(uniform_paths)]` may become the default + +error: `std` import is ambiguous + --> $DIR/block-scoped-shadow.rs:18:9 + | +LL | struct std; + | ----------- may refer to `self::std` in the future +... +LL | fn std() {} + | ----------- shadowed by block-scoped `std` +LL | enum std {} +LL | use std as foo; + | ^^^ + | + = help: write `self::std` explicitly instead + = note: in the future, `#![feature(uniform_paths)]` may become the default + +error: aborting due to 2 previous errors + From e942e0eae35b172567a615beb241c3159195dbb3 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 6 Sep 2018 10:20:01 -0600 Subject: [PATCH 25/28] Stabilize the 2018 edition --- src/doc/rustdoc/src/command-line-arguments.md | 14 ++++++++++++++ src/doc/rustdoc/src/unstable-features.md | 13 ------------- src/librustdoc/lib.rs | 2 +- src/libsyntax_pos/edition.rs | 2 +- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index 417608cc5ca0a..aba485f752ab2 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -345,3 +345,17 @@ $ rustdoc src/lib.rs --sysroot /path/to/sysroot Similar to `rustc --sysroot`, this lets you change the sysroot `rustdoc` uses when compiling your code. + +### `--edition`: control the edition of docs and doctests + +Using this flag looks like this: + +```bash +$ rustdoc src/lib.rs --edition 2018 +$ rustdoc --test src/lib.rs --edition 2018 +``` + +This flag allows rustdoc to treat your rust code as the given edition. It will compile doctests with +the given edition as well. As with `rustc`, the default edition that `rustdoc` will use is `2015` +(the first edition). + diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 32fb8c2f7d58e..071575b1fc094 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -346,19 +346,6 @@ details. [issue-display-warnings]: https://github.com/rust-lang/rust/issues/41574 -### `--edition`: control the edition of docs and doctests - -Using this flag looks like this: - -```bash -$ rustdoc src/lib.rs -Z unstable-options --edition 2018 -$ rustdoc --test src/lib.rs -Z unstable-options --edition 2018 -``` - -This flag allows rustdoc to treat your rust code as the given edition. It will compile doctests with -the given edition as well. As with `rustc`, the default edition that `rustdoc` will use is `2015` -(the first edition). - ### `--extern-html-root-url`: control how rustdoc links to non-local crates Using this flag looks like this: diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 1acae86f0068f..3211607807ff3 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -286,7 +286,7 @@ fn opts() -> Vec { \"light-suffix.css\"", "PATH") }), - unstable("edition", |o| { + stable("edition", |o| { o.optopt("", "edition", "edition to use when compiling rust code (default: 2015)", "EDITION") diff --git a/src/libsyntax_pos/edition.rs b/src/libsyntax_pos/edition.rs index fce8fc3db4e4e..7709db72a02fb 100644 --- a/src/libsyntax_pos/edition.rs +++ b/src/libsyntax_pos/edition.rs @@ -65,7 +65,7 @@ impl Edition { pub fn is_stable(&self) -> bool { match *self { Edition::Edition2015 => true, - Edition::Edition2018 => false, + Edition::Edition2018 => true, } } } From a0330f5b5b4f77d4c83db8d729dfd92b17e487bb Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 6 Sep 2018 10:47:41 -0600 Subject: [PATCH 26/28] Remove crate_visibility_modifier from 2018 edition --- src/libsyntax/feature_gate.rs | 2 +- src/test/ui-fulldeps/unnecessary-extern-crate.rs | 2 +- src/test/ui/crate-in-paths.rs | 2 +- src/test/ui/rust-2018/edition-lint-fully-qualified-paths.fixed | 2 +- src/test/ui/rust-2018/edition-lint-fully-qualified-paths.rs | 2 +- src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed | 2 +- src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs | 2 +- src/test/ui/rust-2018/edition-lint-nested-paths.fixed | 2 +- src/test/ui/rust-2018/edition-lint-nested-paths.rs | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 0270e36db1177..9a9fb05529291 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -389,7 +389,7 @@ declare_features! ( (active, non_exhaustive, "1.22.0", Some(44109), None), // `crate` as visibility modifier, synonymous to `pub(crate)` - (active, crate_visibility_modifier, "1.23.0", Some(45388), Some(Edition::Edition2018)), + (active, crate_visibility_modifier, "1.23.0", Some(45388), None), // extern types (active, extern_types, "1.23.0", Some(43467), None), diff --git a/src/test/ui-fulldeps/unnecessary-extern-crate.rs b/src/test/ui-fulldeps/unnecessary-extern-crate.rs index ea3e0587958b1..df723ddf590c4 100644 --- a/src/test/ui-fulldeps/unnecessary-extern-crate.rs +++ b/src/test/ui-fulldeps/unnecessary-extern-crate.rs @@ -11,7 +11,7 @@ // edition:2018 #![deny(unused_extern_crates)] -#![feature(alloc, test, libc)] +#![feature(alloc, test, libc, crate_visibility_modifier)] extern crate alloc; //~^ ERROR unused extern crate diff --git a/src/test/ui/crate-in-paths.rs b/src/test/ui/crate-in-paths.rs index ef01294f941aa..cbf60b6b6a696 100644 --- a/src/test/ui/crate-in-paths.rs +++ b/src/test/ui/crate-in-paths.rs @@ -10,7 +10,7 @@ // edition:2018 -#![feature(edition_2018_preview)] +#![feature(crate_visibility_modifier)] mod bar { crate struct Foo; diff --git a/src/test/ui/rust-2018/edition-lint-fully-qualified-paths.fixed b/src/test/ui/rust-2018/edition-lint-fully-qualified-paths.fixed index 279d4e9a80622..211d2b726de1a 100644 --- a/src/test/ui/rust-2018/edition-lint-fully-qualified-paths.fixed +++ b/src/test/ui/rust-2018/edition-lint-fully-qualified-paths.fixed @@ -10,7 +10,7 @@ // run-rustfix -#![feature(rust_2018_preview)] +#![feature(rust_2018_preview, crate_visibility_modifier)] #![deny(absolute_paths_not_starting_with_crate)] mod foo { diff --git a/src/test/ui/rust-2018/edition-lint-fully-qualified-paths.rs b/src/test/ui/rust-2018/edition-lint-fully-qualified-paths.rs index ff290555a695c..90b5a7f816226 100644 --- a/src/test/ui/rust-2018/edition-lint-fully-qualified-paths.rs +++ b/src/test/ui/rust-2018/edition-lint-fully-qualified-paths.rs @@ -10,7 +10,7 @@ // run-rustfix -#![feature(rust_2018_preview)] +#![feature(rust_2018_preview, crate_visibility_modifier)] #![deny(absolute_paths_not_starting_with_crate)] mod foo { diff --git a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed index 929b7cd061b3e..94803a117dc54 100644 --- a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed +++ b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed @@ -10,7 +10,7 @@ // run-rustfix -#![feature(rust_2018_preview)] +#![feature(rust_2018_preview, crate_visibility_modifier)] #![deny(absolute_paths_not_starting_with_crate)] #![allow(unused_imports)] #![allow(dead_code)] diff --git a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs index b5693c4bb93ad..7f68eeff438cd 100644 --- a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs +++ b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs @@ -10,7 +10,7 @@ // run-rustfix -#![feature(rust_2018_preview)] +#![feature(rust_2018_preview, crate_visibility_modifier)] #![deny(absolute_paths_not_starting_with_crate)] #![allow(unused_imports)] #![allow(dead_code)] diff --git a/src/test/ui/rust-2018/edition-lint-nested-paths.fixed b/src/test/ui/rust-2018/edition-lint-nested-paths.fixed index 06f6b6d75a700..ee54229bfb240 100644 --- a/src/test/ui/rust-2018/edition-lint-nested-paths.fixed +++ b/src/test/ui/rust-2018/edition-lint-nested-paths.fixed @@ -10,7 +10,7 @@ // run-rustfix -#![feature(rust_2018_preview)] +#![feature(rust_2018_preview, crate_visibility_modifier)] #![deny(absolute_paths_not_starting_with_crate)] use crate::foo::{a, b}; diff --git a/src/test/ui/rust-2018/edition-lint-nested-paths.rs b/src/test/ui/rust-2018/edition-lint-nested-paths.rs index c2831ec04b797..9a42f5f28c821 100644 --- a/src/test/ui/rust-2018/edition-lint-nested-paths.rs +++ b/src/test/ui/rust-2018/edition-lint-nested-paths.rs @@ -10,7 +10,7 @@ // run-rustfix -#![feature(rust_2018_preview)] +#![feature(rust_2018_preview, crate_visibility_modifier)] #![deny(absolute_paths_not_starting_with_crate)] use foo::{a, b}; From 0ec351d528f95298afc399a3ac65f794394d6c58 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 8 Sep 2018 20:00:57 +0300 Subject: [PATCH 27/28] `&CStr`, not `CStr`, is the counterpart of `&str` --- src/libstd/ffi/c_str.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 2b87094926cf5..372f3e83e3dcd 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -33,7 +33,7 @@ use sys; /// type is a static guarantee that the underlying bytes contain no interior 0 /// bytes ("nul characters") and that the final byte is 0 ("nul terminator"). /// -/// `CString` is to [`CStr`] as [`String`] is to [`&str`]: the former +/// `CString` is to [`&CStr`] as [`String`] is to [`&str`]: the former /// in each pair are owned strings; the latter are borrowed /// references. /// @@ -88,6 +88,7 @@ use sys; /// [slice.len]: ../primitive.slice.html#method.len /// [`Deref`]: ../ops/trait.Deref.html /// [`CStr`]: struct.CStr.html +/// [`&CStr`]: struct.CStr.html /// /// # Examples /// @@ -137,7 +138,7 @@ pub struct CString { /// converted to a Rust [`&str`] by performing UTF-8 validation, or /// into an owned [`CString`]. /// -/// `CStr` is to [`CString`] as [`&str`] is to [`String`]: the former +/// `&CStr` is to [`CString`] as [`&str`] is to [`String`]: the former /// in each pair are borrowed references; the latter are owned /// strings. /// From 3e56dece47ce2ba67614cf1408f669da1e292961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 8 Sep 2018 14:06:40 +0200 Subject: [PATCH 28/28] submodules: update clippy, rls with crate visibility patches --- src/tools/clippy | 2 +- src/tools/rls | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/clippy b/src/tools/clippy index cafef7b576203..fdd830f52c082 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit cafef7b576203f166add9ed143979d9775c25219 +Subproject commit fdd830f52c082b83db0dac3e0066c0cf114050d2 diff --git a/src/tools/rls b/src/tools/rls index cf6358a00540a..5b5cd9d457194 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit cf6358a00540a83dcc6e8c243f3306ccdbb9c354 +Subproject commit 5b5cd9d45719414196e254ec17baa598acc8cd25