From b66eb696af9ef1952f2582b2b8ec07156868b2f6 Mon Sep 17 00:00:00 2001 From: Yenlin Chen <3822365+hencrice@users.noreply.github.com> Date: Sun, 13 Dec 2020 04:14:08 +0000 Subject: [PATCH 01/22] Refactored verbose print into a function Also handle Tuple and Array separately, which was not explicitly checked. Fixes #79799. --- compiler/rustc_mir/src/util/pretty.rs | 44 ++++++++++++++++++++------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index cd60602b088f2..9b81629400a66 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -17,7 +17,8 @@ use rustc_middle::mir::interpret::{ }; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor}; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor}; use rustc_target::abi::Size; use std::ops::ControlFlow; @@ -408,6 +409,33 @@ impl ExtraComments<'tcx> { } } +fn use_verbose(ty: &&TyS<'tcx>) -> bool { + match ty.kind() { + ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false, + // Unit type + ty::Tuple(g_args) if g_args.is_empty() => false, + ty::Tuple(g_args) => { + // could have used `try_fold` here but it seems a bit silly that + // the accumulator is useless + let mut should_be_verbose = false; + for g_arg in g_args.iter() { + if match g_arg.unpack() { + GenericArgKind::Type(ty) => use_verbose(&ty), + GenericArgKind::Const(ty::Const { ty, val: _ }) => use_verbose(ty), + _ => false, + } { + should_be_verbose = true; + break; + } + } + should_be_verbose + } + ty::Array(ty, _) => use_verbose(ty), + ty::FnDef(..) => false, + _ => true, + } +} + impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); @@ -430,16 +458,10 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { self.super_const(constant); let ty::Const { ty, val, .. } = constant; - match ty.kind() { - ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => {} - // Unit type - ty::Tuple(tys) if tys.is_empty() => {} - ty::FnDef(..) => {} - _ => { - self.push("ty::Const"); - self.push(&format!("+ ty: {:?}", ty)); - self.push(&format!("+ val: {:?}", val)); - } + if use_verbose(ty) { + self.push("ty::Const"); + self.push(&format!("+ ty: {:?}", ty)); + self.push(&format!("+ val: {:?}", val)); } } From 830ceaa41908bd428e36b1a804dd93c9a257aea8 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Sun, 6 Dec 2020 13:57:37 +0100 Subject: [PATCH 02/22] Remap instrument-coverage line numbers in doctests This uses the `SourceMap::doctest_offset_line` method to re-map line numbers from doctests. Remapping columns is not yet done. Part of issue #79417. --- .../rustc_mir/src/transform/coverage/mod.rs | 6 +- compiler/rustc_span/src/lib.rs | 2 +- src/librustdoc/doctest.rs | 75 +++++--- src/librustdoc/doctest/tests.rs | 69 +++++-- src/librustdoc/html/markdown.rs | 2 +- .../coverage-reports/Makefile | 22 ++- .../expected_show_coverage.doctest.txt | 79 ++++++++ .../expected_show_coverage.uses_crate.txt | 4 +- .../coverage-reports/normalize_paths.py | 10 + ...est.main.-------.InstrumentCoverage.0.html | 127 +++++++++++++ ...doctests.-------.InstrumentCoverage.0.html | 173 ++++++++++++++++++ .../coverage/compiletest-ignore-dir | 4 +- .../coverage/coverage_tools.mk | 4 +- .../run-make-fulldeps/coverage/doctest.rs | 66 +++++++ .../coverage/lib/doctest_crate.rs | 9 + 15 files changed, 596 insertions(+), 56 deletions(-) create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports/normalize_paths.py create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage/doctest.rs create mode 100644 src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index 4590d37c182e4..93133e9b7f063 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -30,6 +30,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; +use rustc_span::source_map::SourceMap; use rustc_span::{CharPos, Pos, SourceFile, Span, Symbol}; /// A simple error message wrapper for `coverage::Error`s. @@ -311,7 +312,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { self.mir_body, counter_kind, self.bcb_leader_bb(bcb), - Some(make_code_region(file_name, &self.source_file, span, body_span)), + Some(make_code_region(source_map, file_name, &self.source_file, span, body_span)), ); } } @@ -489,6 +490,7 @@ fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: Co /// Convert the Span into its file name, start line and column, and end line and column fn make_code_region( + source_map: &SourceMap, file_name: Symbol, source_file: &Lrc, span: Span, @@ -508,6 +510,8 @@ fn make_code_region( } else { source_file.lookup_file_pos(span.hi()) }; + let start_line = source_map.doctest_offset_line(&source_file.name, start_line); + let end_line = source_map.doctest_offset_line(&source_file.name, end_line); CodeRegion { file_name, start_line: start_line as u32, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f63a73acbf4ba..fbef4d06709ec 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -182,7 +182,7 @@ impl std::fmt::Display for FileName { use FileName::*; match *self { Real(RealFileName::Named(ref path)) => write!(fmt, "{}", path.display()), - // FIXME: might be nice to display both compoments of Devirtualized. + // FIXME: might be nice to display both components of Devirtualized. // But for now (to backport fix for issue #70924), best to not // perturb diagnostics so its obvious test suite still works. Real(RealFileName::Devirtualized { ref local_path, virtual_name: _ }) => { diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 37fe13c32ce74..a08ded926402f 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -247,9 +247,10 @@ fn run_test( edition: Edition, outdir: DirState, path: PathBuf, + test_id: &str, ) -> Result<(), TestFailure> { let (test, line_offset, supports_color) = - make_test(test, Some(cratename), as_test_harness, opts, edition); + make_test(test, Some(cratename), as_test_harness, opts, edition, Some(test_id)); let output_file = outdir.path().join("rust_out"); @@ -387,6 +388,7 @@ crate fn make_test( dont_insert_main: bool, opts: &TestOptions, edition: Edition, + test_id: Option<&str>, ) -> (String, usize, bool) { let (crate_attrs, everything_else, crates) = partition_source(s); let everything_else = everything_else.trim(); @@ -542,16 +544,40 @@ crate fn make_test( prog.push_str(everything_else); } else { let returns_result = everything_else.trim_end().ends_with("(())"); + // Give each doctest main function a unique name. + // This is for example needed for the tooling around `-Z instrument-coverage`. + let inner_fn_name = if let Some(test_id) = test_id { + format!("_doctest_main_{}", test_id) + } else { + "_inner".into() + }; let (main_pre, main_post) = if returns_result { ( - "fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> {", - "}\n_inner().unwrap() }", + format!( + "fn main() {{ fn {}() -> Result<(), impl core::fmt::Debug> {{\n", + inner_fn_name + ), + format!("\n}}; {}().unwrap() }}", inner_fn_name), + ) + } else if test_id.is_some() { + ( + format!("fn main() {{ fn {}() {{\n", inner_fn_name), + format!("\n}}; {}() }}", inner_fn_name), ) } else { - ("fn main() {\n", "\n}") + ("fn main() {\n".into(), "\n}".into()) }; - prog.extend([main_pre, everything_else, main_post].iter().cloned()); + // Note on newlines: We insert a line/newline *before*, and *after* + // the doctest and adjust the `line_offset` accordingly. + // In the case of `-Z instrument-coverage`, this means that the generated + // inner `main` function spans from the doctest opening codeblock to the + // closing one. For example + // /// ``` <- start of the inner main + // /// <- code under doctest + // /// ``` <- end of the inner main line_offset += 1; + + prog.extend([&main_pre, everything_else, &main_post].iter().cloned()); } debug!("final doctest:\n{}", prog); @@ -749,28 +775,24 @@ impl Tester for Collector { _ => PathBuf::from(r"doctest.rs"), }; + // For example `module/file.rs` would become `module_file_rs` + let file = filename + .to_string() + .chars() + .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' }) + .collect::(); + let test_id = format!( + "{file}_{line}_{number}", + file = file, + line = line, + number = { + // Increases the current test number, if this file already + // exists or it creates a new entry with a test number of 0. + self.visited_tests.entry((file.clone(), line)).and_modify(|v| *v += 1).or_insert(0) + }, + ); let outdir = if let Some(mut path) = options.persist_doctests.clone() { - // For example `module/file.rs` would become `module_file_rs` - let folder_name = filename - .to_string() - .chars() - .map(|c| if c == '\\' || c == '/' || c == '.' { '_' } else { c }) - .collect::(); - - path.push(format!( - "{krate}_{file}_{line}_{number}", - krate = cratename, - file = folder_name, - line = line, - number = { - // Increases the current test number, if this file already - // exists or it creates a new entry with a test number of 0. - self.visited_tests - .entry((folder_name.clone(), line)) - .and_modify(|v| *v += 1) - .or_insert(0) - }, - )); + path.push(&test_id); std::fs::create_dir_all(&path) .expect("Couldn't create directory for doctest executables"); @@ -817,6 +839,7 @@ impl Tester for Collector { edition, outdir, path, + &test_id, ); if let Err(err) = res { diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index a024e9c72a43e..7c0df673c1b9e 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -11,7 +11,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -26,7 +26,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -44,7 +44,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 3)); } @@ -61,7 +61,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -79,7 +79,7 @@ use std::*; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -98,7 +98,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -115,7 +115,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -134,7 +134,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 3)); // Adding more will also bump the returned line offset. @@ -147,7 +147,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 4)); } @@ -164,7 +164,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -180,7 +180,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 1)); } @@ -196,7 +196,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); } @@ -210,7 +210,7 @@ assert_eq!(2+2, 4);"; //Ceci n'est pas une `fn main` assert_eq!(2+2, 4);" .to_string(); - let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 1)); } @@ -224,7 +224,7 @@ fn make_test_display_warnings() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 1)); } @@ -242,7 +242,7 @@ assert_eq!(2+2, 4); }" .to_string(); - let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); let input = "extern crate hella_qwop; @@ -256,7 +256,7 @@ assert_eq!(asdf::foo, 4); }" .to_string(); - let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 3)); } @@ -274,6 +274,41 @@ test_wrapper! { }" .to_string(); - let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION); + let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 1)); } + +#[test] +fn make_test_returns_result() { + // creates an inner function and unwraps it + let opts = TestOptions::default(); + let input = "use std::io; +let mut input = String::new(); +io::stdin().read_line(&mut input)?; +Ok::<(), io:Error>(())"; + let expected = "#![allow(unused)] +fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> { +use std::io; +let mut input = String::new(); +io::stdin().read_line(&mut input)?; +Ok::<(), io:Error>(()) +}; _inner().unwrap() }" + .to_string(); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); + assert_eq!((output, len), (expected, 2)); +} + +#[test] +fn make_test_named_wrapper() { + // creates an inner function with a specific name + let opts = TestOptions::default(); + let input = "assert_eq!(2+2, 4);"; + let expected = "#![allow(unused)] +fn main() { fn _doctest_main_some_unique_name() { +assert_eq!(2+2, 4); +}; _doctest_main_some_unique_name() }" + .to_string(); + let (output, len, _) = + make_test(input, None, false, &opts, DEFAULT_EDITION, Some("some_unique_name")); + assert_eq!((output, len), (expected, 2)); +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 22096203d4ce6..f911a2ce3fc78 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -248,7 +248,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { .join("\n"); let krate = krate.as_ref().map(|s| &**s); let (test, _, _) = - doctest::make_test(&test, krate, false, &Default::default(), edition); + doctest::make_test(&test, krate, false, &Default::default(), edition, None); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; let edition_string = format!("&edition={}", edition); diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile index 5c24f909130c0..c4700b317efa0 100644 --- a/src/test/run-make-fulldeps/coverage-reports/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -98,7 +98,7 @@ endif # Run it in order to generate some profiling data, # with `LLVM_PROFILE_FILE=` environment variable set to # output the coverage stats for this run. - LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \ + LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \ $(call RUN,$@) || \ ( \ status=$$?; \ @@ -108,9 +108,16 @@ endif ) \ ) + # Run it through rustdoc as well to cover doctests + LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \ + $(RUSTDOC) --crate-name workaround_for_79771 --test $(SOURCEDIR)/$@.rs \ + $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/$@.rs && echo "--edition=2018" ) \ + -L "$(TMPDIR)" -Zinstrument-coverage \ + -Z unstable-options --persist-doctests=$(TMPDIR)/rustdoc-$@ + # Postprocess the profiling data so it can be used by the llvm-cov tool "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \ - "$(TMPDIR)"/$@.profraw \ + "$(TMPDIR)"/$@-*.profraw \ -o "$(TMPDIR)"/$@.profdata # Generate a coverage report using `llvm-cov show`. @@ -121,8 +128,15 @@ endif --show-line-counts-or-regions \ --instr-profile="$(TMPDIR)"/$@.profdata \ $(call BIN,"$(TMPDIR)"/$@) \ - > "$(TMPDIR)"/actual_show_coverage.$@.txt \ - 2> "$(TMPDIR)"/show_coverage_stderr.$@.txt || \ + $$( \ + for file in $(TMPDIR)/rustdoc-$@/*/rust_out; \ + do \ + [[ -x $$file ]] && printf "%s %s " -object $$file; \ + done \ + ) \ + 2> "$(TMPDIR)"/show_coverage_stderr.$@.txt \ + | "$(PYTHON)" $(BASEDIR)/normalize_paths.py \ + > "$(TMPDIR)"/actual_show_coverage.$@.txt || \ ( status=$$? ; \ >&2 cat "$(TMPDIR)"/show_coverage_stderr.$@.txt ; \ exit $$status \ diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt new file mode 100644 index 0000000000000..e1731c7223c5d --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt @@ -0,0 +1,79 @@ +../coverage/doctest.rs: + 1| |//! This test ensures that code from doctests is properly re-mapped. + 2| |//! See for more info. + 3| |//! + 4| |//! Just some random code: + 5| 1|//! ``` + 6| 1|//! if true { + 7| |//! // this is executed! + 8| 1|//! assert_eq!(1, 1); + 9| |//! } else { + 10| |//! // this is not! + 11| |//! assert_eq!(1, 2); + 12| |//! } + 13| 1|//! ``` + 14| |//! + 15| |//! doctest testing external code: + 16| |//! ``` + 17| 1|//! extern crate doctest_crate; + 18| 1|//! doctest_crate::fn_run_in_doctests(1); + 19| 1|//! ``` + 20| |//! + 21| |//! doctest returning a result: + 22| 1|//! ``` + 23| 1|//! #[derive(Debug)] + 24| 1|//! struct SomeError; + 25| 1|//! let mut res = Err(SomeError); + 26| 1|//! if res.is_ok() { + 27| 0|//! res?; + 28| 1|//! } else { + 29| 1|//! res = Ok(0); + 30| 1|//! } + 31| |//! // need to be explicit because rustdoc cant infer the return type + 32| 1|//! Ok::<(), SomeError>(()) + 33| 1|//! ``` + 34| |//! + 35| |//! doctest with custom main: + 36| |//! ``` + 37| |//! #[derive(Debug)] + 38| |//! struct SomeError; + 39| |//! + 40| |//! extern crate doctest_crate; + 41| |//! + 42| 1|//! fn doctest_main() -> Result<(), SomeError> { + 43| 1|//! doctest_crate::fn_run_in_doctests(2); + 44| 1|//! Ok(()) + 45| 1|//! } + 46| |//! + 47| |//! // this `main` is not shown as covered, as it clashes with all the other + 48| |//! // `main` functions that were automatically generated for doctests + 49| |//! fn main() -> Result<(), SomeError> { + 50| |//! doctest_main() + 51| |//! } + 52| |//! ``` + 53| | + 54| |/// doctest attached to fn testing external code: + 55| |/// ``` + 56| 1|/// extern crate doctest_crate; + 57| 1|/// doctest_crate::fn_run_in_doctests(3); + 58| 1|/// ``` + 59| |/// + 60| 1|fn main() { + 61| 1| if true { + 62| 1| assert_eq!(1, 1); + 63| | } else { + 64| | assert_eq!(1, 2); + 65| | } + 66| 1|} + +../coverage/lib/doctest_crate.rs: + 1| |/// A function run only from within doctests + 2| 3|pub fn fn_run_in_doctests(conditional: usize) { + 3| 3| match conditional { + 4| 1| 1 => assert_eq!(1, 1), // this is run, + 5| 1| 2 => assert_eq!(1, 1), // this, + 6| 1| 3 => assert_eq!(1, 1), // and this too + 7| 0| _ => assert_eq!(1, 2), // however this is not + 8| | } + 9| 3|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index e14e733fff6d4..4c03e950af029 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -19,12 +19,12 @@ 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 19| 2|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&str>: + | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | used_crate::used_only_from_bin_crate_generic_function::<&str>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py new file mode 100644 index 0000000000000..05fb412cdb635 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +import sys + +# Normalize file paths in output +for line in sys.stdin: + if line.startswith("..") and line.rstrip().endswith(".rs:"): + print(line.replace("\\", "/"), end='') + else: + print(line, end='') diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..8d074558aae20 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,127 @@ + + + + +doctest.main - Coverage Spans + + + +
@0⦊fn main() ⦉@0{ + if @0⦊true⦉@0 { + @5⦊@4,6,7,8,9⦊assert_eq!(1, 1);⦉@4,6,7,8,9⦉@5 + } else { + @11⦊@10,12,13,14,15⦊assert_eq!(1, 2);⦉@10,12,13,14,15⦉@11 + } +}@16⦊⦉@16
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..ae119d9ca9f2e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html @@ -0,0 +1,173 @@ + + + + +doctest_crate.fn_run_in_doctests - Coverage Spans + + + +
@0⦊pub fn fn_run_in_doctests(conditional: usize) ⦉@0{ + match @0⦊conditional⦉@0 { + 1 => @7⦊@6,8,9,10,11⦊assert_eq!(1, 1)⦉@6,8,9,10,11⦉@7, // this is run, + 2 => @14⦊@13,15,16,17,18⦊assert_eq!(1, 1)⦉@13,15,16,17,18⦉@14, // this, + 3 => @21⦊@20,22,23,24,25⦊assert_eq!(1, 1)⦉@20,22,23,24,25⦉@21, // and this too + _ => @27⦊@26,28,29,30,31⦊assert_eq!(1, 2)⦉@26,28,29,30,31⦉@27, // however this is not + } +}@32⦊⦉@32
+ + diff --git a/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir b/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir index abf8df8fdc9e6..d1824d189e382 100644 --- a/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir +++ b/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir @@ -1,3 +1,3 @@ -# Directory "instrument-coverage" supports the tests at prefix ../instrument-coverage-* +# Directory "coverage" supports the tests at prefix ../coverage-* -# Use ./x.py [options] test src/test/run-make-fulldeps/instrument-coverage to run all related tests. +# Use ./x.py [options] test src/test/run-make-fulldeps/coverage to run all related tests. diff --git a/src/test/run-make-fulldeps/coverage/coverage_tools.mk b/src/test/run-make-fulldeps/coverage/coverage_tools.mk index 7dc485cd94d66..4d340d4b1dadd 100644 --- a/src/test/run-make-fulldeps/coverage/coverage_tools.mk +++ b/src/test/run-make-fulldeps/coverage/coverage_tools.mk @@ -1,7 +1,7 @@ -# Common Makefile include for Rust `run-make-fulldeps/instrument-coverage-* tests. Include this +# Common Makefile include for Rust `run-make-fulldeps/coverage-* tests. Include this # file with the line: # -# -include ../instrument-coverage/coverage_tools.mk +# -include ../coverage/coverage_tools.mk -include ../tools.mk diff --git a/src/test/run-make-fulldeps/coverage/doctest.rs b/src/test/run-make-fulldeps/coverage/doctest.rs new file mode 100644 index 0000000000000..e41d669bf0c76 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/doctest.rs @@ -0,0 +1,66 @@ +//! This test ensures that code from doctests is properly re-mapped. +//! See for more info. +//! +//! Just some random code: +//! ``` +//! if true { +//! // this is executed! +//! assert_eq!(1, 1); +//! } else { +//! // this is not! +//! assert_eq!(1, 2); +//! } +//! ``` +//! +//! doctest testing external code: +//! ``` +//! extern crate doctest_crate; +//! doctest_crate::fn_run_in_doctests(1); +//! ``` +//! +//! doctest returning a result: +//! ``` +//! #[derive(Debug)] +//! struct SomeError; +//! let mut res = Err(SomeError); +//! if res.is_ok() { +//! res?; +//! } else { +//! res = Ok(0); +//! } +//! // need to be explicit because rustdoc cant infer the return type +//! Ok::<(), SomeError>(()) +//! ``` +//! +//! doctest with custom main: +//! ``` +//! #[derive(Debug)] +//! struct SomeError; +//! +//! extern crate doctest_crate; +//! +//! fn doctest_main() -> Result<(), SomeError> { +//! doctest_crate::fn_run_in_doctests(2); +//! Ok(()) +//! } +//! +//! // this `main` is not shown as covered, as it clashes with all the other +//! // `main` functions that were automatically generated for doctests +//! fn main() -> Result<(), SomeError> { +//! doctest_main() +//! } +//! ``` + +/// doctest attached to fn testing external code: +/// ``` +/// extern crate doctest_crate; +/// doctest_crate::fn_run_in_doctests(3); +/// ``` +/// +fn main() { + if true { + assert_eq!(1, 1); + } else { + assert_eq!(1, 2); + } +} diff --git a/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs b/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs new file mode 100644 index 0000000000000..c3210146d69b0 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs @@ -0,0 +1,9 @@ +/// A function run only from within doctests +pub fn fn_run_in_doctests(conditional: usize) { + match conditional { + 1 => assert_eq!(1, 1), // this is run, + 2 => assert_eq!(1, 1), // this, + 3 => assert_eq!(1, 1), // and this too + _ => assert_eq!(1, 2), // however this is not + } +} From f9fa3fe65f561001535b069ed1f55c202758588c Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Sun, 20 Dec 2020 10:00:32 +0100 Subject: [PATCH 03/22] add an attribute to inner doctest fn --- src/librustdoc/doctest.rs | 7 ++++--- src/librustdoc/doctest/tests.rs | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index a08ded926402f..7313c761eae8c 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -551,17 +551,18 @@ crate fn make_test( } else { "_inner".into() }; + let inner_attr = if test_id.is_some() { "#[allow(non_snake_case)] " } else { "" }; let (main_pre, main_post) = if returns_result { ( format!( - "fn main() {{ fn {}() -> Result<(), impl core::fmt::Debug> {{\n", - inner_fn_name + "fn main() {{ {}fn {}() -> Result<(), impl core::fmt::Debug> {{\n", + inner_attr, inner_fn_name ), format!("\n}}; {}().unwrap() }}", inner_fn_name), ) } else if test_id.is_some() { ( - format!("fn main() {{ fn {}() {{\n", inner_fn_name), + format!("fn main() {{ {}fn {}() {{\n", inner_attr, inner_fn_name), format!("\n}}; {}() }}", inner_fn_name), ) } else { diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index 7c0df673c1b9e..1aea85e99708a 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -304,11 +304,11 @@ fn make_test_named_wrapper() { let opts = TestOptions::default(); let input = "assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] -fn main() { fn _doctest_main_some_unique_name() { +fn main() { #[allow(non_snake_case)] fn _doctest_main__some_unique_name() { assert_eq!(2+2, 4); -}; _doctest_main_some_unique_name() }" +}; _doctest_main__some_unique_name() }" .to_string(); let (output, len, _) = - make_test(input, None, false, &opts, DEFAULT_EDITION, Some("some_unique_name")); + make_test(input, None, false, &opts, DEFAULT_EDITION, Some("_some_unique_name")); assert_eq!((output, len), (expected, 2)); } From 087101e285895b8bce94a16a90f7e7a3d938c3da Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 21 Dec 2020 12:05:10 +0100 Subject: [PATCH 04/22] make path normalization compatible with mac python2 --- src/test/run-make-fulldeps/coverage-reports/normalize_paths.py | 2 ++ 1 file changed, 2 insertions(+) mode change 100644 => 100755 src/test/run-make-fulldeps/coverage-reports/normalize_paths.py diff --git a/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py old mode 100644 new mode 100755 index 05fb412cdb635..e5777ad2512f1 --- a/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py +++ b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py @@ -1,5 +1,7 @@ #!/usr/bin/env python +from __future__ import print_function + import sys # Normalize file paths in output From a272d621bc7a2ca61d704fbe531dc532d49ab402 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Fri, 18 Dec 2020 17:32:26 +0100 Subject: [PATCH 05/22] Implemented a compiler diagnostic for move async mistake Ran the tidy check Following the diagnostic guide better Diagnostic generation is now relegated to its own function in the diagnostics module. Added tests Fixed the ui test --- compiler/rustc_parse/src/parser/diagnostics.rs | 18 ++++++++++++++++++ compiler/rustc_parse/src/parser/expr.rs | 18 ++++++++++++++---- ...ncorrect-move-async-order-issue-79694.fixed | 8 ++++++++ .../incorrect-move-async-order-issue-79694.rs | 8 ++++++++ ...correct-move-async-order-issue-79694.stderr | 13 +++++++++++++ 5 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.rs create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 350a372a684cc..98c7b9a63a55f 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1912,4 +1912,22 @@ impl<'a> Parser<'a> { *self = snapshot; Err(err) } + + /// Get the diagnostics for the cases where `move async` is found. + /// + /// `move_async_span` starts at the 'm' of the move keyword and ends with the 'c' of the async keyword + pub(super) fn incorrect_move_async_order_found( + &self, + move_async_span: Span, + ) -> DiagnosticBuilder<'a> { + let mut err = + self.struct_span_err(move_async_span, "the order of `move` and `async` is incorrect"); + err.span_suggestion_verbose( + move_async_span, + "try switching the order", + "async move".to_owned(), + Applicability::MaybeIncorrect, + ); + err + } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 93be478fc8c2c..7d0d4f30137ac 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1603,7 +1603,7 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::async_closure, span); } - let capture_clause = self.parse_capture_clause(); + let capture_clause = self.parse_capture_clause()?; let decl = self.parse_fn_block_decl()?; let decl_hi = self.prev_token.span; let body = match decl.output { @@ -1626,8 +1626,18 @@ impl<'a> Parser<'a> { } /// Parses an optional `move` prefix to a closure-like construct. - fn parse_capture_clause(&mut self) -> CaptureBy { - if self.eat_keyword(kw::Move) { CaptureBy::Value } else { CaptureBy::Ref } + fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> { + if self.eat_keyword(kw::Move) { + // Check for `move async` and recover + if self.check_keyword(kw::Async) { + let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo); + Err(self.incorrect_move_async_order_found(move_async_span)) + } else { + Ok(CaptureBy::Value) + } + } else { + Ok(CaptureBy::Ref) + } } /// Parses the `|arg, arg|` header of a closure. @@ -2018,7 +2028,7 @@ impl<'a> Parser<'a> { fn parse_async_block(&mut self, mut attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; self.expect_keyword(kw::Async)?; - let capture_clause = self.parse_capture_clause(); + let capture_clause = self.parse_capture_clause()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); let kind = ExprKind::Async(capture_clause, DUMMY_NODE_ID, body); diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed b/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed new file mode 100644 index 0000000000000..055800d23b6c6 --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed @@ -0,0 +1,8 @@ +// run-rustfix +// edition:2018 + +// Regression test for issue 79694 + +fn main() { + let _ = async move { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect +} diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs b/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs new file mode 100644 index 0000000000000..e8be16516d6d3 --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs @@ -0,0 +1,8 @@ +// run-rustfix +// edition:2018 + +// Regression test for issue 79694 + +fn main() { + let _ = move async { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect +} diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr b/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr new file mode 100644 index 0000000000000..2add9fb33c70e --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr @@ -0,0 +1,13 @@ +error: the order of `move` and `async` is incorrect + --> $DIR/incorrect-move-async-order-issue-79694.rs:7:13 + | +LL | let _ = move async { }; + | ^^^^^^^^^^ + | +help: try switching the order + | +LL | let _ = async move { }; + | ^^^^^^^^^^ + +error: aborting due to previous error + From aec3575aa7d6903fbff2140b37b65961836d47dc Mon Sep 17 00:00:00 2001 From: pierwill Date: Mon, 21 Dec 2020 14:17:53 -0800 Subject: [PATCH 06/22] Rename rustc_middle::lint::LintSource Rename rustc_middle::lint::LintSource to rustc_middle::lint::LintLevelSource. --- compiler/rustc_lint/src/levels.rs | 20 ++++++------ compiler/rustc_middle/src/lint.rs | 32 +++++++++---------- compiler/rustc_middle/src/ty/context.rs | 4 +-- .../passes/calculate_doc_coverage.rs | 4 +-- src/librustdoc/passes/doc_test_lints.rs | 4 +-- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 3e22eba15aaef..410bd06850e75 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -12,7 +12,7 @@ use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::map::Map; use rustc_middle::lint::LevelSource; use rustc_middle::lint::LintDiagnosticBuilder; -use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource}; +use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintLevelSource}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::{builtin, Level, Lint, LintId}; @@ -91,7 +91,7 @@ impl<'s> LintLevelsBuilder<'s> { }; for id in ids { self.check_gated_lint(id, DUMMY_SP); - let src = LintSource::CommandLine(lint_flag_val, orig_level); + let src = LintLevelSource::CommandLine(lint_flag_val, orig_level); specs.insert(id, (level, src)); } } @@ -128,19 +128,19 @@ impl<'s> LintLevelsBuilder<'s> { ); diag_builder.span_label(src.span(), "overruled by previous forbid"); match old_src { - LintSource::Default => { + LintLevelSource::Default => { diag_builder.note(&format!( "`forbid` lint level is the default for {}", id.to_string() )); } - LintSource::Node(_, forbid_source_span, reason) => { + LintLevelSource::Node(_, forbid_source_span, reason) => { diag_builder.span_label(forbid_source_span, "`forbid` level set here"); if let Some(rationale) = reason { diag_builder.note(&rationale.as_str()); } } - LintSource::CommandLine(_, _) => { + LintLevelSource::CommandLine(_, _) => { diag_builder.note("`forbid` lint level was set on command line"); } } @@ -276,7 +276,7 @@ impl<'s> LintLevelsBuilder<'s> { let name = meta_item.path.segments.last().expect("empty lint name").ident.name; match store.check_lint_name(&name.as_str(), tool_name) { CheckLintNameResult::Ok(ids) => { - let src = LintSource::Node(name, li.span(), reason); + let src = LintLevelSource::Node(name, li.span(), reason); for &id in ids { self.check_gated_lint(id, attr.span); self.insert_spec(&mut specs, id, (level, src)); @@ -287,7 +287,7 @@ impl<'s> LintLevelsBuilder<'s> { match result { Ok(ids) => { let complete_name = &format!("{}::{}", tool_name.unwrap(), name); - let src = LintSource::Node( + let src = LintLevelSource::Node( Symbol::intern(complete_name), li.span(), reason, @@ -324,7 +324,7 @@ impl<'s> LintLevelsBuilder<'s> { }, ); - let src = LintSource::Node( + let src = LintLevelSource::Node( Symbol::intern(&new_lint_name), li.span(), reason, @@ -403,7 +403,7 @@ impl<'s> LintLevelsBuilder<'s> { } let (lint_attr_name, lint_attr_span) = match *src { - LintSource::Node(name, span, _) => (name, span), + LintLevelSource::Node(name, span, _) => (name, span), _ => continue, }; @@ -460,7 +460,7 @@ impl<'s> LintLevelsBuilder<'s> { } /// Find the lint level for a lint. - pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintSource) { + pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintLevelSource) { self.sets.get_lint_level(lint, self.cur, None, self.sess) } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index a61d37cc90eba..2dbb84970d106 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -13,7 +13,7 @@ use rustc_span::{symbol, Span, Symbol, DUMMY_SP}; /// How a lint level was set. #[derive(Clone, Copy, PartialEq, Eq, HashStable)] -pub enum LintSource { +pub enum LintLevelSource { /// Lint is at the default level as declared /// in rustc or a plugin. Default, @@ -27,25 +27,25 @@ pub enum LintSource { CommandLine(Symbol, Level), } -impl LintSource { +impl LintLevelSource { pub fn name(&self) -> Symbol { match *self { - LintSource::Default => symbol::kw::Default, - LintSource::Node(name, _, _) => name, - LintSource::CommandLine(name, _) => name, + LintLevelSource::Default => symbol::kw::Default, + LintLevelSource::Node(name, _, _) => name, + LintLevelSource::CommandLine(name, _) => name, } } pub fn span(&self) -> Span { match *self { - LintSource::Default => DUMMY_SP, - LintSource::Node(_, span, _) => span, - LintSource::CommandLine(_, _) => DUMMY_SP, + LintLevelSource::Default => DUMMY_SP, + LintLevelSource::Node(_, span, _) => span, + LintLevelSource::CommandLine(_, _) => DUMMY_SP, } } } -pub type LevelSource = (Level, LintSource); +pub type LevelSource = (Level, LintLevelSource); pub struct LintLevelSets { pub list: Vec, @@ -113,7 +113,7 @@ impl LintLevelSets { id: LintId, mut idx: u32, aux: Option<&FxHashMap>, - ) -> (Option, LintSource) { + ) -> (Option, LintLevelSource) { if let Some(specs) = aux { if let Some(&(level, src)) = specs.get(&id) { return (Some(level), src); @@ -125,7 +125,7 @@ impl LintLevelSets { if let Some(&(level, src)) = specs.get(&id) { return (Some(level), src); } - return (None, LintSource::Default); + return (None, LintLevelSource::Default); } LintSet::Node { ref specs, parent } => { if let Some(&(level, src)) = specs.get(&id) { @@ -213,7 +213,7 @@ pub fn struct_lint_level<'s, 'd>( sess: &'s Session, lint: &'static Lint, level: Level, - src: LintSource, + src: LintLevelSource, span: Option, decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd, ) { @@ -223,7 +223,7 @@ pub fn struct_lint_level<'s, 'd>( sess: &'s Session, lint: &'static Lint, level: Level, - src: LintSource, + src: LintLevelSource, span: Option, decorate: Box FnOnce(LintDiagnosticBuilder<'b>) + 'd>, ) { @@ -274,14 +274,14 @@ pub fn struct_lint_level<'s, 'd>( let name = lint.name_lower(); match src { - LintSource::Default => { + LintLevelSource::Default => { sess.diag_note_once( &mut err, DiagnosticMessageId::from(lint), &format!("`#[{}({})]` on by default", level.as_str(), name), ); } - LintSource::CommandLine(lint_flag_val, orig_level) => { + LintLevelSource::CommandLine(lint_flag_val, orig_level) => { let flag = match orig_level { Level::Warn => "-W", Level::Deny => "-D", @@ -310,7 +310,7 @@ pub fn struct_lint_level<'s, 'd>( ); } } - LintSource::Node(lint_attr_name, src, reason) => { + LintLevelSource::Node(lint_attr_name, src, reason) => { if let Some(rationale) = reason { err.note(&rationale.as_str()); } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4205e2ca5aa61..9b944f202a937 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -5,7 +5,7 @@ use crate::dep_graph::{self, DepGraph, DepKind, DepNode, DepNodeExt}; use crate::hir::exports::ExportMap; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintSource}; +use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; use crate::middle; use crate::middle::cstore::{CrateStoreDyn, EncodedMetadata}; use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; @@ -2559,7 +2559,7 @@ impl<'tcx> TyCtxt<'tcx> { self, lint: &'static Lint, mut id: hir::HirId, - ) -> (Level, LintSource) { + ) -> (Level, LintLevelSource) { let sets = self.lint_levels(LOCAL_CRATE); loop { if let Some(pair) = sets.level_and_source(lint, id, self.sess) { diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 52f6a97089bde..af5121d6b1be7 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -5,7 +5,7 @@ use crate::html::markdown::{find_testable_code, ErrorCodes}; use crate::passes::doc_test_lints::{should_have_doc_example, Tests}; use crate::passes::Pass; use rustc_lint::builtin::MISSING_DOCS; -use rustc_middle::lint::LintSource; +use rustc_middle::lint::LintLevelSource; use rustc_session::lint; use rustc_span::symbol::sym; use rustc_span::FileName; @@ -254,7 +254,7 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { // `missing_docs` is allow-by-default, so don't treat this as ignoring the item // unless the user had an explicit `allow` let should_have_docs = - level != lint::Level::Allow || matches!(source, LintSource::Default); + level != lint::Level::Allow || matches!(source, LintLevelSource::Default); debug!("counting {:?} {:?} in {}", i.type_(), i.name, filename); self.items.entry(filename).or_default().count_item( has_docs, diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 1c1141e7c8122..17d2847913d4b 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -9,7 +9,7 @@ use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; -use rustc_middle::lint::LintSource; +use rustc_middle::lint::LintLevelSource; use rustc_session::lint; crate const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { @@ -77,7 +77,7 @@ crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> boo let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_local()); let (level, source) = cx.tcx.lint_level_at_node(lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id); - level != lint::Level::Allow || matches!(source, LintSource::Default) + level != lint::Level::Allow || matches!(source, LintLevelSource::Default) } crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { From d3900d3775c665237b83ea87e01838da9cf0da87 Mon Sep 17 00:00:00 2001 From: pierwill Date: Mon, 21 Dec 2020 14:40:50 -0800 Subject: [PATCH 07/22] Document rustc_middle::lint::LevelSource This is to clarify the difference between `LevelSource` and `LintLevelSource`. Appease x.py fmt. --- compiler/rustc_lint/src/levels.rs | 4 +++- compiler/rustc_middle/src/lint.rs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 410bd06850e75..5cece569903c7 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -12,7 +12,9 @@ use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::map::Map; use rustc_middle::lint::LevelSource; use rustc_middle::lint::LintDiagnosticBuilder; -use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintLevelSource}; +use rustc_middle::lint::{ + struct_lint_level, LintLevelMap, LintLevelSets, LintLevelSource, LintSet, +}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::{builtin, Level, Lint, LintId}; diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 2dbb84970d106..d1a7e89734d2a 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -45,6 +45,7 @@ impl LintLevelSource { } } +/// A tuple of a lint level and its source. pub type LevelSource = (Level, LintLevelSource); pub struct LintLevelSets { From 163f5da322f7e62216532735c67813060eacc8de Mon Sep 17 00:00:00 2001 From: pierwill Date: Mon, 21 Dec 2020 17:18:48 -0800 Subject: [PATCH 08/22] Add installation commands to `x` tool README --- src/tools/x/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tools/x/README.md b/src/tools/x/README.md index 3b3cf2847c200..80bf02e8a0ef5 100644 --- a/src/tools/x/README.md +++ b/src/tools/x/README.md @@ -1,3 +1,10 @@ # x `x` invokes `x.py` from any subdirectory. + +To install, run the following commands: + +``` +$ cd rust/src/tools/x/ +$ cargo install --path . +``` From 9414f0b833734c344e795d590e9a845ce437c908 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 19 Dec 2020 16:29:38 -0500 Subject: [PATCH 09/22] Revert "Remove missing_fragment_specifier lint" This reverts commit 5ba961018c482e050af908de60e4f8bd1a00f0ae. --- compiler/rustc_lint_defs/src/builtin.rs | 17 +++++++++++++++++ .../rustc/src/lints/listing/deny-by-default.md | 3 --- 2 files changed, 17 insertions(+), 3 deletions(-) delete mode 100644 src/doc/rustc/src/lints/listing/deny-by-default.md diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 6a48b8f4dfbb2..de5253a84cc06 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1227,6 +1227,22 @@ declare_lint! { }; } +declare_lint! { + /// The missing_fragment_specifier warning is issued when an unused pattern in a + /// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not + /// followed by a fragment specifier (e.g. `:expr`). + /// + /// This warning can always be fixed by removing the unused pattern in the + /// `macro_rules!` macro definition. + pub MISSING_FRAGMENT_SPECIFIER, + Deny, + "detects missing fragment specifiers in unused `macro_rules!` patterns", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #40107 ", + edition: None, + }; +} + declare_lint! { /// The `late_bound_lifetime_arguments` lint detects generic lifetime /// arguments in path segments with late bound lifetime parameters. @@ -2827,6 +2843,7 @@ declare_lint_pass! { CONST_ITEM_MUTATION, SAFE_PACKED_BORROWS, PATTERNS_IN_FNS_WITHOUT_BODY, + MISSING_FRAGMENT_SPECIFIER, LATE_BOUND_LIFETIME_ARGUMENTS, ORDER_DEPENDENT_TRAIT_OBJECTS, COHERENCE_LEAK_CHECK, diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md deleted file mode 100644 index 3c1452d64676c..0000000000000 --- a/src/doc/rustc/src/lints/listing/deny-by-default.md +++ /dev/null @@ -1,3 +0,0 @@ -# Deny-by-default lints - -This file is auto-generated by the lint-docs script. From f1eb88b28a84b0533ddd036a60bb5b8acbffabb2 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 19 Dec 2020 16:30:56 -0500 Subject: [PATCH 10/22] Revert "Promote missing_fragment_specifier to hard error" This reverts commit 02eae432e7476a0686633a8c2b7cb1d5aab1bd2c. --- compiler/rustc_expand/src/mbe.rs | 2 +- compiler/rustc_expand/src/mbe/macro_parser.rs | 20 ++++++++++++++--- compiler/rustc_expand/src/mbe/macro_rules.rs | 15 +++++++------ compiler/rustc_expand/src/mbe/quoted.rs | 11 ++++++---- compiler/rustc_interface/src/passes.rs | 19 +++++++++++++++- compiler/rustc_session/src/parse.rs | 2 ++ src/test/ui/lint/expansion-time.rs | 4 ++++ src/test/ui/lint/expansion-time.stderr | 22 +++++++++++++++---- src/test/ui/macros/issue-39404.rs | 1 + src/test/ui/macros/issue-39404.stderr | 4 ++++ src/test/ui/macros/macro-match-nonterminal.rs | 1 + .../ui/macros/macro-match-nonterminal.stderr | 4 ++++ src/test/ui/parser/macro/issue-33569.rs | 1 - src/test/ui/parser/macro/issue-33569.stderr | 16 +++++--------- 14 files changed, 90 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs index eb4aab116f00f..cbc4d14a65a1b 100644 --- a/compiler/rustc_expand/src/mbe.rs +++ b/compiler/rustc_expand/src/mbe.rs @@ -84,7 +84,7 @@ enum TokenTree { /// e.g., `$var` MetaVar(Span, Ident), /// e.g., `$var:expr`. This is only used in the left hand side of MBE macros. - MetaVarDecl(Span, Ident /* name to bind */, NonterminalKind), + MetaVarDecl(Span, Ident /* name to bind */, Option), } impl TokenTree { diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 3cf2d8f8ac1ef..0c44f5fe9e10a 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -378,6 +378,11 @@ fn nameize>( n_rec(sess, next_m, res.by_ref(), ret_val)?; } } + TokenTree::MetaVarDecl(span, _, None) => { + if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() { + return Err((span, "missing fragment specifier".to_string())); + } + } TokenTree::MetaVarDecl(sp, bind_name, _) => match ret_val .entry(MacroRulesNormalizedIdent::new(bind_name)) { @@ -446,6 +451,7 @@ fn or_pat_mode(edition: Edition) -> OrPatNonterminalMode { /// /// A `ParseResult`. Note that matches are kept track of through the items generated. fn inner_parse_loop<'root, 'tt>( + sess: &ParseSess, cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, next_items: &mut Vec>, eof_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, @@ -563,9 +569,16 @@ fn inner_parse_loop<'root, 'tt>( }))); } + // We need to match a metavar (but the identifier is invalid)... this is an error + TokenTree::MetaVarDecl(span, _, None) => { + if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() { + return Error(span, "missing fragment specifier".to_string()); + } + } + // We need to match a metavar with a valid ident... call out to the black-box // parser by adding an item to `bb_items`. - TokenTree::MetaVarDecl(span, _, kind) => { + TokenTree::MetaVarDecl(span, _, Some(kind)) => { // Built-in nonterminals never start with these tokens, so we can eliminate // them from consideration. // @@ -640,6 +653,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na // parsing from the black-box parser done. The result is that `next_items` will contain a // bunch of possible next matcher positions in `next_items`. match inner_parse_loop( + parser.sess, &mut cur_items, &mut next_items, &mut eof_items, @@ -701,7 +715,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na let nts = bb_items .iter() .map(|item| match item.top_elts.get_tt(item.idx) { - TokenTree::MetaVarDecl(_, bind, kind) => format!("{} ('{}')", kind, bind), + TokenTree::MetaVarDecl(_, bind, Some(kind)) => format!("{} ('{}')", kind, bind), _ => panic!(), }) .collect::>() @@ -731,7 +745,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na assert_eq!(bb_items.len(), 1); let mut item = bb_items.pop().unwrap(); - if let TokenTree::MetaVarDecl(span, _, kind) = item.top_elts.get_tt(item.idx) { + if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) { let match_cur = item.match_cur; // We use the span of the metavariable declaration to determine any // edition-specific matching behavior for non-terminals. diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 66463eeb90713..89d375b257da5 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -401,7 +401,7 @@ pub fn compile_declarative_macro( let diag = &sess.parse_sess.span_diagnostic; let lhs_nm = Ident::new(sym::lhs, def.span); let rhs_nm = Ident::new(sym::rhs, def.span); - let tt_spec = NonterminalKind::TT; + let tt_spec = Some(NonterminalKind::TT); // Parse the macro_rules! invocation let (macro_rules, body) = match &def.kind { @@ -578,7 +578,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool { TokenTree::Sequence(span, ref seq) => { if seq.separator.is_none() && seq.tts.iter().all(|seq_tt| match *seq_tt { - TokenTree::MetaVarDecl(_, _, NonterminalKind::Vis) => true, + TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true, TokenTree::Sequence(_, ref sub_seq) => { sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne @@ -961,7 +961,7 @@ fn check_matcher_core( // Now `last` holds the complete set of NT tokens that could // end the sequence before SUFFIX. Check that every one works with `suffix`. for token in &last.tokens { - if let TokenTree::MetaVarDecl(_, name, kind) = *token { + if let TokenTree::MetaVarDecl(_, name, Some(kind)) = *token { for next_token in &suffix_first.tokens { match is_in_follow(next_token, kind) { IsInFollow::Yes => {} @@ -1019,7 +1019,7 @@ fn check_matcher_core( } fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool { - if let mbe::TokenTree::MetaVarDecl(_, _, kind) = *tok { + if let mbe::TokenTree::MetaVarDecl(_, _, Some(kind)) = *tok { frag_can_be_followed_by_any(kind) } else { // (Non NT's can always be followed by anything in matchers.) @@ -1123,7 +1123,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { } _ => IsInFollow::No(TOKENS), }, - TokenTree::MetaVarDecl(_, _, NonterminalKind::Block) => IsInFollow::Yes, + TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Block)) => IsInFollow::Yes, _ => IsInFollow::No(TOKENS), } } @@ -1158,7 +1158,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { TokenTree::MetaVarDecl( _, _, - NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path, + Some(NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path), ) => IsInFollow::Yes, _ => IsInFollow::No(TOKENS), } @@ -1171,7 +1171,8 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { match *tt { mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token), mbe::TokenTree::MetaVar(_, name) => format!("${}", name), - mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind), + mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind), + mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name), _ => panic!( "{}", "unexpected mbe::TokenTree::{Sequence or Delimited} \ diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 48db532c78f30..01b11bb979d68 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -3,7 +3,7 @@ use crate::mbe::{Delimited, KleeneOp, KleeneToken, SequenceRepetition, TokenTree use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream; -use rustc_ast::NodeId; +use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_session::parse::ParseSess; use rustc_span::symbol::{kw, Ident}; @@ -73,7 +73,7 @@ pub(super) fn parse( .emit(); token::NonterminalKind::Ident }); - result.push(TokenTree::MetaVarDecl(span, ident, kind)); + result.push(TokenTree::MetaVarDecl(span, ident, Some(kind))); continue; } _ => token.span, @@ -83,8 +83,11 @@ pub(super) fn parse( } tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp), }; - sess.span_diagnostic.struct_span_err(span, "missing fragment specifier").emit(); - continue; + if node_id != DUMMY_NODE_ID { + // Macros loaded from other crates have dummy node ids. + sess.missing_fragment_specifiers.borrow_mut().insert(span, node_id); + } + result.push(TokenTree::MetaVarDecl(span, ident, None)); } // Not a metavar or no matchers allowed, so just return the tree diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index c13d26c79d738..a8c8690b9e7fa 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -29,6 +29,7 @@ use rustc_passes::{self, hir_stats, layout_test}; use rustc_plugin_impl as plugin; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode}; +use rustc_session::lint; use rustc_session::output::{filename_for_input, filename_for_metadata}; use rustc_session::search_paths::PathKind; use rustc_session::Session; @@ -306,11 +307,27 @@ fn configure_and_expand_inner<'a>( ecx.check_unused_macros(); }); + let mut missing_fragment_specifiers: Vec<_> = ecx + .sess + .parse_sess + .missing_fragment_specifiers + .borrow() + .iter() + .map(|(span, node_id)| (*span, *node_id)) + .collect(); + missing_fragment_specifiers.sort_unstable_by_key(|(span, _)| *span); + + let recursion_limit_hit = ecx.reduced_recursion_limit.is_some(); + + for (span, node_id) in missing_fragment_specifiers { + let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER; + let msg = "missing fragment specifier"; + resolver.lint_buffer().buffer_lint(lint, node_id, span, msg); + } if cfg!(windows) { env::set_var("PATH", &old_path); } - let recursion_limit_hit = ecx.reduced_recursion_limit.is_some(); if recursion_limit_hit { // If we hit a recursion limit, exit early to avoid later passes getting overwhelmed // with a large AST diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 66c3738fb5b5a..b1a4834241730 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -119,6 +119,7 @@ pub struct ParseSess { pub unstable_features: UnstableFeatures, pub config: CrateConfig, pub edition: Edition, + pub missing_fragment_specifiers: Lock>, /// Places where raw identifiers were used. This is used for feature-gating raw identifiers. pub raw_identifier_spans: Lock>, /// Used to determine and report recursive module inclusions. @@ -152,6 +153,7 @@ impl ParseSess { unstable_features: UnstableFeatures::from_environment(None), config: FxHashSet::default(), edition: ExpnId::root().expn_data().edition, + missing_fragment_specifiers: Default::default(), raw_identifier_spans: Lock::new(Vec::new()), included_mod_stack: Lock::new(vec![]), source_map, diff --git a/src/test/ui/lint/expansion-time.rs b/src/test/ui/lint/expansion-time.rs index a9c7ac363b0b3..f23c7cb0dca14 100644 --- a/src/test/ui/lint/expansion-time.rs +++ b/src/test/ui/lint/expansion-time.rs @@ -5,6 +5,10 @@ macro_rules! foo { ( $($i:ident)* ) => { $($i)+ }; //~ WARN meta-variable repeats with different Kleene operator } +#[warn(missing_fragment_specifier)] +macro_rules! m { ($i) => {} } //~ WARN missing fragment specifier + //~| WARN this was previously accepted + #[warn(soft_unstable)] mod benches { #[bench] //~ WARN use of unstable library feature 'test' diff --git a/src/test/ui/lint/expansion-time.stderr b/src/test/ui/lint/expansion-time.stderr index 24e2733064e48..b0fc1f8e5eec7 100644 --- a/src/test/ui/lint/expansion-time.stderr +++ b/src/test/ui/lint/expansion-time.stderr @@ -12,14 +12,28 @@ note: the lint level is defined here LL | #[warn(meta_variable_misuse)] | ^^^^^^^^^^^^^^^^^^^^ +warning: missing fragment specifier + --> $DIR/expansion-time.rs:9:19 + | +LL | macro_rules! m { ($i) => {} } + | ^^ + | +note: the lint level is defined here + --> $DIR/expansion-time.rs:8:8 + | +LL | #[warn(missing_fragment_specifier)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 + warning: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable - --> $DIR/expansion-time.rs:10:7 + --> $DIR/expansion-time.rs:14:7 | LL | #[bench] | ^^^^^ | note: the lint level is defined here - --> $DIR/expansion-time.rs:8:8 + --> $DIR/expansion-time.rs:12:8 | LL | #[warn(soft_unstable)] | ^^^^^^^^^^^^^ @@ -33,10 +47,10 @@ LL | 2 | ^ | note: the lint level is defined here - --> $DIR/expansion-time.rs:25:8 + --> $DIR/expansion-time.rs:29:8 | LL | #[warn(incomplete_include)] | ^^^^^^^^^^^^^^^^^^ -warning: 3 warnings emitted +warning: 4 warnings emitted diff --git a/src/test/ui/macros/issue-39404.rs b/src/test/ui/macros/issue-39404.rs index 054958ba00b8d..2229f2c3900c3 100644 --- a/src/test/ui/macros/issue-39404.rs +++ b/src/test/ui/macros/issue-39404.rs @@ -2,5 +2,6 @@ macro_rules! m { ($i) => {} } //~^ ERROR missing fragment specifier +//~| WARN previously accepted fn main() {} diff --git a/src/test/ui/macros/issue-39404.stderr b/src/test/ui/macros/issue-39404.stderr index 645f06e59d817..d2f2a823c2a6b 100644 --- a/src/test/ui/macros/issue-39404.stderr +++ b/src/test/ui/macros/issue-39404.stderr @@ -3,6 +3,10 @@ error: missing fragment specifier | LL | macro_rules! m { ($i) => {} } | ^^ + | + = note: `#[deny(missing_fragment_specifier)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 error: aborting due to previous error diff --git a/src/test/ui/macros/macro-match-nonterminal.rs b/src/test/ui/macros/macro-match-nonterminal.rs index 6b023e4137274..b23e5c71c03f0 100644 --- a/src/test/ui/macros/macro-match-nonterminal.rs +++ b/src/test/ui/macros/macro-match-nonterminal.rs @@ -2,6 +2,7 @@ macro_rules! test { ($a, $b) => { //~^ ERROR missing fragment //~| ERROR missing fragment + //~| WARN this was previously accepted () }; } diff --git a/src/test/ui/macros/macro-match-nonterminal.stderr b/src/test/ui/macros/macro-match-nonterminal.stderr index 334d62812cdab..674ce3434aac6 100644 --- a/src/test/ui/macros/macro-match-nonterminal.stderr +++ b/src/test/ui/macros/macro-match-nonterminal.stderr @@ -9,6 +9,10 @@ error: missing fragment specifier | LL | ($a, $b) => { | ^^ + | + = note: `#[deny(missing_fragment_specifier)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/macro/issue-33569.rs b/src/test/ui/parser/macro/issue-33569.rs index cf81f0480a2a7..80e2d7c6545ba 100644 --- a/src/test/ui/parser/macro/issue-33569.rs +++ b/src/test/ui/parser/macro/issue-33569.rs @@ -2,7 +2,6 @@ macro_rules! foo { { $+ } => { //~ ERROR expected identifier, found `+` //~^ ERROR missing fragment specifier $(x)(y) //~ ERROR expected one of: `*`, `+`, or `?` - //~^ ERROR attempted to repeat an expression containing no syntax variables } } diff --git a/src/test/ui/parser/macro/issue-33569.stderr b/src/test/ui/parser/macro/issue-33569.stderr index f54efaa6996f2..b4d38d3ce4806 100644 --- a/src/test/ui/parser/macro/issue-33569.stderr +++ b/src/test/ui/parser/macro/issue-33569.stderr @@ -4,23 +4,17 @@ error: expected identifier, found `+` LL | { $+ } => { | ^ -error: missing fragment specifier - --> $DIR/issue-33569.rs:2:8 - | -LL | { $+ } => { - | ^ - error: expected one of: `*`, `+`, or `?` --> $DIR/issue-33569.rs:4:13 | LL | $(x)(y) | ^^^ -error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth - --> $DIR/issue-33569.rs:4:10 +error: missing fragment specifier + --> $DIR/issue-33569.rs:2:8 | -LL | $(x)(y) - | ^^^ +LL | { $+ } => { + | ^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors From 56154a11473da93da0f5d57f4692991ae4972695 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 20 Dec 2020 21:44:27 -0500 Subject: [PATCH 11/22] Add example to lint docs --- compiler/rustc_lint_defs/src/builtin.rs | 30 ++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index de5253a84cc06..1c692d4f20762 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1228,12 +1228,40 @@ declare_lint! { } declare_lint! { - /// The missing_fragment_specifier warning is issued when an unused pattern in a + /// The `missing_fragment_specifier` lint is issued when an unused pattern in a /// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not /// followed by a fragment specifier (e.g. `:expr`). /// /// This warning can always be fixed by removing the unused pattern in the /// `macro_rules!` macro definition. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// macro_rules! foo { + /// () => {}; + /// ($name) => { }; + /// } + /// + /// fn main() { + /// foo!(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// To fix this, remove the unused pattern from the `macro_rules!` macro definition: + /// + /// ```rust + /// macro_rules! foo { + /// () => {}; + /// } + /// fn main() { + /// foo!(); + /// } + /// ``` pub MISSING_FRAGMENT_SPECIFIER, Deny, "detects missing fragment specifiers in unused `macro_rules!` patterns", From a6d377d56560350976ccb46f33ae14ad65eb9372 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 22 Dec 2020 16:33:36 -0800 Subject: [PATCH 12/22] Include rustdoc in the compiler docs index. --- src/bootstrap/doc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 8cacc2512eff1..30a8229036fd8 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -628,6 +628,8 @@ impl Step for Rustdoc { cargo.arg("-p").arg("rustdoc"); cargo.rustdocflag("--document-private-items"); + cargo.rustdocflag("--enable-index-page"); + cargo.rustdocflag("-Zunstable-options"); builder.run(&mut cargo.into()); } } From 732afd41cff1d562e03a6e1611ef7baf9d7f5962 Mon Sep 17 00:00:00 2001 From: Victor Ding Date: Sat, 19 Dec 2020 22:36:35 +1100 Subject: [PATCH 13/22] Exclude unnecessary info from CodegenResults `foreign_module` and `wasm_import_module` are not needed for linking, and hence can be removed from CodegenResults. --- compiler/rustc_codegen_ssa/src/back/link.rs | 5 +++-- compiler/rustc_codegen_ssa/src/base.rs | 5 +++-- compiler/rustc_codegen_ssa/src/lib.rs | 21 ++++++++++++++++++--- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ccd4d103ddb7f..a3a2ef0417568 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib}; +use rustc_middle::middle::cstore::{EncodedMetadata, LibSource}; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SanitizerSet}; @@ -22,7 +22,8 @@ use super::command::Command; use super::linker::{self, Linker}; use super::rpath::{self, RPathConfig}; use crate::{ - looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, METADATA_FILENAME, + looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib, + METADATA_FILENAME, }; use cc::windows_registry; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 21138f967a273..18132a2c7a3c0 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -766,7 +766,7 @@ impl CrateInfo { profiler_runtime: None, is_no_builtins: Default::default(), native_libraries: Default::default(), - used_libraries: tcx.native_libraries(LOCAL_CRATE), + used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(), link_args: tcx.link_args(LOCAL_CRATE), crate_name: Default::default(), used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic), @@ -787,7 +787,8 @@ impl CrateInfo { info.missing_lang_items.reserve(n_crates); for &cnum in crates.iter() { - info.native_libraries.insert(cnum, tcx.native_libraries(cnum)); + info.native_libraries + .insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect()); info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string()); info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum)); if tcx.is_panic_runtime(cnum) { diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index ee889d552412e..bc93bd8b7bd96 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -21,15 +21,17 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; +use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; use rustc_hir::LangItem; use rustc_middle::dep_graph::WorkProduct; -use rustc_middle::middle::cstore::{CrateSource, LibSource, NativeLib}; +use rustc_middle::middle::cstore::{self, CrateSource, LibSource}; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::ty::query::Providers; use rustc_session::config::{OutputFilenames, OutputType, RUST_CGU_EXT}; +use rustc_session::utils::NativeLibKind; use rustc_span::symbol::Symbol; use std::path::{Path, PathBuf}; @@ -105,6 +107,19 @@ bitflags::bitflags! { } } +#[derive(Clone, Debug, Encodable, Decodable, HashStable)] +pub struct NativeLib { + pub kind: NativeLibKind, + pub name: Option, + pub cfg: Option, +} + +impl From<&cstore::NativeLib> for NativeLib { + fn from(lib: &cstore::NativeLib) -> Self { + NativeLib { kind: lib.kind.clone(), name: lib.name.clone(), cfg: lib.cfg.clone() } + } +} + /// Misc info we load from metadata to persist beyond the tcx. /// /// Note: though `CrateNum` is only meaningful within the same tcx, information within `CrateInfo` @@ -119,9 +134,9 @@ pub struct CrateInfo { pub compiler_builtins: Option, pub profiler_runtime: Option, pub is_no_builtins: FxHashSet, - pub native_libraries: FxHashMap>>, + pub native_libraries: FxHashMap>, pub crate_name: FxHashMap, - pub used_libraries: Lrc>, + pub used_libraries: Vec, pub link_args: Lrc>, pub used_crate_source: FxHashMap>, pub used_crates_static: Vec<(CrateNum, LibSource)>, From e8a564edc0a0c19633039848c68d5f81fcfcc00d Mon Sep 17 00:00:00 2001 From: Victor Ding Date: Wed, 23 Dec 2020 12:17:45 +1100 Subject: [PATCH 14/22] Add a test that rustc compiles and links separately --- src/test/run-make-fulldeps/separate-link/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/test/run-make-fulldeps/separate-link/Makefile diff --git a/src/test/run-make-fulldeps/separate-link/Makefile b/src/test/run-make-fulldeps/separate-link/Makefile new file mode 100644 index 0000000000000..060484e89f930 --- /dev/null +++ b/src/test/run-make-fulldeps/separate-link/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +all: + echo 'fn main(){}' | $(RUSTC) -Z no-link - + $(RUSTC) -Z link-only $(TMPDIR)/rust_out.rlink + $(call RUN,rust_out) From 1a30823370d64f4dc5e55b3832c47774aa87179c Mon Sep 17 00:00:00 2001 From: Arlie Davis Date: Tue, 22 Dec 2020 14:02:07 -0800 Subject: [PATCH 15/22] Improvements to NatVis support NatVis files describe how to display types in some Windows debuggers, such as Visual Studio, WinDbg, and VS Code. This commit makes several improvements: * Adds visualizers for Rc, Weak, and Arc. * Changes [size] to [len], for consistency with the Rust API. Visualizers often use [size] to mirror the size() method on C++ STL collections. * Several visualizers used the PVOID and ULONG typedefs. These are part of the Windows API; they are not guaranteed to always be defined in a pure Rust DLL/EXE. I converted PVOID to `void*` and `ULONG` to `unsigned long`. * Cosmetic change: Removed {} braces around the visualized display for `Option` types. They now display simply as `Some(value)` or `None`, which reflects what is written in source code. * The visualizer for `alloc::string::String` makes assumptions about the layout of `String` (it casts `String*` to another type), rather than using symbolic expressions. This commit changes the visualizer so that it simply uses symbolic expressions to access the string data and string length. --- src/etc/natvis/intrinsic.natvis | 18 ++++++++----- src/etc/natvis/liballoc.natvis | 46 ++++++++++++++++++++++++--------- src/etc/natvis/libcore.natvis | 26 +++++++------------ src/etc/natvis/libstd.natvis | 8 +++--- 4 files changed, 59 insertions(+), 39 deletions(-) diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 874550da8b0c9..030892a432b31 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -4,17 +4,21 @@ {data_ptr,[length]s8} data_ptr,[length]s8 - length - - length - data_ptr - + length + + + + length + data_ptr + + + - {{ length={length} }} + {{ len={length} }} - length + length length data_ptr diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis index de30b58526a13..cfaafc5734bce 100644 --- a/src/etc/natvis/liballoc.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -1,9 +1,9 @@ - {{ size={len} }} + {{ len={len} }} - len + len buf.cap len @@ -12,9 +12,9 @@ - {{ size={tail <= head ? head - tail : buf.cap - tail + head} }} + {{ len={tail <= head ? head - tail : buf.cap - tail + head} }} - tail <= head ? head - tail : buf.cap - tail + head + tail <= head ? head - tail : buf.cap - tail + head buf.cap @@ -31,7 +31,7 @@ - {{ size={len} }} + {{ len={len} }} len @@ -42,15 +42,37 @@ - {*(char**)this,[vec.len]s8} - *(char**)this,[vec.len]s8 + {(char*)vec.buf.ptr.pointer,[vec.len]s8} + (char*)vec.buf.ptr.pointer,[vec.len]s8 - vec.len + vec.len vec.buf.cap - - vec.len - *(char**)this - + + + + vec.len + (char*)vec.buf.ptr.pointer + + + + + + + {ptr.pointer->value} + + ptr.pointer->value + + + + {ptr.pointer->data} + + ptr.pointer->data + + + + {ptr.pointer->data} + + ptr.pointer->data diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 0e703b3b95026..984a8bfb13c7c 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -6,34 +6,28 @@ pointer + {{ Shared {pointer} }} pointer + - {{ None }} - {{ Some {__0} }} + None + Some({__0}) - (ULONG)(RUST$ENUM$DISR != 0) - __0 - - (ULONG)(RUST$ENUM$DISR != 0) - &__0 - + __0 + - {{ None }} - {{ Some {($T1 *)this} }} + None + Some({($T1 *)this}) - (ULONG)(*(PVOID *)this != nullptr) - ($T1 *)this - - (ULONG)(*(PVOID *)this != nullptr) - ($T1 *)this - + ($T1 *)this + \ No newline at end of file diff --git a/src/etc/natvis/libstd.natvis b/src/etc/natvis/libstd.natvis index 9550c25f2fcfe..7e5ee7b13daf1 100644 --- a/src/etc/natvis/libstd.natvis +++ b/src/etc/natvis/libstd.natvis @@ -26,9 +26,9 @@ --> - {{ size={base.table.items} }} + {{ len={base.table.items} }} - base.table.items + base.table.items base.table.items + base.table.growth_left base.hash_builder @@ -50,9 +50,9 @@ - {{ size={base.map.table.items} }} + {{ len={base.map.table.items} }} - base.map.table.items + base.map.table.items base.map.table.items + base.map.table.growth_left base.map.hash_builder From c625d3183cfc64184f5f68687a964ef83f41f199 Mon Sep 17 00:00:00 2001 From: PankajChaudhary5 Date: Wed, 23 Dec 2020 11:02:04 +0530 Subject: [PATCH 16/22] Updated the match with the matches macro --- compiler/rustc_middle/src/ty/sty.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a955cca53cc8b..aa0751ae60451 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -205,10 +205,7 @@ pub enum TyKind<'tcx> { impl TyKind<'tcx> { #[inline] pub fn is_primitive(&self) -> bool { - match self { - Bool | Char | Int(_) | Uint(_) | Float(_) => true, - _ => false, - } + matches!(self, Bool | Char | Int(_) | Uint(_) | Float(_)) } } From f459b0fea5723010bf1654d8073389fd0a0263d1 Mon Sep 17 00:00:00 2001 From: Yenlin Chen <3822365+hencrice@users.noreply.github.com> Date: Wed, 23 Dec 2020 18:55:37 +0000 Subject: [PATCH 17/22] Addressed feedbacks Also updated the mir-opt test output files. --- compiler/rustc_mir/src/util/pretty.rs | 20 +++---------------- .../checked_add.main.ConstProp.diff | 3 --- .../const_prop/indirect.main.ConstProp.diff | 3 --- .../issue_67019.main.ConstProp.diff | 3 --- ...ble_variable_aggregate.main.ConstProp.diff | 3 --- ...es_into_variable.main.ConstProp.32bit.diff | 3 --- ...es_into_variable.main.ConstProp.64bit.diff | 3 --- .../return_place.add.ConstProp.diff | 3 --- ...le_literal_propagation.main.ConstProp.diff | 3 --- ...ves_unused_consts.main.SimplifyLocals.diff | 3 --- 10 files changed, 3 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 9b81629400a66..394eb8334223c 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -17,7 +17,6 @@ use rustc_middle::mir::interpret::{ }; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor}; use rustc_target::abi::Size; use std::ops::ControlFlow; @@ -414,22 +413,9 @@ fn use_verbose(ty: &&TyS<'tcx>) -> bool { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false, // Unit type ty::Tuple(g_args) if g_args.is_empty() => false, - ty::Tuple(g_args) => { - // could have used `try_fold` here but it seems a bit silly that - // the accumulator is useless - let mut should_be_verbose = false; - for g_arg in g_args.iter() { - if match g_arg.unpack() { - GenericArgKind::Type(ty) => use_verbose(&ty), - GenericArgKind::Const(ty::Const { ty, val: _ }) => use_verbose(ty), - _ => false, - } { - should_be_verbose = true; - break; - } - } - should_be_verbose - } + ty::Tuple(g_args) => g_args.iter().any(|g_arg| { + use_verbose(&g_arg.expect_ty()) + }), ty::Array(ty, _) => use_verbose(ty), ty::FnDef(..) => false, _ => true, diff --git a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff index f01676b6da863..3397ef95856a5 100644 --- a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff @@ -14,9 +14,6 @@ - _2 = CheckedAdd(const 1_u32, const 1_u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 - assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 + _2 = const (2_u32, false); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 -+ // ty::Const -+ // + ty: (u32, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/checked_add.rs:5:18: 5:23 + // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff index 8c7b35887c915..9ddb34e58e5a6 100644 --- a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff @@ -18,9 +18,6 @@ - assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 + _2 = const 2_u8; // scope 0 at $DIR/indirect.rs:5:13: 5:25 + _3 = const (3_u8, false); // scope 0 at $DIR/indirect.rs:5:13: 5:29 -+ // ty::Const -+ // + ty: (u8, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/indirect.rs:5:13: 5:29 + // + literal: Const { ty: (u8, bool), val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff index 492938fc206bd..da35bf18c7116 100644 --- a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff @@ -15,9 +15,6 @@ (_3.1: u8) = const 2_u8; // scope 0 at $DIR/issue-67019.rs:11:11: 11:17 - (_2.0: (u8, u8)) = move _3; // scope 0 at $DIR/issue-67019.rs:11:10: 11:19 + (_2.0: (u8, u8)) = const (1_u8, 2_u8); // scope 0 at $DIR/issue-67019.rs:11:10: 11:19 -+ // ty::Const -+ // + ty: (u8, u8) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [1, 2], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/issue-67019.rs:11:10: 11:19 + // + literal: Const { ty: (u8, u8), val: Value(ByRef { alloc: Allocation { bytes: [1, 2], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff index 204c1acecf548..12b02e90345d9 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff @@ -20,9 +20,6 @@ StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10 - _2 = _1; // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14 + _2 = const (42_i32, 99_i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14 -+ // ty::Const -+ // + ty: (i32, i32) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [42, 0, 0, 0, 99, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/mutable_variable_aggregate.rs:7:13: 7:14 + // + literal: Const { ty: (i32, i32), val: Value(ByRef { alloc: Allocation { bytes: [42, 0, 0, 0, 99, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff index 53ffc01ccaf25..a10bac4f3ea3b 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff @@ -27,9 +27,6 @@ - _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 - assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 -+ // ty::Const -+ // + ty: (i32, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 + // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff index 53ffc01ccaf25..a10bac4f3ea3b 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff @@ -27,9 +27,6 @@ - _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 - assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 -+ // ty::Const -+ // + ty: (i32, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 + // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff index fc8a5437232cf..f0e9916e6300e 100644 --- a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff +++ b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff @@ -9,9 +9,6 @@ - _1 = CheckedAdd(const 2_u32, const 2_u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10 - assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 + _1 = const (4_u32, false); // scope 0 at $DIR/return_place.rs:6:5: 6:10 -+ // ty::Const -+ // + ty: (u32, bool) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/return_place.rs:6:5: 6:10 + // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff index 2de1ab19b7c3d..da4b135d4c6d6 100644 --- a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff @@ -18,9 +18,6 @@ StorageLive(_3); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 - _3 = _1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 + _3 = const (1_u32, 2_u32); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14 -+ // ty::Const -+ // + ty: (u32, u32) -+ // + val: Value(ByRef { alloc: Allocation { bytes: [1, 0, 0, 0, 2, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) + // mir::Constant + // + span: $DIR/tuple_literal_propagation.rs:5:13: 5:14 + // + literal: Const { ty: (u32, u32), val: Value(ByRef { alloc: Allocation { bytes: [1, 0, 0, 0, 2, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } diff --git a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff index 3064e92f90007..34f8ca870cd23 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff @@ -42,9 +42,6 @@ // mir::Constant // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:12 // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(Scalar()) } - // ty::Const - // + ty: ((), ()) - // + val: Value(Scalar()) // mir::Constant // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 // + literal: Const { ty: ((), ()), val: Value(Scalar()) } From ecba49c1bd6e16235e13a076e03e31fcd8d7ffc8 Mon Sep 17 00:00:00 2001 From: Yenlin Chen <3822365+hencrice@users.noreply.github.com> Date: Wed, 23 Dec 2020 19:10:59 +0000 Subject: [PATCH 18/22] Fixed formatting --- compiler/rustc_mir/src/util/pretty.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 394eb8334223c..34ec16d9f2916 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -413,9 +413,7 @@ fn use_verbose(ty: &&TyS<'tcx>) -> bool { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false, // Unit type ty::Tuple(g_args) if g_args.is_empty() => false, - ty::Tuple(g_args) => g_args.iter().any(|g_arg| { - use_verbose(&g_arg.expect_ty()) - }), + ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(&g_arg.expect_ty())), ty::Array(ty, _) => use_verbose(ty), ty::FnDef(..) => false, _ => true, From 68ad606c0e2695253b18f1e490d63cf0f726a169 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 30 Nov 2020 20:51:37 +0100 Subject: [PATCH 19/22] Add edition 2021. --- compiler/rustc_parse/src/parser/expr.rs | 5 +++-- compiler/rustc_parse/src/parser/item.rs | 6 +++--- compiler/rustc_session/src/session.rs | 5 +++++ compiler/rustc_span/src/edition.rs | 14 ++++++++++++-- compiler/rustc_span/src/lib.rs | 5 +++++ compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_typeck/src/check/expr.rs | 5 +++-- .../edition-deny-async-fns-2015.stderr | 18 +++++++++--------- .../suggest-switching-edition-on-await.stderr | 8 ++++---- src/test/ui/editions/async-block-2015.rs | 6 +++--- src/test/ui/editions/async-block-2015.stderr | 6 +++--- src/test/ui/hello2021.rs | 6 ++++++ 12 files changed, 57 insertions(+), 28 deletions(-) create mode 100644 src/test/ui/hello2021.rs diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index eed3e9947b2aa..87d69e08a0666 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -15,6 +15,7 @@ use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; +use rustc_span::edition::LATEST_STABLE_EDITION; use rustc_span::source_map::{self, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Pos}; @@ -2098,8 +2099,8 @@ impl<'a> Parser<'a> { let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| { recover_async = true; - e.span_label(span, "`async` blocks are only allowed in the 2018 edition"); - e.help("set `edition = \"2018\"` in `Cargo.toml`"); + e.span_label(span, "`async` blocks are only allowed in edition 2018 or later"); + e.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION)); e.note("for more on editions, read https://doc.rust-lang.org/edition-guide"); }; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 634cce403df96..8b85dc8eebc25 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -16,7 +16,7 @@ use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, Visibility use rustc_ast::{MacArgs, MacCall, MacDelimiter}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, PResult, StashKey}; -use rustc_span::edition::Edition; +use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; use rustc_span::source_map::{self, Span}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -1668,8 +1668,8 @@ impl<'a> Parser<'a> { if span.rust_2015() { let diag = self.diagnostic(); struct_span_err!(diag, span, E0670, "`async fn` is not permitted in the 2015 edition") - .span_label(span, "to use `async fn`, switch to Rust 2018") - .help("set `edition = \"2018\"` in `Cargo.toml`") + .span_label(span, "to use `async fn`, switch to Rust 2018 or later") + .help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION)) .note("for more on editions, read https://doc.rust-lang.org/edition-guide") .emit(); } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 75faab12e3e12..3a420f5f9def7 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1076,6 +1076,11 @@ impl Session { self.opts.edition >= Edition::Edition2018 } + /// Are we allowed to use features from the Rust 2021 edition? + pub fn rust_2021(&self) -> bool { + self.opts.edition >= Edition::Edition2021 + } + pub fn edition(&self) -> Edition { self.opts.edition } diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs index 4d0c92f51d7ca..3511e2ea1c0e4 100644 --- a/compiler/rustc_span/src/edition.rs +++ b/compiler/rustc_span/src/edition.rs @@ -13,6 +13,8 @@ pub enum Edition { Edition2015, /// The 2018 edition Edition2018, + /// The 2021 ediiton + Edition2021, // when adding new editions, be sure to update: // // - Update the `ALL_EDITIONS` const @@ -22,17 +24,21 @@ pub enum Edition { } // must be in order from oldest to newest -pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018]; +pub const ALL_EDITIONS: &[Edition] = + &[Edition::Edition2015, Edition::Edition2018, Edition::Edition2021]; -pub const EDITION_NAME_LIST: &str = "2015|2018"; +pub const EDITION_NAME_LIST: &str = "2015|2018|2021"; pub const DEFAULT_EDITION: Edition = Edition::Edition2015; +pub const LATEST_STABLE_EDITION: Edition = Edition::Edition2018; + impl fmt::Display for Edition { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match *self { Edition::Edition2015 => "2015", Edition::Edition2018 => "2018", + Edition::Edition2021 => "2021", }; write!(f, "{}", s) } @@ -43,6 +49,7 @@ impl Edition { match *self { Edition::Edition2015 => "rust_2015_compatibility", Edition::Edition2018 => "rust_2018_compatibility", + Edition::Edition2021 => "rust_2021_compatibility", } } @@ -50,6 +57,7 @@ impl Edition { match *self { Edition::Edition2015 => sym::rust_2015_preview, Edition::Edition2018 => sym::rust_2018_preview, + Edition::Edition2021 => sym::rust_2021_preview, } } @@ -57,6 +65,7 @@ impl Edition { match *self { Edition::Edition2015 => true, Edition::Edition2018 => true, + Edition::Edition2021 => false, } } } @@ -67,6 +76,7 @@ impl FromStr for Edition { match s { "2015" => Ok(Edition::Edition2015), "2018" => Ok(Edition::Edition2018), + "2021" => Ok(Edition::Edition2021), _ => Err(()), } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f63a73acbf4ba..33c830c0f5fb3 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -469,6 +469,11 @@ impl Span { self.edition() >= edition::Edition::Edition2018 } + #[inline] + pub fn rust_2021(&self) -> bool { + self.edition() >= edition::Edition::Edition2021 + } + /// Returns the source callee. /// /// Returns `None` if the supplied span has no expansion trace, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 99a523c3f3bb4..a52742fb1dfe8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -920,6 +920,7 @@ symbols! { rust, rust_2015_preview, rust_2018_preview, + rust_2021_preview, rust_begin_unwind, rust_eh_catch_typeinfo, rust_eh_personality, diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index ec0e039b5d29d..b0163c1e46aae 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -38,6 +38,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::Ty; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{AdtKind, Visibility}; +use rustc_span::edition::LATEST_STABLE_EDITION; use rustc_span::hygiene::DesugaringKind; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::Span; @@ -1637,8 +1638,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if field.name == kw::Await { // We know by construction that `.await` is either on Rust 2015 // or results in `ExprKind::Await`. Suggest switching the edition to 2018. - err.note("to `.await` a `Future`, switch to Rust 2018"); - err.help("set `edition = \"2018\"` in `Cargo.toml`"); + err.note("to `.await` a `Future`, switch to Rust 2018 or later"); + err.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION)); err.note("for more on editions, read https://doc.rust-lang.org/edition-guide"); } diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr index 8bffeb2131dec..39bc8e7be8f9f 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -2,7 +2,7 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:3:1 | LL | async fn foo() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 + | ^^^^^ to use `async fn`, switch to Rust 2018 or later | = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -11,7 +11,7 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:5:12 | LL | fn baz() { async fn foo() {} } - | ^^^^^ to use `async fn`, switch to Rust 2018 + | ^^^^^ to use `async fn`, switch to Rust 2018 or later | = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -20,7 +20,7 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:7:1 | LL | async fn async_baz() { - | ^^^^^ to use `async fn`, switch to Rust 2018 + | ^^^^^ to use `async fn`, switch to Rust 2018 or later | = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -29,7 +29,7 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:8:5 | LL | async fn bar() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 + | ^^^^^ to use `async fn`, switch to Rust 2018 or later | = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -38,7 +38,7 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:14:5 | LL | async fn foo() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 + | ^^^^^ to use `async fn`, switch to Rust 2018 or later | = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -47,7 +47,7 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:18:5 | LL | async fn foo() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 + | ^^^^^ to use `async fn`, switch to Rust 2018 or later | = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -56,7 +56,7 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:36:9 | LL | async fn bar() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 + | ^^^^^ to use `async fn`, switch to Rust 2018 or later | = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -65,7 +65,7 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:26:9 | LL | async fn foo() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 + | ^^^^^ to use `async fn`, switch to Rust 2018 or later | = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -74,7 +74,7 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:31:13 | LL | async fn bar() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 + | ^^^^^ to use `async fn`, switch to Rust 2018 or later | = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await.stderr b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr index 695d7dd59fb4f..9ac2bc5cc8964 100644 --- a/src/test/ui/async-await/suggest-switching-edition-on-await.stderr +++ b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr @@ -4,7 +4,7 @@ error[E0609]: no field `await` on type `await_on_struct_missing::S` LL | x.await; | ^^^^^ unknown field | - = note: to `.await` a `Future`, switch to Rust 2018 + = note: to `.await` a `Future`, switch to Rust 2018 or later = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -14,7 +14,7 @@ error[E0609]: no field `await` on type `await_on_struct_similar::S` LL | x.await; | ^^^^^ help: a field with a similar name exists: `awai` | - = note: to `.await` a `Future`, switch to Rust 2018 + = note: to `.await` a `Future`, switch to Rust 2018 or later = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -24,7 +24,7 @@ error[E0609]: no field `await` on type `Pin<&mut dyn Future>` LL | x.await; | ^^^^^ unknown field | - = note: to `.await` a `Future`, switch to Rust 2018 + = note: to `.await` a `Future`, switch to Rust 2018 or later = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -34,7 +34,7 @@ error[E0609]: no field `await` on type `impl Future` LL | x.await; | ^^^^^ | - = note: to `.await` a `Future`, switch to Rust 2018 + = note: to `.await` a `Future`, switch to Rust 2018 or later = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide diff --git a/src/test/ui/editions/async-block-2015.rs b/src/test/ui/editions/async-block-2015.rs index 985606a6f2545..b35cc1564b3d9 100644 --- a/src/test/ui/editions/async-block-2015.rs +++ b/src/test/ui/editions/async-block-2015.rs @@ -1,13 +1,13 @@ async fn foo() { //~^ ERROR `async fn` is not permitted in the 2015 edition -//~| NOTE to use `async fn`, switch to Rust 2018 +//~| NOTE to use `async fn`, switch to Rust 2018 or later //~| HELP set `edition = "2018"` in `Cargo.toml` //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide let x = async {}; //~^ ERROR cannot find struct, variant or union type `async` in this scope //~| NOTE `async` blocks are only allowed in the 2018 edition - let y = async { //~ NOTE `async` blocks are only allowed in the 2018 edition + let y = async { //~ NOTE `async` blocks are only allowed in edition 2018 or later let x = 42; //~^ ERROR expected identifier, found keyword `let` //~| NOTE expected identifier, found keyword @@ -15,7 +15,7 @@ async fn foo() { //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide 42 }; - let z = async { //~ NOTE `async` blocks are only allowed in the 2018 edition + let z = async { //~ NOTE `async` blocks are only allowed in edition 2018 or later 42 //~^ ERROR expected identifier, found `42` //~| NOTE expected identifier diff --git a/src/test/ui/editions/async-block-2015.stderr b/src/test/ui/editions/async-block-2015.stderr index 8e5e5d8bfab9a..d65761d79ff2b 100644 --- a/src/test/ui/editions/async-block-2015.stderr +++ b/src/test/ui/editions/async-block-2015.stderr @@ -2,7 +2,7 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/async-block-2015.rs:1:1 | LL | async fn foo() { - | ^^^^^ to use `async fn`, switch to Rust 2018 + | ^^^^^ to use `async fn`, switch to Rust 2018 or later | = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -11,7 +11,7 @@ error: expected identifier, found keyword `let` --> $DIR/async-block-2015.rs:11:9 | LL | let y = async { - | ----- `async` blocks are only allowed in the 2018 edition + | ----- `async` blocks are only allowed in edition 2018 or later LL | let x = 42; | ^^^ expected identifier, found keyword | @@ -22,7 +22,7 @@ error: expected identifier, found `42` --> $DIR/async-block-2015.rs:19:9 | LL | let z = async { - | ----- `async` blocks are only allowed in the 2018 edition + | ----- `async` blocks are only allowed in edition 2018 or later LL | 42 | ^^ expected identifier | diff --git a/src/test/ui/hello2021.rs b/src/test/ui/hello2021.rs new file mode 100644 index 0000000000000..134d8af5bfb8a --- /dev/null +++ b/src/test/ui/hello2021.rs @@ -0,0 +1,6 @@ +// run-pass +// edition:2021 + +fn main() { + println!("hello, 2021"); +} From 0a3ff20f2f60c1da683a73391a07009fdf5e883a Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 30 Nov 2020 22:11:29 +0100 Subject: [PATCH 20/22] Consistently call editions "Rust 20xx" in messages. --- compiler/rustc_parse/src/parser/expr.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 2 +- compiler/rustc_resolve/src/late/diagnostics.rs | 4 ++-- .../async-await/edition-deny-async-fns-2015.rs | 18 +++++++++--------- .../edition-deny-async-fns-2015.stderr | 18 +++++++++--------- src/test/ui/editions/async-block-2015.rs | 8 ++++---- src/test/ui/editions/async-block-2015.stderr | 8 ++++---- .../try-block/try-block-in-edition2015.stderr | 2 +- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 87d69e08a0666..45c3e67bd0bfc 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2099,7 +2099,7 @@ impl<'a> Parser<'a> { let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| { recover_async = true; - e.span_label(span, "`async` blocks are only allowed in edition 2018 or later"); + e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later"); e.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION)); e.note("for more on editions, read https://doc.rust-lang.org/edition-guide"); }; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 8b85dc8eebc25..7b72a8f2c6dbe 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1667,7 +1667,7 @@ impl<'a> Parser<'a> { fn ban_async_in_2015(&self, span: Span) { if span.rust_2015() { let diag = self.diagnostic(); - struct_span_err!(diag, span, E0670, "`async fn` is not permitted in the 2015 edition") + struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015") .span_label(span, "to use `async fn`, switch to Rust 2018 or later") .help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION)) .note("for more on editions, read https://doc.rust-lang.org/edition-guide") diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 68f59baffce17..03b03448ee5bd 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -180,7 +180,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { ( format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), if path_str == "async" && expected.starts_with("struct") { - "`async` blocks are only allowed in the 2018 edition".to_string() + "`async` blocks are only allowed in Rust 2018 or later".to_string() } else { format!("not found in {}", mod_str) }, @@ -904,7 +904,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { Applicability::MaybeIncorrect, ); if path_str == "try" && span.rust_2015() { - err.note("if you want the `try` keyword, you need to be in the 2018 edition"); + err.note("if you want the `try` keyword, you need Rust 2018 or later"); } } (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => { diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.rs b/src/test/ui/async-await/edition-deny-async-fns-2015.rs index 5d2d186137e16..e5dc9c8a5fee8 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.rs +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.rs @@ -1,21 +1,21 @@ // edition:2015 -async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition +async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015 -fn baz() { async fn foo() {} } //~ ERROR `async fn` is not permitted in the 2015 edition +fn baz() { async fn foo() {} } //~ ERROR `async fn` is not permitted in Rust 2015 -async fn async_baz() { //~ ERROR `async fn` is not permitted in the 2015 edition - async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition +async fn async_baz() { //~ ERROR `async fn` is not permitted in Rust 2015 + async fn bar() {} //~ ERROR `async fn` is not permitted in Rust 2015 } struct Foo {} impl Foo { - async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition + async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015 } trait Bar { - async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition + async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015 //~^ ERROR functions in traits cannot be declared `async` } @@ -23,16 +23,16 @@ fn main() { macro_rules! accept_item { ($x:item) => {} } accept_item! { - async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition + async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015 } accept_item! { impl Foo { - async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition + async fn bar() {} //~ ERROR `async fn` is not permitted in Rust 2015 } } let inside_closure = || { - async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition + async fn bar() {} //~ ERROR `async fn` is not permitted in Rust 2015 }; } diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr index 39bc8e7be8f9f..43364a8e85896 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -1,4 +1,4 @@ -error[E0670]: `async fn` is not permitted in the 2015 edition +error[E0670]: `async fn` is not permitted in Rust 2015 --> $DIR/edition-deny-async-fns-2015.rs:3:1 | LL | async fn foo() {} @@ -7,7 +7,7 @@ LL | async fn foo() {} = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0670]: `async fn` is not permitted in the 2015 edition +error[E0670]: `async fn` is not permitted in Rust 2015 --> $DIR/edition-deny-async-fns-2015.rs:5:12 | LL | fn baz() { async fn foo() {} } @@ -16,7 +16,7 @@ LL | fn baz() { async fn foo() {} } = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0670]: `async fn` is not permitted in the 2015 edition +error[E0670]: `async fn` is not permitted in Rust 2015 --> $DIR/edition-deny-async-fns-2015.rs:7:1 | LL | async fn async_baz() { @@ -25,7 +25,7 @@ LL | async fn async_baz() { = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0670]: `async fn` is not permitted in the 2015 edition +error[E0670]: `async fn` is not permitted in Rust 2015 --> $DIR/edition-deny-async-fns-2015.rs:8:5 | LL | async fn bar() {} @@ -34,7 +34,7 @@ LL | async fn bar() {} = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0670]: `async fn` is not permitted in the 2015 edition +error[E0670]: `async fn` is not permitted in Rust 2015 --> $DIR/edition-deny-async-fns-2015.rs:14:5 | LL | async fn foo() {} @@ -43,7 +43,7 @@ LL | async fn foo() {} = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0670]: `async fn` is not permitted in the 2015 edition +error[E0670]: `async fn` is not permitted in Rust 2015 --> $DIR/edition-deny-async-fns-2015.rs:18:5 | LL | async fn foo() {} @@ -52,7 +52,7 @@ LL | async fn foo() {} = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0670]: `async fn` is not permitted in the 2015 edition +error[E0670]: `async fn` is not permitted in Rust 2015 --> $DIR/edition-deny-async-fns-2015.rs:36:9 | LL | async fn bar() {} @@ -61,7 +61,7 @@ LL | async fn bar() {} = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0670]: `async fn` is not permitted in the 2015 edition +error[E0670]: `async fn` is not permitted in Rust 2015 --> $DIR/edition-deny-async-fns-2015.rs:26:9 | LL | async fn foo() {} @@ -70,7 +70,7 @@ LL | async fn foo() {} = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0670]: `async fn` is not permitted in the 2015 edition +error[E0670]: `async fn` is not permitted in Rust 2015 --> $DIR/edition-deny-async-fns-2015.rs:31:13 | LL | async fn bar() {} diff --git a/src/test/ui/editions/async-block-2015.rs b/src/test/ui/editions/async-block-2015.rs index b35cc1564b3d9..92eae9e3c14f8 100644 --- a/src/test/ui/editions/async-block-2015.rs +++ b/src/test/ui/editions/async-block-2015.rs @@ -1,13 +1,13 @@ async fn foo() { -//~^ ERROR `async fn` is not permitted in the 2015 edition +//~^ ERROR `async fn` is not permitted in Rust 2015 //~| NOTE to use `async fn`, switch to Rust 2018 or later //~| HELP set `edition = "2018"` in `Cargo.toml` //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide let x = async {}; //~^ ERROR cannot find struct, variant or union type `async` in this scope - //~| NOTE `async` blocks are only allowed in the 2018 edition - let y = async { //~ NOTE `async` blocks are only allowed in edition 2018 or later + //~| NOTE `async` blocks are only allowed in Rust 2018 or later + let y = async { //~ NOTE `async` blocks are only allowed in Rust 2018 or later let x = 42; //~^ ERROR expected identifier, found keyword `let` //~| NOTE expected identifier, found keyword @@ -15,7 +15,7 @@ async fn foo() { //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide 42 }; - let z = async { //~ NOTE `async` blocks are only allowed in edition 2018 or later + let z = async { //~ NOTE `async` blocks are only allowed in Rust 2018 or later 42 //~^ ERROR expected identifier, found `42` //~| NOTE expected identifier diff --git a/src/test/ui/editions/async-block-2015.stderr b/src/test/ui/editions/async-block-2015.stderr index d65761d79ff2b..e42747c804c71 100644 --- a/src/test/ui/editions/async-block-2015.stderr +++ b/src/test/ui/editions/async-block-2015.stderr @@ -1,4 +1,4 @@ -error[E0670]: `async fn` is not permitted in the 2015 edition +error[E0670]: `async fn` is not permitted in Rust 2015 --> $DIR/async-block-2015.rs:1:1 | LL | async fn foo() { @@ -11,7 +11,7 @@ error: expected identifier, found keyword `let` --> $DIR/async-block-2015.rs:11:9 | LL | let y = async { - | ----- `async` blocks are only allowed in edition 2018 or later + | ----- `async` blocks are only allowed in Rust 2018 or later LL | let x = 42; | ^^^ expected identifier, found keyword | @@ -22,7 +22,7 @@ error: expected identifier, found `42` --> $DIR/async-block-2015.rs:19:9 | LL | let z = async { - | ----- `async` blocks are only allowed in edition 2018 or later + | ----- `async` blocks are only allowed in Rust 2018 or later LL | 42 | ^^ expected identifier | @@ -33,7 +33,7 @@ error[E0422]: cannot find struct, variant or union type `async` in this scope --> $DIR/async-block-2015.rs:7:13 | LL | let x = async {}; - | ^^^^^ `async` blocks are only allowed in the 2018 edition + | ^^^^^ `async` blocks are only allowed in Rust 2018 or later error: aborting due to 4 previous errors diff --git a/src/test/ui/try-block/try-block-in-edition2015.stderr b/src/test/ui/try-block/try-block-in-edition2015.stderr index 78cdfb2cc7f04..0f3c14b1386e7 100644 --- a/src/test/ui/try-block/try-block-in-edition2015.stderr +++ b/src/test/ui/try-block/try-block-in-edition2015.stderr @@ -13,7 +13,7 @@ error[E0574]: expected struct, variant or union type, found macro `try` LL | let try_result: Option<_> = try { | ^^^ not a struct, variant or union type | - = note: if you want the `try` keyword, you need to be in the 2018 edition + = note: if you want the `try` keyword, you need Rust 2018 or later help: use `!` to invoke the macro | LL | let try_result: Option<_> = try! { From b3428fcbef7be6cfb1ccaf3716316350a42a8652 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 24 Dec 2020 16:48:41 +0100 Subject: [PATCH 21/22] Require `-Z unstable-options` for unstable editions. --- compiler/rustc_session/src/config.rs | 5 ++--- src/test/ui/hello2021.rs | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index c9ddcbdb5f5cc..62859f4bef430 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1308,12 +1308,11 @@ fn parse_crate_edition(matches: &getopts::Matches) -> Edition { None => DEFAULT_EDITION, }; - if !edition.is_stable() && !nightly_options::match_is_nightly_build(matches) { + if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) { early_error( ErrorOutputType::default(), &format!( - "edition {} is unstable and only \ - available for nightly builds of rustc.", + "edition {} is unstable and only available with -Z unstable-options.", edition, ), ) diff --git a/src/test/ui/hello2021.rs b/src/test/ui/hello2021.rs index 134d8af5bfb8a..738f151b0f60b 100644 --- a/src/test/ui/hello2021.rs +++ b/src/test/ui/hello2021.rs @@ -1,5 +1,6 @@ // run-pass // edition:2021 +// compile-flags: -Zunstable-options fn main() { println!("hello, 2021"); From cfee9fb07b958f401f49f21e27cd0889e1e58f4b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 24 Dec 2020 16:55:39 +0100 Subject: [PATCH 22/22] Enable OrPatNonterminalMode::TopPat in edition 2021. --- compiler/rustc_expand/src/mbe/macro_parser.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 3cf2d8f8ac1ef..5746bab4e04b8 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -421,8 +421,7 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { fn or_pat_mode(edition: Edition) -> OrPatNonterminalMode { match edition { Edition::Edition2015 | Edition::Edition2018 => OrPatNonterminalMode::NoTopAlt, - // FIXME(mark-i-m): uncomment this when edition 2021 machinery is added. - // Edition::Edition2021 => OrPatNonterminalMode::TopPat, + Edition::Edition2021 => OrPatNonterminalMode::TopPat, } }