From dec40530f71f38eaf0f853ddbbd80232ee3a5955 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 16 Nov 2021 13:12:38 -0600 Subject: [PATCH 1/9] Use get_diagnostic_name more --- .../rustc_borrowck/src/diagnostics/mod.rs | 35 +++++------ .../src/enum_intrinsics_non_enums.rs | 18 +++--- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/non_fmt_panic.rs | 19 ++++-- compiler/rustc_lint/src/noop_method_call.rs | 62 +++++++++---------- .../src/traits/error_reporting/mod.rs | 12 ++-- 6 files changed, 73 insertions(+), 74 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index a4df277a7b084..851c4ae3123c7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -742,15 +742,13 @@ impl BorrowedContentSource<'tcx> { BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(), BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(), BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(), - BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() { - ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { - "an `Rc`".to_string() - } - ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => { - "an `Arc`".to_string() - } - _ => format!("dereference of `{}`", ty), - }, + BorrowedContentSource::OverloadedDeref(ty) => ty + .ty_adt_def() + .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? { + name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)), + _ => None, + }) + .unwrap_or_else(|| format!("dereference of `{}`", ty)), BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty), } } @@ -774,15 +772,13 @@ impl BorrowedContentSource<'tcx> { BorrowedContentSource::DerefMutableRef => { bug!("describe_for_immutable_place: DerefMutableRef isn't immutable") } - BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() { - ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { - "an `Rc`".to_string() - } - ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => { - "an `Arc`".to_string() - } - _ => format!("a dereference of `{}`", ty), - }, + BorrowedContentSource::OverloadedDeref(ty) => ty + .ty_adt_def() + .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? { + name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)), + _ => None, + }) + .unwrap_or_else(|| format!("dereference of `{}`", ty)), BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty), } } @@ -966,8 +962,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { _ => None, }); let is_option_or_result = parent_self_ty.map_or(false, |def_id| { - tcx.is_diagnostic_item(sym::Option, def_id) - || tcx.is_diagnostic_item(sym::Result, def_id) + matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) }); FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result } }); diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs index 876245747f64a..65772d02376d4 100644 --- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs +++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs @@ -91,16 +91,14 @@ fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, sp impl<'tcx> LateLintPass<'tcx> for EnumIntrinsicsNonEnums { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { - if let hir::ExprKind::Call(ref func, ref args) = expr.kind { - if let hir::ExprKind::Path(ref qpath) = func.kind { - if let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() { - if cx.tcx.is_diagnostic_item(sym::mem_discriminant, def_id) { - enforce_mem_discriminant(cx, func, expr.span, args[0].span); - } else if cx.tcx.is_diagnostic_item(sym::mem_variant_count, def_id) { - enforce_mem_variant_count(cx, func, expr.span); - } - } - } + let hir::ExprKind::Call(func, args) = &expr.kind else { return }; + let hir::ExprKind::Path(qpath) = &func.kind else { return }; + let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() else { return }; + let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return }; + match name { + sym::mem_discriminant => enforce_mem_discriminant(cx, func, expr.span, args[0].span), + sym::mem_variant_count => enforce_mem_variant_count(cx, func, expr.span), + _ => {} } } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 507b4421fa160..7cc40cc60d9cd 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -33,6 +33,7 @@ #![cfg_attr(bootstrap, feature(format_args_capture))] #![feature(iter_order_by)] #![feature(iter_zip)] +#![feature(let_else)] #![feature(never_type)] #![feature(nll)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index f2ad72f97eca7..4a9b27e89b199 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -309,14 +309,21 @@ fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span, // Unwrap more levels of macro expansion, as panic_2015!() // was likely expanded from panic!() and possibly from // [debug_]assert!(). - for &i in - &[sym::std_panic_macro, sym::core_panic_macro, sym::assert_macro, sym::debug_assert_macro] - { + loop { let parent = expn.call_site.ctxt().outer_expn_data(); - if parent.macro_def_id.map_or(false, |id| cx.tcx.is_diagnostic_item(i, id)) { - expn = parent; - panic_macro = i; + let Some(id) = parent.macro_def_id else { break }; + let Some(name) = cx.tcx.get_diagnostic_name(id) else { break }; + if !matches!( + name, + sym::core_panic_macro + | sym::std_panic_macro + | sym::assert_macro + | sym::debug_assert_macro + ) { + break; } + expn = parent; + panic_macro = name; } let macro_symbol = diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index d2c970468abc7..a3a3cd0077dbe 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -75,38 +75,36 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { _ => return, }; // (Re)check that it implements the noop diagnostic. - for s in [sym::noop_method_clone, sym::noop_method_deref, sym::noop_method_borrow].iter() { - if cx.tcx.is_diagnostic_item(*s, i.def_id()) { - let method = &call.ident.name; - let receiver = &elements[0]; - let receiver_ty = cx.typeck_results().expr_ty(receiver); - let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); - if receiver_ty != expr_ty { - // This lint will only trigger if the receiver type and resulting expression \ - // type are the same, implying that the method call is unnecessary. - return; - } - let expr_span = expr.span; - let note = format!( - "the type `{:?}` which `{}` is being called on is the same as \ - the type returned from `{}`, so the method call does not do \ - anything and can be removed", - receiver_ty, method, method, - ); - - let span = expr_span.with_lo(receiver.span.hi()); - cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { - let method = &call.ident.name; - let message = format!( - "call to `.{}()` on a reference in this situation does nothing", - &method, - ); - lint.build(&message) - .span_label(span, "unnecessary method call") - .note(¬e) - .emit() - }); - } + let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return }; + if !matches!( + name, + sym::noop_method_borrow | sym::noop_method_clone | sym::noop_method_deref + ) { + return; } + let method = &call.ident.name; + let receiver = &elements[0]; + let receiver_ty = cx.typeck_results().expr_ty(receiver); + let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); + if receiver_ty != expr_ty { + // This lint will only trigger if the receiver type and resulting expression \ + // type are the same, implying that the method call is unnecessary. + return; + } + let expr_span = expr.span; + let note = format!( + "the type `{:?}` which `{}` is being called on is the same as \ + the type returned from `{}`, so the method call does not do \ + anything and can be removed", + receiver_ty, method, method, + ); + + let span = expr_span.with_lo(receiver.span.hi()); + cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { + let method = &call.ident.name; + let message = + format!("call to `.{}()` on a reference in this situation does nothing", &method,); + lint.build(&message).span_label(span, "unnecessary method call").note(¬e).emit() + }); } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index f8df0e2595973..6c41f530d7d6b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -539,11 +539,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // is otherwise overwhelming and unhelpful (see #85844 for an // example). - let trait_is_debug = - self.tcx.is_diagnostic_item(sym::Debug, trait_ref.def_id()); - let trait_is_display = - self.tcx.is_diagnostic_item(sym::Display, trait_ref.def_id()); - let in_std_macro = match obligation.cause.span.ctxt().outer_expn_data().macro_def_id { Some(macro_def_id) => { @@ -553,7 +548,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { None => false, }; - if in_std_macro && (trait_is_debug || trait_is_display) { + if in_std_macro + && matches!( + self.tcx.get_diagnostic_name(trait_ref.def_id()), + Some(sym::Debug | sym::Display) + ) + { err.emit(); return; } From 566ad8da451a85ba2e45126cb7ad64f55450e31d Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 19 Oct 2021 11:09:43 +0200 Subject: [PATCH 2/9] Update CoverageMappingFormat Support to Version6 Version 5 adds Branch Regions which are a prerequisite for branch coverage. Version 6 can use the zeroth filename as prefix for other relative files. --- .../src/coverageinfo/mapgen.rs | 20 ++++----- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 42 ++++++++++++++++++- .../rustc_codegen_ssa/src/coverageinfo/ffi.rs | 8 ++-- .../llvm-wrapper/CoverageMappingWrapper.cpp | 9 +++- compiler/rustc_middle/src/mir/coverage.rs | 6 +-- .../src/compiler-flags/instrument-coverage.md | 4 +- 6 files changed, 66 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 6830864ba04b4..67cd5363a7ba5 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -17,10 +17,10 @@ use tracing::debug; /// Generates and exports the Coverage Map. /// -/// This Coverage Map complies with Coverage Mapping Format version 4 (zero-based encoded as 3), -/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format) -/// and published in Rust's November 2020 fork of LLVM. This version is supported by the LLVM -/// coverage tools (`llvm-profdata` and `llvm-cov`) bundled with Rust's fork of LLVM. +/// This Coverage Map complies with Coverage Mapping Format version 5 (zero-based encoded as 4), +/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). +/// This version is supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`) +/// bundled with Rust's fork of LLVM. /// /// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with /// the same version. Clang's implementation of Coverage Map generation was referenced when @@ -30,12 +30,12 @@ use tracing::debug; pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { let tcx = cx.tcx; - // Ensure LLVM supports Coverage Map Version 4 (encoded as a zero-based value: 3). - // If not, the LLVM Version must be less than 11. - let version = coverageinfo::mapping_version(); - if version != 3 { - tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 11 or higher."); - } + // While our bundled LLVM might support Coverage Map Version 6 + // (encoded as a zero-based value: 5), we clamp that to Version 5, + // as Version 6 would require us to use the 0-th filename as a path prefix + // for all other relative paths, which we don't take advantage of right now. + let _version = coverageinfo::mapping_version(); + let version = 4; debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name()); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 1d255c0755980..badb386b6b1d5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -681,7 +681,7 @@ pub type InlineAsmDiagHandler = unsafe extern "C" fn(&SMDiagnostic, *const c_voi pub mod coverageinfo { use super::coverage_map; - /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222) + /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L209-L230) #[derive(Copy, Clone, Debug)] #[repr(C)] pub enum RegionKind { @@ -700,11 +700,16 @@ pub mod coverageinfo { /// A GapRegion is like a CodeRegion, but its count is only set as the /// line execution count when its the only region in the line. GapRegion = 3, + + /// A BranchRegion represents leaf-level boolean expressions and is + /// associated with two counters, each representing the number of times the + /// expression evaluates to true or false. + BranchRegion = 4, } /// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the /// coverage map, in accordance with the - /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). + /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). /// The struct composes fields representing the `Counter` type and value(s) (injected counter /// ID, or expression type and operands), the source file (an indirect index into a "filenames /// array", encoded separately), and source location (start and end positions of the represented @@ -717,6 +722,10 @@ pub mod coverageinfo { /// The counter type and type-dependent counter data, if any. counter: coverage_map::Counter, + /// If the `RegionKind` is a `BranchRegion`, this represents the counter + /// for the false branch of the region. + false_counter: coverage_map::Counter, + /// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the /// file_id is an index into a function-specific `virtual_file_mapping` array of indexes /// that, in turn, are used to look up the filename for this region. @@ -754,6 +763,7 @@ pub mod coverageinfo { ) -> Self { Self { counter, + false_counter: coverage_map::Counter::zero(), file_id, expanded_file_id: 0, start_line, @@ -764,6 +774,31 @@ pub mod coverageinfo { } } + // This function might be used in the future; the LLVM API is still evolving, as is coverage + // support. + #[allow(dead_code)] + crate fn branch_region( + counter: coverage_map::Counter, + false_counter: coverage_map::Counter, + file_id: u32, + start_line: u32, + start_col: u32, + end_line: u32, + end_col: u32, + ) -> Self { + Self { + counter, + false_counter, + file_id, + expanded_file_id: 0, + start_line, + start_col, + end_line, + end_col, + kind: RegionKind::BranchRegion, + } + } + // This function might be used in the future; the LLVM API is still evolving, as is coverage // support. #[allow(dead_code)] @@ -777,6 +812,7 @@ pub mod coverageinfo { ) -> Self { Self { counter: coverage_map::Counter::zero(), + false_counter: coverage_map::Counter::zero(), file_id, expanded_file_id, start_line, @@ -799,6 +835,7 @@ pub mod coverageinfo { ) -> Self { Self { counter: coverage_map::Counter::zero(), + false_counter: coverage_map::Counter::zero(), file_id, expanded_file_id: 0, start_line, @@ -822,6 +859,7 @@ pub mod coverageinfo { ) -> Self { Self { counter, + false_counter: coverage_map::Counter::zero(), file_id, expanded_file_id: 0, start_line, diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs index 962c01c2ee7a6..e288760a02b18 100644 --- a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs @@ -1,6 +1,6 @@ use rustc_middle::mir::coverage::{CounterValueReference, MappedExpressionIndex}; -/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222) +/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L95) #[derive(Copy, Clone, Debug)] #[repr(C)] pub enum CounterKind { @@ -17,7 +17,7 @@ pub enum CounterKind { /// `instrprof.increment()`) /// * For `CounterKind::Expression`, `id` is the index into the coverage map's array of /// counter expressions. -/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L99-L100) +/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L102-L103) /// Important: The Rust struct layout (order and types of fields) must match its C++ counterpart. #[derive(Copy, Clone, Debug)] #[repr(C)] @@ -59,7 +59,7 @@ impl Counter { } } -/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L147) +/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L150) #[derive(Copy, Clone, Debug)] #[repr(C)] pub enum ExprKind { @@ -67,7 +67,7 @@ pub enum ExprKind { Add = 1, } -/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L148-L149) +/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L151-L152) /// Important: The Rust struct layout (order and types of fields) must match its C++ /// counterpart. #[derive(Copy, Clone, Debug)] diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 8cd2bd12450e3..154f554d607df 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -10,6 +10,7 @@ using namespace llvm; struct LLVMRustCounterMappingRegion { coverage::Counter Count; + coverage::Counter FalseCount; uint32_t FileID; uint32_t ExpandedFileID; uint32_t LineStart; @@ -53,7 +54,7 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer( MappingRegions.reserve(NumMappingRegions); for (const auto &Region : makeArrayRef(RustMappingRegions, NumMappingRegions)) { MappingRegions.emplace_back( - Region.Count, Region.FileID, Region.ExpandedFileID, + Region.Count, Region.FalseCount, Region.FileID, Region.ExpandedFileID, Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd, Region.Kind); } @@ -108,5 +109,9 @@ extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) { } extern "C" uint32_t LLVMRustCoverageMappingVersion() { - return coverage::CovMapVersion::Version4; +#if LLVM_VERSION_GE(13, 0) + return coverage::CovMapVersion::Version6; +#else + return coverage::CovMapVersion::Version5; +#endif } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index ddb1a84fe7bdf..640d3a5a02b0f 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -21,9 +21,9 @@ rustc_index::newtype_index! { impl ExpressionOperandId { /// An expression operand for a "zero counter", as described in the following references: /// - /// * - /// * - /// * + /// * + /// * + /// * /// /// This operand can be used to count two or more separate code regions with a single counter, /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for diff --git a/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md b/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md index f7c2a26f01817..0424ed08dafbe 100644 --- a/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md +++ b/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md @@ -20,7 +20,7 @@ This document describes how to enable and use the LLVM instrumentation-based cov When `-Z instrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by: - Automatically injecting calls to an LLVM intrinsic ([`llvm.instrprof.increment`]), at functions and branches in compiled code, to increment counters when conditional sections of code are executed. -- Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 4_, supported _only_ in LLVM 11 and up), to define the code regions (start and end positions in the source code) being counted. +- Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 5_, supported _only_ in LLVM 12 and up), to define the code regions (start and end positions in the source code) being counted. When running a coverage-instrumented program, the counter values are written to a `profraw` file at program termination. LLVM bundles tools that read the counter results, combine those results with the coverage map (embedded in the program binary), and generate coverage reports in multiple formats. @@ -123,7 +123,7 @@ If `LLVM_PROFILE_FILE` contains a path to a non-existent directory, the missing ## Installing LLVM coverage tools -LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 11 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.): +LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 12 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.): - The LLVM tools may be installed (or installable) directly to your OS (such as via `apt-get`, for Linux). - If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`. From d6e34ad108dc998e9f9d872e807e221c0df4f24b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 15 Jul 2021 08:36:19 -0700 Subject: [PATCH 3/9] When recovering from a `:` in a pattern, use adequate AST pattern --- compiler/rustc_parse/src/parser/pat.rs | 103 +++++++++++++++--- .../issues/issue-87086-colon-path-sep.rs | 31 ++++-- .../issues/issue-87086-colon-path-sep.stderr | 60 ++++++---- 3 files changed, 150 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index bb3947bb47a25..c1f5c569cf09f 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -3,13 +3,17 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; use rustc_ast::token; -use rustc_ast::{self as ast, AttrVec, Attribute, MacCall, Pat, PatField, PatKind, RangeEnd}; -use rustc_ast::{BindingMode, Expr, ExprKind, Mutability, Path, QSelf, RangeSyntax}; +use rustc_ast::{ + self as ast, AttrVec, Attribute, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat, + PatField, PatKind, Path, PathSegment, QSelf, RangeEnd, RangeSyntax, +}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult}; use rustc_span::source_map::{respan, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; +use std::mem::take; + type Expected = Option<&'static str>; /// `Expected` for function and lambda parameter patterns. @@ -101,11 +105,8 @@ impl<'a> Parser<'a> { let mut first_pat = first_pat; if let (RecoverColon::Yes, token::Colon) = (ra, &self.token.kind) { - if matches!( - first_pat.kind, - PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) - | PatKind::Path(..) - ) && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) + if matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) + && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) { // The pattern looks like it might be a path with a `::` -> `:` typo: // `match foo { bar:baz => {} }` @@ -126,17 +127,87 @@ impl<'a> Parser<'a> { err.cancel(); *self = snapshot; } - Ok(pat) => { + Ok(mut pat) => { // We've parsed the rest of the pattern. - err.span_suggestion( - span, - "maybe write a path separator here", - "::".to_string(), - Applicability::MachineApplicable, - ); + let new_span = first_pat.span.to(pat.span); + let mut show_sugg = false; + match &mut pat.kind { + PatKind::Struct(qself @ None, path, ..) + | PatKind::TupleStruct(qself @ None, path, _) + | PatKind::Path(qself @ None, path) => { + match &first_pat.kind { + PatKind::Ident(_, ident, _) => { + path.segments.insert( + 0, + PathSegment::from_ident(ident.clone()), + ); + path.span = new_span; + show_sugg = true; + first_pat = pat; + } + PatKind::Path(old_qself, old_path) => { + path.segments = old_path + .segments + .iter() + .cloned() + .chain(take(&mut path.segments)) + .collect(); + path.span = new_span; + *qself = old_qself.clone(); + first_pat = pat; + show_sugg = true; + } + _ => {} + } + } + PatKind::Ident( + BindingMode::ByValue(Mutability::Not), + ident, + None, + ) => match &first_pat.kind { + PatKind::Ident(_, old_ident, _) => { + let path = PatKind::Path( + None, + Path { + span: new_span, + segments: vec![ + PathSegment::from_ident( + old_ident.clone(), + ), + PathSegment::from_ident(ident.clone()), + ], + tokens: None, + }, + ); + first_pat = self.mk_pat(new_span, path); + show_sugg = true; + } + PatKind::Path(old_qself, old_path) => { + let mut segments = old_path.segments.clone(); + segments + .push(PathSegment::from_ident(ident.clone())); + let path = PatKind::Path( + old_qself.clone(), + Path { span: new_span, segments, tokens: None }, + ); + first_pat = self.mk_pat(new_span, path); + show_sugg = true; + } + _ => {} + }, + _ => {} + } + if show_sugg { + err.span_suggestion( + span, + "maybe write a path separator here", + "::".to_string(), + Applicability::MachineApplicable, + ); + } else { + first_pat = self.mk_pat(new_span, PatKind::Wild); + } err.emit(); - first_pat = - self.mk_pat(first_pat.span.to(pat.span), PatKind::Wild); } } } diff --git a/src/test/ui/parser/issues/issue-87086-colon-path-sep.rs b/src/test/ui/parser/issues/issue-87086-colon-path-sep.rs index 4ee0b2054ff77..0b7b67496d6f3 100644 --- a/src/test/ui/parser/issues/issue-87086-colon-path-sep.rs +++ b/src/test/ui/parser/issues/issue-87086-colon-path-sep.rs @@ -1,11 +1,15 @@ // Tests that a suggestion is issued if the user wrote a colon instead of // a path separator in a match arm. -enum Foo { - Bar, - Baz, +mod qux { + pub enum Foo { + Bar, + Baz, + } } +use qux::Foo; + fn f() -> Foo { Foo::Bar } fn g1() { @@ -16,24 +20,24 @@ fn g1() { _ => {} } match f() { - Foo::Bar:Baz => {} + qux::Foo:Bar => {} //~^ ERROR: expected one of //~| HELP: maybe write a path separator here _ => {} } match f() { - Foo:Bar::Baz => {} + qux:Foo::Baz => {} //~^ ERROR: expected one of //~| HELP: maybe write a path separator here _ => {} } match f() { - Foo: Bar::Baz if true => {} + qux: Foo::Baz if true => {} //~^ ERROR: expected one of //~| HELP: maybe write a path separator here _ => {} } - if let Bar:Baz = f() { + if let Foo:Bar = f() { //~^ ERROR: expected one of //~| HELP: maybe write a path separator here } @@ -41,16 +45,18 @@ fn g1() { fn g1_neg() { match f() { - ref Foo: Bar::Baz => {} + ref qux: Foo::Baz => {} //~^ ERROR: expected one of + //~| HELP: maybe write a path separator here _ => {} } } fn g2_neg() { match f() { - mut Foo: Bar::Baz => {} + mut qux: Foo::Baz => {} //~^ ERROR: expected one of + //~| HELP: maybe write a path separator here _ => {} } } @@ -62,5 +68,12 @@ fn main() { Foo:Bar::Baz => {} //~^ ERROR: expected one of //~| HELP: maybe write a path separator here + //~| ERROR: failed to resolve: `Bar` is a variant, not a module + } + match myfoo { + Foo::Bar => {} + Foo:Bar => {} + //~^ ERROR: expected one of + //~| HELP: maybe write a path separator here } } diff --git a/src/test/ui/parser/issues/issue-87086-colon-path-sep.stderr b/src/test/ui/parser/issues/issue-87086-colon-path-sep.stderr index 8f93661a62646..2050a16beb349 100644 --- a/src/test/ui/parser/issues/issue-87086-colon-path-sep.stderr +++ b/src/test/ui/parser/issues/issue-87086-colon-path-sep.stderr @@ -1,5 +1,5 @@ error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:13:12 + --> $DIR/issue-87086-colon-path-sep.rs:17:12 | LL | Foo:Bar => {} | ^ @@ -8,55 +8,61 @@ LL | Foo:Bar => {} | help: maybe write a path separator here: `::` error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:19:17 + --> $DIR/issue-87086-colon-path-sep.rs:23:17 | -LL | Foo::Bar:Baz => {} +LL | qux::Foo:Bar => {} | ^ | | | expected one of 8 possible tokens | help: maybe write a path separator here: `::` error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:25:12 + --> $DIR/issue-87086-colon-path-sep.rs:29:12 | -LL | Foo:Bar::Baz => {} +LL | qux:Foo::Baz => {} | ^ | | | expected one of `@` or `|` | help: maybe write a path separator here: `::` error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:31:12 + --> $DIR/issue-87086-colon-path-sep.rs:35:12 | -LL | Foo: Bar::Baz if true => {} +LL | qux: Foo::Baz if true => {} | ^ | | | expected one of `@` or `|` | help: maybe write a path separator here: `::` error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:36:15 + --> $DIR/issue-87086-colon-path-sep.rs:40:15 | -LL | if let Bar:Baz = f() { +LL | if let Foo:Bar = f() { | ^ | | | expected one of `@` or `|` | help: maybe write a path separator here: `::` -error: expected one of `=>`, `@`, `if`, or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:44:16 +error: expected one of `@` or `|`, found `:` + --> $DIR/issue-87086-colon-path-sep.rs:48:16 | -LL | ref Foo: Bar::Baz => {} - | ^ expected one of `=>`, `@`, `if`, or `|` +LL | ref qux: Foo::Baz => {} + | ^ + | | + | expected one of `@` or `|` + | help: maybe write a path separator here: `::` -error: expected one of `=>`, `@`, `if`, or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:52:16 +error: expected one of `@` or `|`, found `:` + --> $DIR/issue-87086-colon-path-sep.rs:57:16 | -LL | mut Foo: Bar::Baz => {} - | ^ expected one of `=>`, `@`, `if`, or `|` +LL | mut qux: Foo::Baz => {} + | ^ + | | + | expected one of `@` or `|` + | help: maybe write a path separator here: `::` error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:62:12 + --> $DIR/issue-87086-colon-path-sep.rs:68:12 | LL | Foo:Bar::Baz => {} | ^ @@ -64,5 +70,21 @@ LL | Foo:Bar::Baz => {} | expected one of `@` or `|` | help: maybe write a path separator here: `::` -error: aborting due to 8 previous errors +error: expected one of `@` or `|`, found `:` + --> $DIR/issue-87086-colon-path-sep.rs:75:12 + | +LL | Foo:Bar => {} + | ^ + | | + | expected one of `@` or `|` + | help: maybe write a path separator here: `::` + +error[E0433]: failed to resolve: `Bar` is a variant, not a module + --> $DIR/issue-87086-colon-path-sep.rs:68:13 + | +LL | Foo:Bar::Baz => {} + | ^^^ `Bar` is a variant, not a module + +error: aborting due to 10 previous errors +For more information about this error, try `rustc --explain E0433`. From 6dfed31c4313c1eee7b1aa155e0761c5cdf7f128 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Sat, 27 Nov 2021 18:42:49 +0100 Subject: [PATCH 4/9] Improve error message for `E0659` if the source is not available --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 2e4cb4ff7270d..6a13627a56314 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1178,7 +1178,7 @@ impl<'a> Resolver<'a> { fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String { let res = b.res(); - if b.span.is_dummy() { + if b.span.is_dummy() || self.session.source_map().span_to_snippet(b.span).is_err() { // These already contain the "built-in" prefix or look bad with it. let add_built_in = !matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod); From 2e8358e1ab933c6599b40294c0b33a1a17d19a23 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Sun, 28 Nov 2021 23:31:32 -0500 Subject: [PATCH 5/9] add `Option::inspect` and `Result::{inspect, inspect_err}` --- library/core/src/option.rs | 25 ++++++++++++++++++++ library/core/src/result.rs | 47 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index baf9948857bbe..4eeb5e4394386 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -848,6 +848,31 @@ impl Option { } } + /// Calls the provided closure with a reference to the contained value (if [`Some`]). + /// + /// # Examples + /// + /// ``` + /// #![feature(result_option_inspect)] + /// + /// let v = vec![1, 2, 3, 4, 5]; + /// + /// // prints "got: 4" + /// let x: Option<&usize> = v.get(3).inspect(|x| println!("got: {}", x)); + /// + /// // prints nothing + /// let x: Option<&usize> = v.get(5).inspect(|x| println!("got: {}", x)); + /// ``` + #[inline] + #[unstable(feature = "result_option_inspect", issue = "91345")] + pub fn inspect(self, f: F) -> Self { + if let Some(ref x) = self { + f(x); + } + + self + } + /// Returns the provided default result (if none), /// or applies a function to the contained value (if any). /// diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 8fec2e928aae2..a494c089f68ba 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -854,6 +854,53 @@ impl Result { } } + /// Calls the provided closure with a reference to the contained value (if [`Ok`]). + /// + /// # Examples + /// + /// ``` + /// #![feature(result_option_inspect)] + /// + /// let x: u8 = "4" + /// .parse::() + /// .inspect(|x| println!("original: {}", x)) + /// .map(|x| x.pow(3)) + /// .expect("failed to parse number"); + /// ``` + #[inline] + #[unstable(feature = "result_option_inspect", issue = "91345")] + pub fn inspect(self, f: F) -> Self { + if let Ok(ref t) = self { + f(t); + } + + self + } + + /// Calls the provided closure with a reference to the contained error (if [`Err`]). + /// + /// # Examples + /// + /// ``` + /// #![feature(result_option_inspect)] + /// + /// use std::{fs, io}; + /// + /// fn read() -> io::Result { + /// fs::read_to_string("address.txt") + /// .inspect_err(|e| eprintln!("failed to read file: {}", e)) + /// } + /// ``` + #[inline] + #[unstable(feature = "result_option_inspect", issue = "91345")] + pub fn inspect_err(self, f: F) -> Self { + if let Err(ref e) = self { + f(e); + } + + self + } + ///////////////////////////////////////////////////////////////////////// // Iterator constructors ///////////////////////////////////////////////////////////////////////// From c02710530c0005a30759e170be023cc167c6cd67 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Sun, 21 Nov 2021 04:56:32 +0000 Subject: [PATCH 6/9] review comments: clean up --- .../rustc_parse/src/parser/diagnostics.rs | 182 +++++++++++++++++- compiler/rustc_parse/src/parser/pat.rs | 176 +---------------- 2 files changed, 185 insertions(+), 173 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ce39d07656f2a..55af2c9ddd32f 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1,6 +1,9 @@ +use super::pat::Expected; use super::ty::AllowPlus; -use super::TokenType; -use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType}; +use super::{ + BlockMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions, SemiColonMode, SeqSep, + TokenExpectType, TokenType, +}; use rustc_ast as ast; use rustc_ast::ptr::P; @@ -19,6 +22,8 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, Ident}; use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP}; +use std::mem::take; + use tracing::{debug, trace}; const TURBOFISH_SUGGESTION_STR: &str = @@ -2075,4 +2080,177 @@ impl<'a> Parser<'a> { ); err } + + /// Some special error handling for the "top-level" patterns in a match arm, + /// `for` loop, `let`, &c. (in contrast to subpatterns within such). + crate fn maybe_recover_colon_colon_in_pat_typo( + &mut self, + mut first_pat: P, + ra: RecoverColon, + expected: Expected, + ) -> P { + if RecoverColon::Yes != ra || token::Colon != self.token.kind { + return first_pat; + } + if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) + || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) + { + return first_pat; + } + // The pattern looks like it might be a path with a `::` -> `:` typo: + // `match foo { bar:baz => {} }` + let span = self.token.span; + // We only emit "unexpected `:`" error here if we can successfully parse the + // whole pattern correctly in that case. + let snapshot = self.clone(); + + // Create error for "unexpected `:`". + match self.expected_one_of_not_found(&[], &[]) { + Err(mut err) => { + self.bump(); // Skip the `:`. + match self.parse_pat_no_top_alt(expected) { + Err(mut inner_err) => { + // Carry on as if we had not done anything, callers will emit a + // reasonable error. + inner_err.cancel(); + err.cancel(); + *self = snapshot; + } + Ok(mut pat) => { + // We've parsed the rest of the pattern. + let new_span = first_pat.span.to(pat.span); + let mut show_sugg = false; + // Try to construct a recovered pattern. + match &mut pat.kind { + PatKind::Struct(qself @ None, path, ..) + | PatKind::TupleStruct(qself @ None, path, _) + | PatKind::Path(qself @ None, path) => match &first_pat.kind { + PatKind::Ident(_, ident, _) => { + path.segments.insert(0, PathSegment::from_ident(ident.clone())); + path.span = new_span; + show_sugg = true; + first_pat = pat; + } + PatKind::Path(old_qself, old_path) => { + path.segments = old_path + .segments + .iter() + .cloned() + .chain(take(&mut path.segments)) + .collect(); + path.span = new_span; + *qself = old_qself.clone(); + first_pat = pat; + show_sugg = true; + } + _ => {} + }, + PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => { + match &first_pat.kind { + PatKind::Ident(_, old_ident, _) => { + let path = PatKind::Path( + None, + Path { + span: new_span, + segments: vec![ + PathSegment::from_ident(old_ident.clone()), + PathSegment::from_ident(ident.clone()), + ], + tokens: None, + }, + ); + first_pat = self.mk_pat(new_span, path); + show_sugg = true; + } + PatKind::Path(old_qself, old_path) => { + let mut segments = old_path.segments.clone(); + segments.push(PathSegment::from_ident(ident.clone())); + let path = PatKind::Path( + old_qself.clone(), + Path { span: new_span, segments, tokens: None }, + ); + first_pat = self.mk_pat(new_span, path); + show_sugg = true; + } + _ => {} + } + } + _ => {} + } + if show_sugg { + err.span_suggestion( + span, + "maybe write a path separator here", + "::".to_string(), + Applicability::MaybeIncorrect, + ); + } else { + first_pat = self.mk_pat(new_span, PatKind::Wild); + } + err.emit(); + } + } + } + _ => { + // Carry on as if we had not done anything. This should be unreachable. + *self = snapshot; + } + }; + first_pat + } + + /// Some special error handling for the "top-level" patterns in a match arm, + /// `for` loop, `let`, &c. (in contrast to subpatterns within such). + crate fn maybe_recover_unexpected_comma( + &mut self, + lo: Span, + rc: RecoverComma, + ) -> PResult<'a, ()> { + if rc == RecoverComma::No || self.token != token::Comma { + return Ok(()); + } + + // An unexpected comma after a top-level pattern is a clue that the + // user (perhaps more accustomed to some other language) forgot the + // parentheses in what should have been a tuple pattern; return a + // suggestion-enhanced error here rather than choking on the comma later. + let comma_span = self.token.span; + self.bump(); + if let Err(mut err) = self.skip_pat_list() { + // We didn't expect this to work anyway; we just wanted to advance to the + // end of the comma-sequence so we know the span to suggest parenthesizing. + err.cancel(); + } + let seq_span = lo.to(self.prev_token.span); + let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); + if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { + const MSG: &str = "try adding parentheses to match on a tuple..."; + + err.span_suggestion( + seq_span, + MSG, + format!("({})", seq_snippet), + Applicability::MachineApplicable, + ); + err.span_suggestion( + seq_span, + "...or a vertical bar to match on multiple alternatives", + seq_snippet.replace(",", " |"), + Applicability::MachineApplicable, + ); + } + Err(err) + } + + /// Parse and throw away a parenthesized comma separated + /// sequence of patterns until `)` is reached. + fn skip_pat_list(&mut self) -> PResult<'a, ()> { + while !self.check(&token::CloseDelim(token::Paren)) { + self.parse_pat_no_top_alt(None)?; + if !self.eat(&token::Comma) { + return Ok(()); + } + } + Ok(()) + } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index c1f5c569cf09f..ac3123c40e3d9 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -5,16 +5,14 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::{ self as ast, AttrVec, Attribute, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat, - PatField, PatKind, Path, PathSegment, QSelf, RangeEnd, RangeSyntax, + PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax, }; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult}; use rustc_span::source_map::{respan, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; -use std::mem::take; - -type Expected = Option<&'static str>; +pub(super) type Expected = Option<&'static str>; /// `Expected` for function and lambda parameter patterns. pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); @@ -102,122 +100,9 @@ impl<'a> Parser<'a> { // If we parsed a leading `|` which should be gated, // then we should really gate the leading `|`. // This complicated procedure is done purely for diagnostics UX. - let mut first_pat = first_pat; - if let (RecoverColon::Yes, token::Colon) = (ra, &self.token.kind) { - if matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) - && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) - { - // The pattern looks like it might be a path with a `::` -> `:` typo: - // `match foo { bar:baz => {} }` - let span = self.token.span; - // We only emit "unexpected `:`" error here if we can successfully parse the - // whole pattern correctly in that case. - let snapshot = self.clone(); - - // Create error for "unexpected `:`". - match self.expected_one_of_not_found(&[], &[]) { - Err(mut err) => { - self.bump(); // Skip the `:`. - match self.parse_pat_no_top_alt(expected) { - Err(mut inner_err) => { - // Carry on as if we had not done anything, callers will emit a - // reasonable error. - inner_err.cancel(); - err.cancel(); - *self = snapshot; - } - Ok(mut pat) => { - // We've parsed the rest of the pattern. - let new_span = first_pat.span.to(pat.span); - let mut show_sugg = false; - match &mut pat.kind { - PatKind::Struct(qself @ None, path, ..) - | PatKind::TupleStruct(qself @ None, path, _) - | PatKind::Path(qself @ None, path) => { - match &first_pat.kind { - PatKind::Ident(_, ident, _) => { - path.segments.insert( - 0, - PathSegment::from_ident(ident.clone()), - ); - path.span = new_span; - show_sugg = true; - first_pat = pat; - } - PatKind::Path(old_qself, old_path) => { - path.segments = old_path - .segments - .iter() - .cloned() - .chain(take(&mut path.segments)) - .collect(); - path.span = new_span; - *qself = old_qself.clone(); - first_pat = pat; - show_sugg = true; - } - _ => {} - } - } - PatKind::Ident( - BindingMode::ByValue(Mutability::Not), - ident, - None, - ) => match &first_pat.kind { - PatKind::Ident(_, old_ident, _) => { - let path = PatKind::Path( - None, - Path { - span: new_span, - segments: vec![ - PathSegment::from_ident( - old_ident.clone(), - ), - PathSegment::from_ident(ident.clone()), - ], - tokens: None, - }, - ); - first_pat = self.mk_pat(new_span, path); - show_sugg = true; - } - PatKind::Path(old_qself, old_path) => { - let mut segments = old_path.segments.clone(); - segments - .push(PathSegment::from_ident(ident.clone())); - let path = PatKind::Path( - old_qself.clone(), - Path { span: new_span, segments, tokens: None }, - ); - first_pat = self.mk_pat(new_span, path); - show_sugg = true; - } - _ => {} - }, - _ => {} - } - if show_sugg { - err.span_suggestion( - span, - "maybe write a path separator here", - "::".to_string(), - Applicability::MachineApplicable, - ); - } else { - first_pat = self.mk_pat(new_span, PatKind::Wild); - } - err.emit(); - } - } - } - _ => { - // Carry on as if we had not done anything. This should be unreachable. - *self = snapshot; - } - }; - } - } + // Check if the user wrote `foo:bar` instead of `foo::bar`. + let first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, ra, expected); if let Some(leading_vert_span) = leading_vert_span { // If there was a leading vert, treat this as an or-pattern. This improves @@ -392,57 +277,6 @@ impl<'a> Parser<'a> { err.emit(); } - /// Some special error handling for the "top-level" patterns in a match arm, - /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - fn maybe_recover_unexpected_comma(&mut self, lo: Span, rc: RecoverComma) -> PResult<'a, ()> { - if rc == RecoverComma::No || self.token != token::Comma { - return Ok(()); - } - - // An unexpected comma after a top-level pattern is a clue that the - // user (perhaps more accustomed to some other language) forgot the - // parentheses in what should have been a tuple pattern; return a - // suggestion-enhanced error here rather than choking on the comma later. - let comma_span = self.token.span; - self.bump(); - if let Err(mut err) = self.skip_pat_list() { - // We didn't expect this to work anyway; we just wanted to advance to the - // end of the comma-sequence so we know the span to suggest parenthesizing. - err.cancel(); - } - let seq_span = lo.to(self.prev_token.span); - let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); - if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { - const MSG: &str = "try adding parentheses to match on a tuple..."; - - err.span_suggestion( - seq_span, - MSG, - format!("({})", seq_snippet), - Applicability::MachineApplicable, - ); - err.span_suggestion( - seq_span, - "...or a vertical bar to match on multiple alternatives", - seq_snippet.replace(",", " |"), - Applicability::MachineApplicable, - ); - } - Err(err) - } - - /// Parse and throw away a parenthesized comma separated - /// sequence of patterns until `)` is reached. - fn skip_pat_list(&mut self) -> PResult<'a, ()> { - while !self.check(&token::CloseDelim(token::Paren)) { - self.parse_pat_no_top_alt(None)?; - if !self.eat(&token::Comma) { - return Ok(()); - } - } - Ok(()) - } - /// A `|` or possibly `||` token shouldn't be here. Ban it. fn ban_illegal_vert(&mut self, lo: Option, pos: &str, ctx: &str) { let span = self.token.span; @@ -1239,7 +1073,7 @@ impl<'a> Parser<'a> { self.mk_pat(span, PatKind::Ident(bm, ident, None)) } - fn mk_pat(&self, span: Span, kind: PatKind) -> P { + pub(super) fn mk_pat(&self, span: Span, kind: PatKind) -> P { P(Pat { kind, span, id: ast::DUMMY_NODE_ID, tokens: None }) } } From abd704b8446ee984c3d246841384cea49e92575f Mon Sep 17 00:00:00 2001 From: Lucas Kent Date: Sat, 20 Nov 2021 23:13:40 +1100 Subject: [PATCH 7/9] Remove all migrate.nll.stderr files --- ...rowck-migrate-scans-parents.migrate.stderr | 12 +++--- ...-borrowck-migrate-scans-parents.nll.stderr | 12 +++--- ...ue-55492-borrowck-migrate-scans-parents.rs | 4 +- ...776-borrowck-scans-children.migrate.stderr | 32 --------------- src/test/ui/error-codes/E0161.edition.stderr | 2 +- src/test/ui/error-codes/E0161.migrate.stderr | 2 +- src/test/ui/error-codes/E0161.nll.stderr | 2 +- src/test/ui/error-codes/E0161.rs | 7 +++- src/test/ui/error-codes/E0161.zflags.stderr | 2 +- .../issue-71955.migrate.stderr | 20 +++++----- .../issue-71955.nll.stderr | 2 +- .../normalize-under-binder/issue-71955.rs | 5 +++ src/test/ui/hrtb/issue-30786.migrate.stderr | 28 ++++++------- src/test/ui/hrtb/issue-30786.nll.stderr | 28 ++++++------- src/test/ui/hrtb/issue-30786.rs | 3 +- ...rait-outlives-container.migrate.nll.stderr | 15 ------- ...pertrait-outlives-container.migrate.stderr | 6 +-- ...n-supertrait-outlives-container.nll.stderr | 2 +- ...c-type-in-supertrait-outlives-container.rs | 5 +++ ...-region-ordering-caller.migrate.nll.stderr | 39 ------------------- ...free-region-ordering-caller.migrate.stderr | 18 ++++----- ...ons-free-region-ordering-caller.nll.stderr | 6 +-- .../regions-free-region-ordering-caller.rs | 5 +++ ...ojection-container-hrtb.migrate.nll.stderr | 28 ------------- ...s-projection-container-hrtb.migrate.stderr | 12 +++--- ...lives-projection-container-hrtb.nll.stderr | 4 +- ...ions-outlives-projection-container-hrtb.rs | 5 +++ ...projection-container-wc.migrate.nll.stderr | 15 ------- ...ves-projection-container-wc.migrate.stderr | 6 +-- ...utlives-projection-container-wc.nll.stderr | 2 +- ...egions-outlives-projection-container-wc.rs | 5 +++ 31 files changed, 115 insertions(+), 219 deletions(-) delete mode 100644 src/test/ui/borrowck/issue-58776-borrowck-scans-children.migrate.stderr delete mode 100644 src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr delete mode 100644 src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr delete mode 100644 src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr delete mode 100644 src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr index 1cdcc18632c62..10400cff5e51c 100644 --- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr +++ b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr @@ -1,5 +1,5 @@ error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:46 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:17:46 | LL | pub fn e(x: &'static mut isize) { | - help: consider changing this to be mutable: `mut x` @@ -8,7 +8,7 @@ LL | let mut c1 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:50 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:28:50 | LL | pub fn ee(x: &'static mut isize) { | - help: consider changing this to be mutable: `mut x` @@ -17,7 +17,7 @@ LL | let mut c2 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:40:14 | LL | pub fn capture_assign_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -25,7 +25,7 @@ LL | || { x = (1,); }; | ^^^^^^^^ cannot assign error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:47:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:45:14 | LL | pub fn capture_assign_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -33,7 +33,7 @@ LL | || { x.0 = 1; }; | ^^^^^^^ cannot assign error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:52:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:50:14 | LL | pub fn capture_reborrow_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -41,7 +41,7 @@ LL | || { &mut x; }; | ^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:57:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:14 | LL | pub fn capture_reborrow_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr index 1cdcc18632c62..10400cff5e51c 100644 --- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr +++ b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr @@ -1,5 +1,5 @@ error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:46 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:17:46 | LL | pub fn e(x: &'static mut isize) { | - help: consider changing this to be mutable: `mut x` @@ -8,7 +8,7 @@ LL | let mut c1 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:50 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:28:50 | LL | pub fn ee(x: &'static mut isize) { | - help: consider changing this to be mutable: `mut x` @@ -17,7 +17,7 @@ LL | let mut c2 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:40:14 | LL | pub fn capture_assign_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -25,7 +25,7 @@ LL | || { x = (1,); }; | ^^^^^^^^ cannot assign error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:47:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:45:14 | LL | pub fn capture_assign_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -33,7 +33,7 @@ LL | || { x.0 = 1; }; | ^^^^^^^ cannot assign error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:52:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:50:14 | LL | pub fn capture_reborrow_whole(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` @@ -41,7 +41,7 @@ LL | || { &mut x; }; | ^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable - --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:57:14 + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:14 | LL | pub fn capture_reborrow_part(x: (i32,)) { | - help: consider changing this to be mutable: `mut x` diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs index 751a911a6bb86..fe7ed8ed3fa24 100644 --- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs +++ b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs @@ -3,15 +3,13 @@ // looks at some parent. // revisions: migrate nll +//[nll]compile-flags: -Z borrowck=mir // Since we are testing nll (and migration) explicitly as a separate // revisions, don't worry about the --compare-mode=nll on this test. // ignore-compare-mode-nll -//[nll]compile-flags: -Z borrowck=mir - - // transcribed from borrowck-closures-unique.rs mod borrowck_closures_unique { pub fn e(x: &'static mut isize) { diff --git a/src/test/ui/borrowck/issue-58776-borrowck-scans-children.migrate.stderr b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.migrate.stderr deleted file mode 100644 index efd4e1a1716d3..0000000000000 --- a/src/test/ui/borrowck/issue-58776-borrowck-scans-children.migrate.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error[E0506]: cannot assign to `greeting` because it is borrowed - --> $DIR/issue-58776-borrowck-scans-children.rs:11:5 - | -LL | let res = (|| (|| &greeting)())(); - | -- -------- borrow occurs due to use in closure - | | - | borrow of `greeting` occurs here -LL | -LL | greeting = "DEALLOCATED".to_string(); - | ^^^^^^^^ assignment to borrowed `greeting` occurs here -... -LL | println!("thread result: {:?}", res); - | --- borrow later used here - -error[E0505]: cannot move out of `greeting` because it is borrowed - --> $DIR/issue-58776-borrowck-scans-children.rs:14:10 - | -LL | let res = (|| (|| &greeting)())(); - | -- -------- borrow occurs due to use in closure - | | - | borrow of `greeting` occurs here -... -LL | drop(greeting); - | ^^^^^^^^ move out of `greeting` occurs here -... -LL | println!("thread result: {:?}", res); - | --- borrow later used here - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0505, E0506. -For more information about an error, try `rustc --explain E0505`. diff --git a/src/test/ui/error-codes/E0161.edition.stderr b/src/test/ui/error-codes/E0161.edition.stderr index 1060675cd45f4..fb082bc1eabcf 100644 --- a/src/test/ui/error-codes/E0161.edition.stderr +++ b/src/test/ui/error-codes/E0161.edition.stderr @@ -1,5 +1,5 @@ error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined - --> $DIR/E0161.rs:29:5 + --> $DIR/E0161.rs:32:5 | LL | x.f(); | ^^^^^ diff --git a/src/test/ui/error-codes/E0161.migrate.stderr b/src/test/ui/error-codes/E0161.migrate.stderr index 1060675cd45f4..fb082bc1eabcf 100644 --- a/src/test/ui/error-codes/E0161.migrate.stderr +++ b/src/test/ui/error-codes/E0161.migrate.stderr @@ -1,5 +1,5 @@ error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined - --> $DIR/E0161.rs:29:5 + --> $DIR/E0161.rs:32:5 | LL | x.f(); | ^^^^^ diff --git a/src/test/ui/error-codes/E0161.nll.stderr b/src/test/ui/error-codes/E0161.nll.stderr index 1060675cd45f4..fb082bc1eabcf 100644 --- a/src/test/ui/error-codes/E0161.nll.stderr +++ b/src/test/ui/error-codes/E0161.nll.stderr @@ -1,5 +1,5 @@ error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined - --> $DIR/E0161.rs:29:5 + --> $DIR/E0161.rs:32:5 | LL | x.f(); | ^^^^^ diff --git a/src/test/ui/error-codes/E0161.rs b/src/test/ui/error-codes/E0161.rs index ba74529e4b6e4..f3a7b68c7cf85 100644 --- a/src/test/ui/error-codes/E0161.rs +++ b/src/test/ui/error-codes/E0161.rs @@ -1,5 +1,3 @@ -// ignore-compare-mode-nll - // Check that E0161 is a hard error in all possible configurations that might // affect it. @@ -13,6 +11,11 @@ //[zflagsul] check-pass //[editionul] check-pass +// Since we are testing nll (and migration) explicitly as a separate +// revisions, don't worry about the --compare-mode=nll on this test. + +// ignore-compare-mode-nll + #![allow(incomplete_features)] #![cfg_attr(nll, feature(nll))] #![cfg_attr(nllul, feature(nll))] diff --git a/src/test/ui/error-codes/E0161.zflags.stderr b/src/test/ui/error-codes/E0161.zflags.stderr index 1060675cd45f4..fb082bc1eabcf 100644 --- a/src/test/ui/error-codes/E0161.zflags.stderr +++ b/src/test/ui/error-codes/E0161.zflags.stderr @@ -1,5 +1,5 @@ error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined - --> $DIR/E0161.rs:29:5 + --> $DIR/E0161.rs:32:5 | LL | x.f(); | ^^^^^ diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr index 119cec1fa95bf..7da6b029c26f0 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr @@ -1,5 +1,5 @@ error: implementation of `Parser` is not general enough - --> $DIR/issue-71955.rs:52:5 + --> $DIR/issue-71955.rs:57:5 | LL | foo(bar, "string", |s| s.len() == 5); | ^^^ implementation of `Parser` is not general enough @@ -8,7 +8,7 @@ LL | foo(bar, "string", |s| s.len() == 5); = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` error: implementation of `Parser` is not general enough - --> $DIR/issue-71955.rs:52:5 + --> $DIR/issue-71955.rs:57:5 | LL | foo(bar, "string", |s| s.len() == 5); | ^^^ implementation of `Parser` is not general enough @@ -17,7 +17,7 @@ LL | foo(bar, "string", |s| s.len() == 5); = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` error: implementation of `Parser` is not general enough - --> $DIR/issue-71955.rs:52:5 + --> $DIR/issue-71955.rs:57:5 | LL | foo(bar, "string", |s| s.len() == 5); | ^^^ implementation of `Parser` is not general enough @@ -26,7 +26,7 @@ LL | foo(bar, "string", |s| s.len() == 5); = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` error: implementation of `Parser` is not general enough - --> $DIR/issue-71955.rs:52:5 + --> $DIR/issue-71955.rs:57:5 | LL | foo(bar, "string", |s| s.len() == 5); | ^^^ implementation of `Parser` is not general enough @@ -35,7 +35,7 @@ LL | foo(bar, "string", |s| s.len() == 5); = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` error: implementation of `Parser` is not general enough - --> $DIR/issue-71955.rs:52:5 + --> $DIR/issue-71955.rs:57:5 | LL | foo(bar, "string", |s| s.len() == 5); | ^^^ implementation of `Parser` is not general enough @@ -44,7 +44,7 @@ LL | foo(bar, "string", |s| s.len() == 5); = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` error: implementation of `Parser` is not general enough - --> $DIR/issue-71955.rs:58:5 + --> $DIR/issue-71955.rs:63:5 | LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^ implementation of `Parser` is not general enough @@ -53,7 +53,7 @@ LL | foo(baz, "string", |s| s.0.len() == 5); = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` error: implementation of `Parser` is not general enough - --> $DIR/issue-71955.rs:58:5 + --> $DIR/issue-71955.rs:63:5 | LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^ implementation of `Parser` is not general enough @@ -62,7 +62,7 @@ LL | foo(baz, "string", |s| s.0.len() == 5); = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` error: implementation of `Parser` is not general enough - --> $DIR/issue-71955.rs:58:5 + --> $DIR/issue-71955.rs:63:5 | LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^ implementation of `Parser` is not general enough @@ -71,7 +71,7 @@ LL | foo(baz, "string", |s| s.0.len() == 5); = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` error: implementation of `Parser` is not general enough - --> $DIR/issue-71955.rs:58:5 + --> $DIR/issue-71955.rs:63:5 | LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^ implementation of `Parser` is not general enough @@ -80,7 +80,7 @@ LL | foo(baz, "string", |s| s.0.len() == 5); = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` error: implementation of `Parser` is not general enough - --> $DIR/issue-71955.rs:58:5 + --> $DIR/issue-71955.rs:63:5 | LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^ implementation of `Parser` is not general enough diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr index 69ab446bc7a34..c2feaa9128055 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr @@ -1,5 +1,5 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/issue-71955.rs:42:1 + --> $DIR/issue-71955.rs:47:1 | LL | fn main() { | ^^^^^^^^^ diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs index 95e3b3d4e1b88..3d6778b6942c5 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs @@ -3,6 +3,11 @@ // [nll]compile-flags: -Zborrowck=mir // check-fail +// Since we are testing nll (and migration) explicitly as a separate +// revisions, don't worry about the --compare-mode=nll on this test. + +// ignore-compare-mode-nll + #![feature(rustc_attrs)] trait Parser<'s> { diff --git a/src/test/ui/hrtb/issue-30786.migrate.stderr b/src/test/ui/hrtb/issue-30786.migrate.stderr index a497c6257dab6..a2ab1f1856d3e 100644 --- a/src/test/ui/hrtb/issue-30786.migrate.stderr +++ b/src/test/ui/hrtb/issue-30786.migrate.stderr @@ -1,5 +1,5 @@ -error[E0599]: the method `filterx` exists for struct `Map`, but its trait bounds were not satisfied - --> $DIR/issue-30786.rs:128:22 +error[E0599]: the method `filterx` exists for struct `Map`, but its trait bounds were not satisfied + --> $DIR/issue-30786.rs:127:22 | LL | pub struct Map { | -------------------- @@ -8,19 +8,19 @@ LL | pub struct Map { | doesn't satisfy `_: StreamExt` ... LL | let filter = map.filterx(|x: &_| true); - | ^^^^^^^ method cannot be called on `Map` due to unsatisfied trait bounds + | ^^^^^^^ method cannot be called on `Map` due to unsatisfied trait bounds | note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`: - `&'a mut Map: Stream` - `&'a mut &Map: Stream` - `&'a mut &mut Map: Stream` - --> $DIR/issue-30786.rs:106:9 + `&'a mut Map: Stream` + `&'a mut &Map: Stream` + `&'a mut &mut Map: Stream` + --> $DIR/issue-30786.rs:105:9 | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | ^^^^^^^^^ ^ -error[E0599]: the method `countx` exists for struct `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`, but its trait bounds were not satisfied - --> $DIR/issue-30786.rs:141:24 +error[E0599]: the method `countx` exists for struct `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied + --> $DIR/issue-30786.rs:140:24 | LL | pub struct Filter { | ----------------------- @@ -29,13 +29,13 @@ LL | pub struct Filter { | doesn't satisfy `_: StreamExt` ... LL | let count = filter.countx(); - | ^^^^^^ method cannot be called on `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` due to unsatisfied trait bounds + | ^^^^^^ method cannot be called on `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>` due to unsatisfied trait bounds | note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`: - `&'a mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream` - `&'a mut &Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream` - `&'a mut &mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream` - --> $DIR/issue-30786.rs:106:9 + `&'a mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream` + `&'a mut &Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream` + `&'a mut &mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream` + --> $DIR/issue-30786.rs:105:9 | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | ^^^^^^^^^ ^ diff --git a/src/test/ui/hrtb/issue-30786.nll.stderr b/src/test/ui/hrtb/issue-30786.nll.stderr index a497c6257dab6..a2ab1f1856d3e 100644 --- a/src/test/ui/hrtb/issue-30786.nll.stderr +++ b/src/test/ui/hrtb/issue-30786.nll.stderr @@ -1,5 +1,5 @@ -error[E0599]: the method `filterx` exists for struct `Map`, but its trait bounds were not satisfied - --> $DIR/issue-30786.rs:128:22 +error[E0599]: the method `filterx` exists for struct `Map`, but its trait bounds were not satisfied + --> $DIR/issue-30786.rs:127:22 | LL | pub struct Map { | -------------------- @@ -8,19 +8,19 @@ LL | pub struct Map { | doesn't satisfy `_: StreamExt` ... LL | let filter = map.filterx(|x: &_| true); - | ^^^^^^^ method cannot be called on `Map` due to unsatisfied trait bounds + | ^^^^^^^ method cannot be called on `Map` due to unsatisfied trait bounds | note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`: - `&'a mut Map: Stream` - `&'a mut &Map: Stream` - `&'a mut &mut Map: Stream` - --> $DIR/issue-30786.rs:106:9 + `&'a mut Map: Stream` + `&'a mut &Map: Stream` + `&'a mut &mut Map: Stream` + --> $DIR/issue-30786.rs:105:9 | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | ^^^^^^^^^ ^ -error[E0599]: the method `countx` exists for struct `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`, but its trait bounds were not satisfied - --> $DIR/issue-30786.rs:141:24 +error[E0599]: the method `countx` exists for struct `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied + --> $DIR/issue-30786.rs:140:24 | LL | pub struct Filter { | ----------------------- @@ -29,13 +29,13 @@ LL | pub struct Filter { | doesn't satisfy `_: StreamExt` ... LL | let count = filter.countx(); - | ^^^^^^ method cannot be called on `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` due to unsatisfied trait bounds + | ^^^^^^ method cannot be called on `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>` due to unsatisfied trait bounds | note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`: - `&'a mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream` - `&'a mut &Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream` - `&'a mut &mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream` - --> $DIR/issue-30786.rs:106:9 + `&'a mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream` + `&'a mut &Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream` + `&'a mut &mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream` + --> $DIR/issue-30786.rs:105:9 | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | ^^^^^^^^^ ^ diff --git a/src/test/ui/hrtb/issue-30786.rs b/src/test/ui/hrtb/issue-30786.rs index 278c5441ecfb7..540c26c358b1d 100644 --- a/src/test/ui/hrtb/issue-30786.rs +++ b/src/test/ui/hrtb/issue-30786.rs @@ -7,6 +7,7 @@ // through again. // revisions: migrate nll +//[nll]compile-flags: -Z borrowck=mir // Since we are testing nll (and migration) explicitly as a separate // revisions, don't worry about the --compare-mode=nll on this test. @@ -14,8 +15,6 @@ // ignore-compare-mode-nll // ignore-compare-mode-polonius -//[nll]compile-flags: -Z borrowck=mir - pub trait Stream { type Item; fn next(self) -> Option; diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr deleted file mode 100644 index 9bb385b0dcdc8..0000000000000 --- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:39:12 - | -LL | fn with_assoc<'a,'b>() { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -... -LL | let _: &'a WithAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` - | - = help: consider adding the following bound: `'b: 'a` - -error: aborting due to previous error - diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr index 6ae70ec672ce1..d9fd1aebf277d 100644 --- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr +++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr @@ -1,16 +1,16 @@ error[E0491]: in type `&'a WithAssoc>`, reference has a longer lifetime than the data it references - --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:39:12 + --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:44:12 | LL | let _: &'a WithAssoc> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime `'a` as defined here - --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:33:15 + --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:38:15 | LL | fn with_assoc<'a,'b>() { | ^^ note: but the referenced data is only valid for the lifetime `'b` as defined here - --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:33:18 + --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:38:18 | LL | fn with_assoc<'a,'b>() { | ^^ diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr index 9bb385b0dcdc8..ba7572ebe3137 100644 --- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr +++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:39:12 + --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:44:12 | LL | fn with_assoc<'a,'b>() { | -- -- lifetime `'b` defined here diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs index 046d010002e6e..08bc64926fac3 100644 --- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs +++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs @@ -6,6 +6,11 @@ // revisions: migrate nll //[nll]compile-flags: -Z borrowck=mir +// Since we are testing nll (and migration) explicitly as a separate +// revisions, don't worry about the --compare-mode=nll on this test. + +// ignore-compare-mode-nll + #![allow(dead_code)] pub trait TheTrait { diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr deleted file mode 100644 index 0d4694a64d087..0000000000000 --- a/src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/regions-free-region-ordering-caller.rs:11:12 - | -LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | let z: Option<&'b &'a usize> = None; - | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` - | - = help: consider adding the following bound: `'a: 'b` - -error: lifetime may not live long enough - --> $DIR/regions-free-region-ordering-caller.rs:17:12 - | -LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | let y: Paramd<'a> = Paramd { x: a }; -LL | let z: Option<&'b Paramd<'a>> = None; - | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b` - | - = help: consider adding the following bound: `'a: 'b` - -error: lifetime may not live long enough - --> $DIR/regions-free-region-ordering-caller.rs:22:12 - | -LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | let z: Option<&'a &'b usize> = None; - | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` - | - = help: consider adding the following bound: `'b: 'a` - -error: aborting due to 3 previous errors - diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr index c0f3b24f68cfe..a27a010d7f302 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr @@ -1,50 +1,50 @@ error[E0491]: in type `&'b &'a usize`, reference has a longer lifetime than the data it references - --> $DIR/regions-free-region-ordering-caller.rs:11:12 + --> $DIR/regions-free-region-ordering-caller.rs:16:12 | LL | let z: Option<&'b &'a usize> = None; | ^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime `'b` as defined here - --> $DIR/regions-free-region-ordering-caller.rs:10:14 + --> $DIR/regions-free-region-ordering-caller.rs:15:14 | LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { | ^^ note: but the referenced data is only valid for the lifetime `'a` as defined here - --> $DIR/regions-free-region-ordering-caller.rs:10:10 + --> $DIR/regions-free-region-ordering-caller.rs:15:10 | LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { | ^^ error[E0491]: in type `&'b Paramd<'a>`, reference has a longer lifetime than the data it references - --> $DIR/regions-free-region-ordering-caller.rs:17:12 + --> $DIR/regions-free-region-ordering-caller.rs:22:12 | LL | let z: Option<&'b Paramd<'a>> = None; | ^^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime `'b` as defined here - --> $DIR/regions-free-region-ordering-caller.rs:15:14 + --> $DIR/regions-free-region-ordering-caller.rs:20:14 | LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { | ^^ note: but the referenced data is only valid for the lifetime `'a` as defined here - --> $DIR/regions-free-region-ordering-caller.rs:15:10 + --> $DIR/regions-free-region-ordering-caller.rs:20:10 | LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { | ^^ error[E0491]: in type `&'a &'b usize`, reference has a longer lifetime than the data it references - --> $DIR/regions-free-region-ordering-caller.rs:22:12 + --> $DIR/regions-free-region-ordering-caller.rs:27:12 | LL | let z: Option<&'a &'b usize> = None; | ^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime `'a` as defined here - --> $DIR/regions-free-region-ordering-caller.rs:21:10 + --> $DIR/regions-free-region-ordering-caller.rs:26:10 | LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { | ^^ note: but the referenced data is only valid for the lifetime `'b` as defined here - --> $DIR/regions-free-region-ordering-caller.rs:21:14 + --> $DIR/regions-free-region-ordering-caller.rs:26:14 | LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { | ^^ diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr index 0d4694a64d087..546eb93d8ecab 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/regions-free-region-ordering-caller.rs:11:12 + --> $DIR/regions-free-region-ordering-caller.rs:16:12 | LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { | -- -- lifetime `'b` defined here @@ -11,7 +11,7 @@ LL | let z: Option<&'b &'a usize> = None; = help: consider adding the following bound: `'a: 'b` error: lifetime may not live long enough - --> $DIR/regions-free-region-ordering-caller.rs:17:12 + --> $DIR/regions-free-region-ordering-caller.rs:22:12 | LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { | -- -- lifetime `'b` defined here @@ -24,7 +24,7 @@ LL | let z: Option<&'b Paramd<'a>> = None; = help: consider adding the following bound: `'a: 'b` error: lifetime may not live long enough - --> $DIR/regions-free-region-ordering-caller.rs:22:12 + --> $DIR/regions-free-region-ordering-caller.rs:27:12 | LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { | -- -- lifetime `'b` defined here diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.rs b/src/test/ui/regions/regions-free-region-ordering-caller.rs index 2bf4734cf7380..11997a5fb56a5 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller.rs +++ b/src/test/ui/regions/regions-free-region-ordering-caller.rs @@ -5,6 +5,11 @@ // revisions: migrate nll //[nll]compile-flags: -Z borrowck=mir +// Since we are testing nll (and migration) explicitly as a separate +// revisions, don't worry about the --compare-mode=nll on this test. + +// ignore-compare-mode-nll + struct Paramd<'a> { x: &'a usize } fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr deleted file mode 100644 index 29e92f33ec914..0000000000000 --- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/regions-outlives-projection-container-hrtb.rs:30:12 - | -LL | fn with_assoc<'a,'b>() { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -... -LL | let _: &'a WithHrAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` - | - = help: consider adding the following bound: `'b: 'a` - -error: lifetime may not live long enough - --> $DIR/regions-outlives-projection-container-hrtb.rs:50:12 - | -LL | fn with_assoc_sub<'a,'b>() { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -... -LL | let _: &'a WithHrAssocSub> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` - | - = help: consider adding the following bound: `'b: 'a` - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr index 60c115b3f5939..f2308bb7c78b1 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr +++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr @@ -1,33 +1,33 @@ error[E0491]: in type `&'a WithHrAssoc>`, reference has a longer lifetime than the data it references - --> $DIR/regions-outlives-projection-container-hrtb.rs:30:12 + --> $DIR/regions-outlives-projection-container-hrtb.rs:35:12 | LL | let _: &'a WithHrAssoc> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime `'a` as defined here - --> $DIR/regions-outlives-projection-container-hrtb.rs:27:15 + --> $DIR/regions-outlives-projection-container-hrtb.rs:32:15 | LL | fn with_assoc<'a,'b>() { | ^^ note: but the referenced data is only valid for the lifetime `'b` as defined here - --> $DIR/regions-outlives-projection-container-hrtb.rs:27:18 + --> $DIR/regions-outlives-projection-container-hrtb.rs:32:18 | LL | fn with_assoc<'a,'b>() { | ^^ error[E0491]: in type `&'a WithHrAssocSub>`, reference has a longer lifetime than the data it references - --> $DIR/regions-outlives-projection-container-hrtb.rs:50:12 + --> $DIR/regions-outlives-projection-container-hrtb.rs:55:12 | LL | let _: &'a WithHrAssocSub> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime `'a` as defined here - --> $DIR/regions-outlives-projection-container-hrtb.rs:46:19 + --> $DIR/regions-outlives-projection-container-hrtb.rs:51:19 | LL | fn with_assoc_sub<'a,'b>() { | ^^ note: but the referenced data is only valid for the lifetime `'b` as defined here - --> $DIR/regions-outlives-projection-container-hrtb.rs:46:22 + --> $DIR/regions-outlives-projection-container-hrtb.rs:51:22 | LL | fn with_assoc_sub<'a,'b>() { | ^^ diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr index 29e92f33ec914..472323772c1a5 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr +++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/regions-outlives-projection-container-hrtb.rs:30:12 + --> $DIR/regions-outlives-projection-container-hrtb.rs:35:12 | LL | fn with_assoc<'a,'b>() { | -- -- lifetime `'b` defined here @@ -12,7 +12,7 @@ LL | let _: &'a WithHrAssoc> = loop { }; = help: consider adding the following bound: `'b: 'a` error: lifetime may not live long enough - --> $DIR/regions-outlives-projection-container-hrtb.rs:50:12 + --> $DIR/regions-outlives-projection-container-hrtb.rs:55:12 | LL | fn with_assoc_sub<'a,'b>() { | -- -- lifetime `'b` defined here diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs b/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs index cee741184ca2a..695a81dca27c8 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs +++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs @@ -4,6 +4,11 @@ // revisions: migrate nll //[nll]compile-flags: -Z borrowck=mir +// Since we are testing nll (and migration) explicitly as a separate +// revisions, don't worry about the --compare-mode=nll on this test. + +// ignore-compare-mode-nll + #![allow(dead_code)] pub trait TheTrait<'b> { diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr deleted file mode 100644 index 7035144302479..0000000000000 --- a/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/regions-outlives-projection-container-wc.rs:33:12 - | -LL | fn with_assoc<'a,'b>() { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -... -LL | let _: &'a WithAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a` - | - = help: consider adding the following bound: `'b: 'a` - -error: aborting due to previous error - diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr index 8430b69f99832..bda2896fca4ac 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr +++ b/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr @@ -1,16 +1,16 @@ error[E0491]: in type `&'a WithAssoc>`, reference has a longer lifetime than the data it references - --> $DIR/regions-outlives-projection-container-wc.rs:33:12 + --> $DIR/regions-outlives-projection-container-wc.rs:38:12 | LL | let _: &'a WithAssoc> = loop { }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime `'a` as defined here - --> $DIR/regions-outlives-projection-container-wc.rs:27:15 + --> $DIR/regions-outlives-projection-container-wc.rs:32:15 | LL | fn with_assoc<'a,'b>() { | ^^ note: but the referenced data is only valid for the lifetime `'b` as defined here - --> $DIR/regions-outlives-projection-container-wc.rs:27:18 + --> $DIR/regions-outlives-projection-container-wc.rs:32:18 | LL | fn with_assoc<'a,'b>() { | ^^ diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr index 7035144302479..fc32a72d50896 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr +++ b/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/regions-outlives-projection-container-wc.rs:33:12 + --> $DIR/regions-outlives-projection-container-wc.rs:38:12 | LL | fn with_assoc<'a,'b>() { | -- -- lifetime `'b` defined here diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.rs b/src/test/ui/regions/regions-outlives-projection-container-wc.rs index 99965f333907b..c9b714cffb6e4 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-wc.rs +++ b/src/test/ui/regions/regions-outlives-projection-container-wc.rs @@ -6,6 +6,11 @@ // revisions: migrate nll //[nll]compile-flags: -Z borrowck=mir +// Since we are testing nll (and migration) explicitly as a separate +// revisions, don't worry about the --compare-mode=nll on this test. + +// ignore-compare-mode-nll + #![allow(dead_code)] pub trait TheTrait { From 0c57fab5fcd19244df6fa946bb504ce0601b29d1 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Wed, 24 Nov 2021 16:58:49 -0800 Subject: [PATCH 8/9] Add conditional support for coverage map version 6 This commit augments Swatinem's initial commit in uncommitted PR #90047, which was a great starting point, but did not fully support LLVM Coverage Mapping Format version 6. Version 6 requires adding the compilation directory when file paths are relative, and since Rustc coverage maps use relative paths, we should add the expected compilation directory entry. Note, however, that with the compilation directory, coverage reports from `llvm-cov show` can now report file names (when the report includes more than one file) with the full absolute path to the file. This would be a problem for test results, but the workaround (for the rust coverage tests) is to include an additional `llvm-cov show` parameter: `--compilation-dir=.` --- .../src/coverageinfo/mapgen.rs | 45 ++++++++++++++----- .../src/compiler-flags/instrument-coverage.md | 2 +- .../coverage-llvmir/Makefile | 6 +++ .../coverage-reports/Makefile | 7 +++ 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 67cd5363a7ba5..0390caaec33e5 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -9,6 +9,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_llvm::RustString; use rustc_middle::mir::coverage::CodeRegion; +use rustc_middle::ty::TyCtxt; use rustc_span::Symbol; use std::ffi::CString; @@ -17,9 +18,10 @@ use tracing::debug; /// Generates and exports the Coverage Map. /// -/// This Coverage Map complies with Coverage Mapping Format version 5 (zero-based encoded as 4), -/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). -/// This version is supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`) +/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions +/// 5 (LLVM 12, only) and 6 (zero-based encoded as 4 and 5, respectively), as defined at +/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). +/// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`) /// bundled with Rust's fork of LLVM. /// /// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with @@ -30,12 +32,13 @@ use tracing::debug; pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { let tcx = cx.tcx; - // While our bundled LLVM might support Coverage Map Version 6 - // (encoded as a zero-based value: 5), we clamp that to Version 5, - // as Version 6 would require us to use the 0-th filename as a path prefix - // for all other relative paths, which we don't take advantage of right now. - let _version = coverageinfo::mapping_version(); - let version = 4; + // Ensure the installed version of LLVM supports at least Coverage Map + // Version 5 (encoded as a zero-based value: 4), which was introduced with + // LLVM 12. + let version = coverageinfo::mapping_version(); + if version < 4 { + tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 12 or higher."); + } debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name()); @@ -57,7 +60,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { return; } - let mut mapgen = CoverageMapGenerator::new(); + let mut mapgen = CoverageMapGenerator::new(tcx, version); // Encode coverage mappings and generate function records let mut function_data = Vec::new(); @@ -112,8 +115,26 @@ struct CoverageMapGenerator { } impl CoverageMapGenerator { - fn new() -> Self { - Self { filenames: FxIndexSet::default() } + fn new(tcx: TyCtxt<'_>, version: u32) -> Self { + let mut filenames = FxIndexSet::default(); + if version >= 5 { + // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5) + // requires setting the first filename to the compilation directory. + // Since rustc generates coverage maps with relative paths, the + // compilation directory can be combined with the the relative paths + // to get absolute paths, if needed. + let working_dir = tcx + .sess + .opts + .working_dir + .remapped_path_if_available() + .to_string_lossy() + .to_string(); + let c_filename = + CString::new(working_dir).expect("null error converting filename to C string"); + filenames.insert(c_filename); + } + Self { filenames } } /// Using the `expressions` and `counter_regions` collected for the current function, generate diff --git a/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md b/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md index 0424ed08dafbe..f4d1ca0ec6911 100644 --- a/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md +++ b/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md @@ -20,7 +20,7 @@ This document describes how to enable and use the LLVM instrumentation-based cov When `-Z instrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by: - Automatically injecting calls to an LLVM intrinsic ([`llvm.instrprof.increment`]), at functions and branches in compiled code, to increment counters when conditional sections of code are executed. -- Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 5_, supported _only_ in LLVM 12 and up), to define the code regions (start and end positions in the source code) being counted. +- Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 5_, if compiling with LLVM 12, or _Version 6_, if compiling with LLVM 13 or higher), to define the code regions (start and end positions in the source code) being counted. When running a coverage-instrumented program, the counter values are written to a `profraw` file at program termination. LLVM bundles tools that read the counter results, combine those results with the coverage map (embedded in the program binary), and generate coverage reports in multiple formats. diff --git a/src/test/run-make-fulldeps/coverage-llvmir/Makefile b/src/test/run-make-fulldeps/coverage-llvmir/Makefile index 8722d9e10d91d..3c4df3533e147 100644 --- a/src/test/run-make-fulldeps/coverage-llvmir/Makefile +++ b/src/test/run-make-fulldeps/coverage-llvmir/Makefile @@ -1,5 +1,11 @@ # needs-profiler-support +# Rust coverage maps support LLVM Coverage Mapping Format versions 5 and 6, +# corresponding with LLVM versions 12 and 13, respectively. +# When upgrading LLVM versions, consider whether to enforce a minimum LLVM +# version during testing, with an additional directive at the top of this file +# that sets, for example: `min-llvm-version: 12.0` + -include ../coverage/coverage_tools.mk BASEDIR=../coverage-llvmir diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile index 4adf02bee0af4..9122e0406c2ef 100644 --- a/src/test/run-make-fulldeps/coverage-reports/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -1,6 +1,12 @@ # needs-profiler-support # ignore-windows-gnu +# Rust coverage maps support LLVM Coverage Mapping Format versions 5 and 6, +# corresponding with LLVM versions 12 and 13, respectively. +# When upgrading LLVM versions, consider whether to enforce a minimum LLVM +# version during testing, with an additional directive at the top of this file +# that sets, for example: `min-llvm-version: 12.0` + # FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works # properly. Since we only have GCC on the CI ignore the test for now. @@ -115,6 +121,7 @@ endif "$(LLVM_BIN_DIR)"/llvm-cov show \ $(DEBUG_FLAG) \ $(LLVM_COV_IGNORE_FILES) \ + --compilation-dir=. \ --Xdemangler="$(RUST_DEMANGLER)" \ --show-line-counts-or-regions \ --instr-profile="$(TMPDIR)"/$@.profdata \ From e7ee8230ced7c14043ca51191063c13e7fbc7212 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 1 Dec 2021 07:22:29 +1100 Subject: [PATCH 9/9] Fix bad `NodeId` limit checking. `Resolver::next_node_id` converts a `u32` to a `usize` (which is possibly bigger), does a checked add, and then converts the result back to a `u32`. The `usize` conversion completely subverts the checked add! This commit removes the conversion to/from `usize`. --- compiler/rustc_resolve/src/lib.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d17e8875a1ec0..a8ae4736c0402 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1430,12 +1430,9 @@ impl<'a> Resolver<'a> { } pub fn next_node_id(&mut self) -> NodeId { - let next = self - .next_node_id - .as_usize() - .checked_add(1) - .expect("input too large; ran out of NodeIds"); - self.next_node_id = ast::NodeId::from_usize(next); + let next = + self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds"); + self.next_node_id = ast::NodeId::from_u32(next); self.next_node_id }