From 0a619dd8ff56f53ec1b85b7e52ad68dc0e2c2e96 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 18 Nov 2024 17:43:28 +1100 Subject: [PATCH 01/12] Rename `parse_no_flag` to `parse_no_value` The old name and comment suggest that this parser is only used for options beginning with `no-`, which is mostly true but not entirely true. --- compiler/rustc_session/src/options.rs | 40 +++++++++++++++------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f485e8cace54d..f3d564305b63a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -358,7 +358,7 @@ fn build_options( #[allow(non_upper_case_globals)] mod desc { - pub(crate) const parse_no_flag: &str = "no value"; + pub(crate) const parse_no_value: &str = "no value"; pub(crate) const parse_bool: &str = "one of: `y`, `yes`, `on`, `true`, `n`, `no`, `off` or `false`"; pub(crate) const parse_opt_bool: &str = parse_bool; @@ -462,14 +462,18 @@ pub mod parse { pub(crate) use super::*; pub(crate) const MAX_THREADS_CAP: usize = 256; - /// This is for boolean options that don't take a value and start with - /// `no-`. This style of option is deprecated. - pub(crate) fn parse_no_flag(slot: &mut bool, v: Option<&str>) -> bool { + /// This is for boolean options that don't take a value, and are true simply + /// by existing on the command-line. + /// + /// This style of option is deprecated, and is mainly used by old options + /// beginning with `no-`. + pub(crate) fn parse_no_value(slot: &mut bool, v: Option<&str>) -> bool { match v { None => { *slot = true; true } + // Trying to specify a value is always forbidden. Some(_) => false, } } @@ -1609,16 +1613,16 @@ options! { "perform LLVM link-time optimizations"), metadata: Vec = (Vec::new(), parse_list, [TRACKED], "metadata to mangle symbol names with"), - no_prepopulate_passes: bool = (false, parse_no_flag, [TRACKED], + no_prepopulate_passes: bool = (false, parse_no_value, [TRACKED], "give an empty list of passes to the pass manager"), no_redzone: Option = (None, parse_opt_bool, [TRACKED], "disable the use of the redzone"), #[rustc_lint_opt_deny_field_access("documented to do nothing")] - no_stack_check: bool = (false, parse_no_flag, [UNTRACKED], + no_stack_check: bool = (false, parse_no_value, [UNTRACKED], "this option is deprecated and does nothing"), - no_vectorize_loops: bool = (false, parse_no_flag, [TRACKED], + no_vectorize_loops: bool = (false, parse_no_value, [TRACKED], "disable loop vectorization optimization passes"), - no_vectorize_slp: bool = (false, parse_no_flag, [TRACKED], + no_vectorize_slp: bool = (false, parse_no_value, [TRACKED], "disable LLVM's SLP vectorization pass"), opt_level: String = ("0".to_string(), parse_string, [TRACKED], "optimization level (0-3, s, or z; default: 0)"), @@ -1917,25 +1921,25 @@ options! { "dump facts from NLL analysis into side files (default: no)"), nll_facts_dir: String = ("nll-facts".to_string(), parse_string, [UNTRACKED], "the directory the NLL facts are dumped into (default: `nll-facts`)"), - no_analysis: bool = (false, parse_no_flag, [UNTRACKED], + no_analysis: bool = (false, parse_no_value, [UNTRACKED], "parse and expand the source, but run no analysis"), - no_codegen: bool = (false, parse_no_flag, [TRACKED_NO_CRATE_HASH], + no_codegen: bool = (false, parse_no_value, [TRACKED_NO_CRATE_HASH], "run all passes except codegen; no output"), - no_generate_arange_section: bool = (false, parse_no_flag, [TRACKED], + no_generate_arange_section: bool = (false, parse_no_value, [TRACKED], "omit DWARF address ranges that give faster lookups"), no_implied_bounds_compat: bool = (false, parse_bool, [TRACKED], "disable the compatibility version of the `implied_bounds_ty` query"), - no_jump_tables: bool = (false, parse_no_flag, [TRACKED], + no_jump_tables: bool = (false, parse_no_value, [TRACKED], "disable the jump tables and lookup tables that can be generated from a switch case lowering"), - no_leak_check: bool = (false, parse_no_flag, [UNTRACKED], + no_leak_check: bool = (false, parse_no_value, [UNTRACKED], "disable the 'leak check' for subtyping; unsound, but useful for tests"), - no_link: bool = (false, parse_no_flag, [TRACKED], + no_link: bool = (false, parse_no_value, [TRACKED], "compile without linking"), - no_parallel_backend: bool = (false, parse_no_flag, [UNTRACKED], + no_parallel_backend: bool = (false, parse_no_value, [UNTRACKED], "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"), - no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED], + no_profiler_runtime: bool = (false, parse_no_value, [TRACKED], "prevent automatic injection of the profiler_builtins crate"), - no_trait_vptr: bool = (false, parse_no_flag, [TRACKED], + no_trait_vptr: bool = (false, parse_no_value, [TRACKED], "disable generation of trait vptr in vtable for upcasting"), no_unique_section_names: bool = (false, parse_bool, [TRACKED], "do not use unique names for text and data sections when -Z function-sections is used"), @@ -1993,7 +1997,7 @@ options! { proc_macro_execution_strategy: ProcMacroExecutionStrategy = (ProcMacroExecutionStrategy::SameThread, parse_proc_macro_execution_strategy, [UNTRACKED], "how to run proc-macro code (default: same-thread)"), - profile_closures: bool = (false, parse_no_flag, [UNTRACKED], + profile_closures: bool = (false, parse_no_value, [UNTRACKED], "profile size of closures"), profile_sample_use: Option = (None, parse_opt_pathbuf, [TRACKED], "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"), From 660246bc762c426a9f46a212ee4b35b0d54256c1 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 18 Nov 2024 17:36:45 +1100 Subject: [PATCH 02/12] Don't allow `-Zunstable-options` to take a value Passing an explicit boolean value (`on`, `off` etc.) appears to work, but actually puts the compiler into an unintended state where unstable _options_ are still forbidden, but unstable values of _some_ stable options are allowed. --- compiler/rustc_session/src/options.rs | 8 +++++++- tests/ui/codemap_tests/huge_multispan_highlight.rs | 2 +- tests/ui/diagnostic-width/E0271.rs | 2 +- tests/ui/diagnostic-width/flag-human.rs | 2 +- tests/ui/diagnostic-width/long-E0308.rs | 2 +- .../non-1-width-unicode-multiline-label.rs | 2 +- tests/ui/diagnostic-width/non-whitespace-trimming-2.rs | 2 +- tests/ui/error-emitter/unicode-output.rs | 2 +- 8 files changed, 14 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f3d564305b63a..d2ae83cada8fd 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2171,8 +2171,14 @@ written to standard error output)"), "enable unsound and buggy MIR optimizations (default: no)"), /// This name is kind of confusing: Most unstable options enable something themselves, while /// this just allows "normal" options to be feature-gated. + /// + /// The main check for `-Zunstable-options` takes place separately from the + /// usual parsing of `-Z` options (see [`crate::config::nightly_options`]), + /// so this boolean value is mostly used for enabling unstable _values_ of + /// stable options. That separate check doesn't handle boolean values, so + /// to avoid an inconsistent state we also forbid them here. #[rustc_lint_opt_deny_field_access("use `Session::unstable_options` instead of this field")] - unstable_options: bool = (false, parse_bool, [UNTRACKED], + unstable_options: bool = (false, parse_no_value, [UNTRACKED], "adds unstable command line options to rustc interface (default: no)"), use_ctors_section: Option = (None, parse_opt_bool, [TRACKED], "use legacy .ctors section for initializers rather than .init_array"), diff --git a/tests/ui/codemap_tests/huge_multispan_highlight.rs b/tests/ui/codemap_tests/huge_multispan_highlight.rs index 7d7b757082350..6f6834b01bd61 100644 --- a/tests/ui/codemap_tests/huge_multispan_highlight.rs +++ b/tests/ui/codemap_tests/huge_multispan_highlight.rs @@ -1,7 +1,7 @@ //@ revisions: ascii unicode //@ compile-flags: --color=always //@[ascii] compile-flags: --error-format=human -//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode +//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode //@ ignore-windows fn main() { let _ = match true { diff --git a/tests/ui/diagnostic-width/E0271.rs b/tests/ui/diagnostic-width/E0271.rs index ce41ad2952bc9..dedae4365e889 100644 --- a/tests/ui/diagnostic-width/E0271.rs +++ b/tests/ui/diagnostic-width/E0271.rs @@ -1,6 +1,6 @@ //@ revisions: ascii unicode //@[ascii] compile-flags: --diagnostic-width=40 -//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode --diagnostic-width=40 +//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode --diagnostic-width=40 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" trait Future { type Error; diff --git a/tests/ui/diagnostic-width/flag-human.rs b/tests/ui/diagnostic-width/flag-human.rs index 1af4165914164..8e656293b4102 100644 --- a/tests/ui/diagnostic-width/flag-human.rs +++ b/tests/ui/diagnostic-width/flag-human.rs @@ -1,6 +1,6 @@ //@ revisions: ascii unicode //@[ascii] compile-flags: --diagnostic-width=20 -//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode --diagnostic-width=20 +//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode --diagnostic-width=20 // This test checks that `-Z output-width` effects the human error output by restricting it to an // arbitrarily low value so that the effect is visible. diff --git a/tests/ui/diagnostic-width/long-E0308.rs b/tests/ui/diagnostic-width/long-E0308.rs index 73f81f5872a64..695852f83ac0a 100644 --- a/tests/ui/diagnostic-width/long-E0308.rs +++ b/tests/ui/diagnostic-width/long-E0308.rs @@ -1,6 +1,6 @@ //@ revisions: ascii unicode //@[ascii] compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes -//@[unicode] compile-flags: -Zunstable-options=yes --json=diagnostic-unicode --diagnostic-width=60 -Zwrite-long-types-to-disk=yes +//@[unicode] compile-flags: -Zunstable-options --json=diagnostic-unicode --diagnostic-width=60 -Zwrite-long-types-to-disk=yes //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" mod a { diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs index 61c4b31e03a62..e630db8ba42a2 100644 --- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs +++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs @@ -1,5 +1,5 @@ //@ revisions: ascii unicode -//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode +//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode // ignore-tidy-linelength fn main() { diff --git a/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs b/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs index 283506bd6c90d..de2f42a4a7292 100644 --- a/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs +++ b/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs @@ -1,5 +1,5 @@ //@ revisions: ascii unicode -//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode +//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode // ignore-tidy-linelength fn main() { diff --git a/tests/ui/error-emitter/unicode-output.rs b/tests/ui/error-emitter/unicode-output.rs index ba6db37b66c22..5c083c4e57508 100644 --- a/tests/ui/error-emitter/unicode-output.rs +++ b/tests/ui/error-emitter/unicode-output.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Zunstable-options=yes --error-format=human-unicode --color=always +//@ compile-flags: -Zunstable-options --error-format=human-unicode --color=always //@ edition:2018 //@ only-linux From 16550d9e67e4845212879d56ab7e300d7911de24 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 19 Nov 2024 09:11:08 -0800 Subject: [PATCH 03/12] Fix missing submodule in `./x vendor` The `src/tools/rustc-perf` submodule is needed for vendoring because it is included in the vendor set. --- src/bootstrap/src/core/build_steps/vendor.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs index 82a6b4d4f28cb..d6e6e3462d2af 100644 --- a/src/bootstrap/src/core/build_steps/vendor.rs +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -57,7 +57,9 @@ impl Step for Vendor { } // These submodules must be present for `x vendor` to work. - for submodule in SUBMODULES_FOR_RUSTBOOK.iter().chain(["src/tools/cargo"].iter()) { + for submodule in + SUBMODULES_FOR_RUSTBOOK.iter().chain(["src/tools/cargo", "src/tools/rustc-perf"].iter()) + { builder.build.require_submodule(submodule, None); } From 2487765b88fd9122fcaf57dca94024d81183d272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 5 Nov 2024 18:57:15 +0000 Subject: [PATCH 04/12] Detect const in pattern with typo When writing a constant name incorrectly in a pattern, the pattern will be identified as a new binding. We look for consts in the current crate, consts that where imported in the current crate and for local `let` bindings in case someone got them confused with `const`s. ``` error: unreachable pattern --> $DIR/const-with-typo-in-pattern-binding.rs:30:9 | LL | GOOOD => {} | ----- matches any value LL | LL | _ => {} | ^ no value can reach this | help: you might have meant to pattern match against the value of similarly named constant `GOOD` instead of introducing a new catch-all binding | LL | GOOD => {} | ~~~~ ``` Fix #132582. --- compiler/rustc_mir_build/messages.ftl | 7 + compiler/rustc_mir_build/src/errors.rs | 22 +++ .../src/thir/pattern/check_match.rs | 164 +++++++++++++++++- .../const-with-typo-in-pattern-binding.rs | 45 +++++ .../const-with-typo-in-pattern-binding.stderr | 78 +++++++++ 5 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 tests/ui/resolve/const-with-typo-in-pattern-binding.rs create mode 100644 tests/ui/resolve/const-with-typo-in-pattern-binding.stderr diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 55149570dbc4d..5cb5990ae59b4 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -338,6 +338,13 @@ mir_build_unreachable_pattern = unreachable pattern .unreachable_covered_by_catchall = matches any value .unreachable_covered_by_one = matches all the relevant values .unreachable_covered_by_many = multiple earlier patterns match some of the same values + .unreachable_pattern_const_reexport_accessible = there is a constant of the same name imported in another scope, which could have been used to pattern match against its value instead of introducing a new catch-all binding, but it needs to be imported in the pattern's scope + .unreachable_pattern_wanted_const = you might have meant to pattern match against the value of {$is_typo -> + [true] similarly named constant + *[false] constant + } `{$const_name}` instead of introducing a new catch-all binding + .unreachable_pattern_const_inaccessible = there is a constant of the same name, which could have been used to pattern match against its value instead of introducing a new catch-all binding, but it is not accessible from this scope + .unreachable_pattern_let_binding = there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings .suggestion = remove the match arm mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 62c6d85b73fac..4fbbc1e14b2f0 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -593,6 +593,14 @@ pub(crate) struct UnreachablePattern<'tcx> { pub(crate) uninhabited_note: Option<()>, #[label(mir_build_unreachable_covered_by_catchall)] pub(crate) covered_by_catchall: Option, + #[subdiagnostic] + pub(crate) wanted_constant: Option, + #[note(mir_build_unreachable_pattern_const_reexport_accessible)] + pub(crate) accessible_constant: Option, + #[note(mir_build_unreachable_pattern_const_inaccessible)] + pub(crate) inaccessible_constant: Option, + #[note(mir_build_unreachable_pattern_let_binding)] + pub(crate) pattern_let_binding: Option, #[label(mir_build_unreachable_covered_by_one)] pub(crate) covered_by_one: Option, #[note(mir_build_unreachable_covered_by_many)] @@ -602,6 +610,20 @@ pub(crate) struct UnreachablePattern<'tcx> { pub(crate) suggest_remove: Option, } +#[derive(Subdiagnostic)] +#[suggestion( + mir_build_unreachable_pattern_wanted_const, + code = "{const_path}", + applicability = "machine-applicable" +)] +pub(crate) struct WantedConstant { + #[primary_span] + pub(crate) span: Span, + pub(crate) is_typo: bool, + pub(crate) const_name: String, + pub(crate) const_path: String, +} + #[derive(Diagnostic)] #[diag(mir_build_const_pattern_depends_on_generic_parameter, code = E0158)] pub(crate) struct ConstPatternDependsOnGenericParameter { diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 033501c66dbae..48cd6b53fee56 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -7,7 +7,9 @@ use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_e use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; use rustc_hir::{self as hir, BindingMode, ByRef, HirId}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Reveal; +use rustc_lint::Level; use rustc_middle::bug; use rustc_middle::middle::limits::get_limit_size; use rustc_middle::thir::visit::Visitor; @@ -22,8 +24,10 @@ use rustc_pattern_analysis::rustc::{ use rustc_session::lint::builtin::{ BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, }; +use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; use rustc_span::{Span, sym}; +use rustc_trait_selection::infer::InferCtxtExt; use tracing::instrument; use crate::errors::*; @@ -954,6 +958,10 @@ fn report_unreachable_pattern<'p, 'tcx>( covered_by_one: None, covered_by_many: None, covered_by_many_n_more_count: 0, + wanted_constant: None, + accessible_constant: None, + inaccessible_constant: None, + pattern_let_binding: None, suggest_remove: None, }; match explanation.covered_by.as_slice() { @@ -976,7 +984,10 @@ fn report_unreachable_pattern<'p, 'tcx>( }); } [covering_pat] if pat_is_catchall(covering_pat) => { - lint.covered_by_catchall = Some(covering_pat.data().span); + // A binding pattern that matches all, a single binding name. + let pat = covering_pat.data(); + lint.covered_by_catchall = Some(pat.span); + find_fallback_pattern_typo(cx, hir_id, pat, &mut lint); } [covering_pat] => { lint.covered_by_one = Some(covering_pat.data().span); @@ -1009,6 +1020,157 @@ fn report_unreachable_pattern<'p, 'tcx>( cx.tcx.emit_node_span_lint(UNREACHABLE_PATTERNS, hir_id, pat_span, lint); } +/// Detect typos that were meant to be a `const` but were interpreted as a new pattern binding. +fn find_fallback_pattern_typo<'tcx>( + cx: &PatCtxt<'_, 'tcx>, + hir_id: HirId, + pat: &Pat<'tcx>, + lint: &mut UnreachablePattern<'_>, +) { + if let (Level::Allow, _) = cx.tcx.lint_level_at_node(UNREACHABLE_PATTERNS, hir_id) { + // This is because we use `with_no_trimmed_paths` later, so if we never emit the lint we'd + // ICE. At the same time, we don't really need to do all of this if we won't emit anything. + return; + } + if let PatKind::Binding { name, subpattern: None, ty, .. } = pat.kind { + // See if the binding might have been a `const` that was mistyped or out of scope. + let mut accessible = vec![]; + let mut accessible_path = vec![]; + let mut inaccessible = vec![]; + let mut imported = vec![]; + let mut imported_spans = vec![]; + let infcx = cx.tcx.infer_ctxt().build(ty::TypingMode::non_body_analysis()); + let parent = cx.tcx.hir().get_parent_item(hir_id); + + for item in cx.tcx.hir_crate_items(()).free_items() { + if let DefKind::Use = cx.tcx.def_kind(item.owner_id) { + // Look for consts being re-exported. + let item = cx.tcx.hir().expect_item(item.owner_id.def_id); + let use_name = item.ident.name; + let hir::ItemKind::Use(path, _) = item.kind else { + continue; + }; + for res in &path.res { + if let Res::Def(DefKind::Const, id) = res + && infcx.can_eq(cx.param_env, ty, cx.tcx.type_of(id).instantiate_identity()) + { + if cx.tcx.visibility(id).is_accessible_from(parent, cx.tcx) { + // The original const is accessible, suggest using it directly. + let item_name = cx.tcx.item_name(*id); + accessible.push(item_name); + accessible_path.push(with_no_trimmed_paths!(cx.tcx.def_path_str(id))); + } else if cx + .tcx + .visibility(item.owner_id) + .is_accessible_from(parent, cx.tcx) + { + // The const is accessible only through the re-export, point at + // the `use`. + imported.push(use_name); + imported_spans.push(item.ident.span); + } + } + } + } + if let DefKind::Const = cx.tcx.def_kind(item.owner_id) + && infcx.can_eq( + cx.param_env, + ty, + cx.tcx.type_of(item.owner_id).instantiate_identity(), + ) + { + // Look for local consts. + let item_name = cx.tcx.item_name(item.owner_id.into()); + let vis = cx.tcx.visibility(item.owner_id); + if vis.is_accessible_from(parent, cx.tcx) { + accessible.push(item_name); + let path = if item_name == name { + // We know that the const wasn't in scope because it has the exact + // same name, so we suggest the full path. + with_no_trimmed_paths!(cx.tcx.def_path_str(item.owner_id)) + } else { + // The const is likely just typoed, and nothing else. + cx.tcx.def_path_str(item.owner_id) + }; + accessible_path.push(path); + } else if name == item_name { + // The const exists somewhere in this crate, but it can't be imported + // from this pattern's scope. We'll just point at its definition. + inaccessible.push(cx.tcx.def_span(item.owner_id)); + } + } + } + if let Some((i, &const_name)) = + accessible.iter().enumerate().find(|(_, &const_name)| const_name == name) + { + // The pattern name is an exact match, so the pattern needed to be imported. + lint.wanted_constant = Some(WantedConstant { + span: pat.span, + is_typo: false, + const_name: const_name.to_string(), + const_path: accessible_path[i].clone(), + }); + } else if let Some(name) = find_best_match_for_name(&accessible, name, None) { + // The pattern name is likely a typo. + lint.wanted_constant = Some(WantedConstant { + span: pat.span, + is_typo: true, + const_name: name.to_string(), + const_path: name.to_string(), + }); + } else if let Some(i) = + imported.iter().enumerate().find(|(_, &const_name)| const_name == name).map(|(i, _)| i) + { + // The const with the exact name wasn't re-exported from an import in this + // crate, we point at the import. + lint.accessible_constant = Some(imported_spans[i]); + } else if let Some(name) = find_best_match_for_name(&imported, name, None) { + // The typoed const wasn't re-exported by an import in this crate, we suggest + // the right name (which will likely require another follow up suggestion). + lint.wanted_constant = Some(WantedConstant { + span: pat.span, + is_typo: true, + const_path: name.to_string(), + const_name: name.to_string(), + }); + } else if !inaccessible.is_empty() { + for span in inaccessible { + // The const with the exact name match isn't accessible, we just point at it. + lint.inaccessible_constant = Some(span); + } + } else { + // Look for local bindings for people that might have gotten confused with how + // `let` and `const` works. + for (_, node) in cx.tcx.hir().parent_iter(hir_id) { + match node { + hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Let(let_stmt), .. }) => { + if let hir::PatKind::Binding(_, _, binding_name, _) = let_stmt.pat.kind { + if name == binding_name.name { + lint.pattern_let_binding = Some(binding_name.span); + } + } + } + hir::Node::Block(hir::Block { stmts, .. }) => { + for stmt in *stmts { + if let hir::StmtKind::Let(let_stmt) = stmt.kind { + if let hir::PatKind::Binding(_, _, binding_name, _) = + let_stmt.pat.kind + { + if name == binding_name.name { + lint.pattern_let_binding = Some(binding_name.span); + } + } + } + } + } + hir::Node::Item(_) => break, + _ => {} + } + } + } + } +} + /// Report unreachable arms, if any. fn report_arm_reachability<'p, 'tcx>( cx: &PatCtxt<'p, 'tcx>, diff --git a/tests/ui/resolve/const-with-typo-in-pattern-binding.rs b/tests/ui/resolve/const-with-typo-in-pattern-binding.rs new file mode 100644 index 0000000000000..fe45cee91dbcb --- /dev/null +++ b/tests/ui/resolve/const-with-typo-in-pattern-binding.rs @@ -0,0 +1,45 @@ +#![deny(unreachable_patterns)] //~ NOTE the lint level is defined here +#![allow(non_snake_case, non_upper_case_globals)] +mod x { + pub use std::env::consts::ARCH; + const X: i32 = 0; //~ NOTE there is a constant of the same name +} +fn main() { + let input: i32 = 42; + + const god: i32 = 1; + const GOOD: i32 = 1; + const BAD: i32 = 2; + + let name: i32 = 42; //~ NOTE there is a binding of the same name + + match input { + X => {} //~ NOTE matches any value + _ => {} //~ ERROR unreachable pattern + //~^ NOTE no value can reach this + } + match input { + GOD => {} //~ HELP you might have meant to pattern match against the value of similarly named constant `god` + //~^ NOTE matches any value + _ => {} //~ ERROR unreachable pattern + //~^ NOTE no value can reach this + } + match input { + GOOOD => {} //~ HELP you might have meant to pattern match against the value of similarly named constant `GOOD` + //~^ NOTE matches any value + _ => {} //~ ERROR unreachable pattern + //~^ NOTE no value can reach this + } + match input { + name => {} + //~^ NOTE matches any value + _ => {} //~ ERROR unreachable pattern + //~^ NOTE no value can reach this + } + match "" { + ARCH => {} //~ HELP you might have meant to pattern match against the value of constant `ARCH` + //~^ NOTE matches any value + _ => {} //~ ERROR unreachable pattern + //~^ NOTE no value can reach this + } +} diff --git a/tests/ui/resolve/const-with-typo-in-pattern-binding.stderr b/tests/ui/resolve/const-with-typo-in-pattern-binding.stderr new file mode 100644 index 0000000000000..a0cdac3fa2538 --- /dev/null +++ b/tests/ui/resolve/const-with-typo-in-pattern-binding.stderr @@ -0,0 +1,78 @@ +error: unreachable pattern + --> $DIR/const-with-typo-in-pattern-binding.rs:18:9 + | +LL | X => {} + | - matches any value +LL | _ => {} + | ^ no value can reach this + | +note: there is a constant of the same name, which could have been used to pattern match against its value instead of introducing a new catch-all binding, but it is not accessible from this scope + --> $DIR/const-with-typo-in-pattern-binding.rs:5:5 + | +LL | const X: i32 = 0; + | ^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/const-with-typo-in-pattern-binding.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/const-with-typo-in-pattern-binding.rs:24:9 + | +LL | GOD => {} + | --- matches any value +LL | +LL | _ => {} + | ^ no value can reach this + | +help: you might have meant to pattern match against the value of similarly named constant `god` instead of introducing a new catch-all binding + | +LL | god => {} + | ~~~ + +error: unreachable pattern + --> $DIR/const-with-typo-in-pattern-binding.rs:30:9 + | +LL | GOOOD => {} + | ----- matches any value +LL | +LL | _ => {} + | ^ no value can reach this + | +help: you might have meant to pattern match against the value of similarly named constant `GOOD` instead of introducing a new catch-all binding + | +LL | GOOD => {} + | ~~~~ + +error: unreachable pattern + --> $DIR/const-with-typo-in-pattern-binding.rs:36:9 + | +LL | name => {} + | ---- matches any value +LL | +LL | _ => {} + | ^ no value can reach this + | +note: there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings + --> $DIR/const-with-typo-in-pattern-binding.rs:14:9 + | +LL | let name: i32 = 42; + | ^^^^ + +error: unreachable pattern + --> $DIR/const-with-typo-in-pattern-binding.rs:42:9 + | +LL | ARCH => {} + | ---- matches any value +LL | +LL | _ => {} + | ^ no value can reach this + | +help: you might have meant to pattern match against the value of constant `ARCH` instead of introducing a new catch-all binding + | +LL | std::env::consts::ARCH => {} + | ~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 5 previous errors + From 666bcbdb2edb829b76d9c2a4447562b397040f36 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Nov 2024 12:27:08 +0100 Subject: [PATCH 05/12] aarch64 softfloat target: always pass floats in int registers --- compiler/rustc_target/src/callconv/aarch64.rs | 62 +++++++++++++++++-- compiler/rustc_target/src/callconv/mod.rs | 1 + tests/codegen/aarch64-softfloat.rs | 48 ++++++++++++++ 3 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 tests/codegen/aarch64-softfloat.rs diff --git a/compiler/rustc_target/src/callconv/aarch64.rs b/compiler/rustc_target/src/callconv/aarch64.rs index 55b65fb1caaaf..67345f0d47b71 100644 --- a/compiler/rustc_target/src/callconv/aarch64.rs +++ b/compiler/rustc_target/src/callconv/aarch64.rs @@ -1,5 +1,10 @@ +use std::iter; + +use rustc_abi::{BackendRepr, Primitive}; + use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform}; use crate::abi::{HasDataLayout, TyAbiInterface}; +use crate::spec::{HasTargetSpec, Target}; /// Indicates the variant of the AArch64 ABI we are compiling for. /// Used to accommodate Apple and Microsoft's deviations from the usual AAPCS ABI. @@ -15,7 +20,7 @@ pub(crate) enum AbiKind { fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option where Ty: TyAbiInterface<'a, C> + Copy, - C: HasDataLayout, + C: HasDataLayout + HasTargetSpec, { arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| { let size = arg.layout.size; @@ -27,7 +32,9 @@ where let valid_unit = match unit.kind { RegKind::Integer => false, - RegKind::Float => true, + // The softfloat ABI treats floats like integers, so they + // do not get homogeneous aggregate treatment. + RegKind::Float => cx.target_spec().abi != "softfloat", RegKind::Vector => size.bits() == 64 || size.bits() == 128, }; @@ -35,10 +42,42 @@ where }) } +fn softfloat_float_abi(target: &Target, arg: &mut ArgAbi<'_, Ty>) { + if target.abi != "softfloat" { + return; + } + // Do *not* use the float registers for passing arguments, as that would make LLVM pick the ABI + // and its choice depends on whether `neon` instructions are enabled. Instead, we follow the + // AAPCS "softfloat" ABI, which specifies that floats should be passed as equivalently-sized + // integers. Nominally this only exists for "R" profile chips, but sometimes people don't want + // to use hardfloats even if the hardware supports them, so we do this for all softfloat + // targets. + if let BackendRepr::Scalar(s) = arg.layout.backend_repr + && let Primitive::Float(f) = s.primitive() + { + arg.cast_to(Reg { kind: RegKind::Integer, size: f.size() }); + } else if let BackendRepr::ScalarPair(s1, s2) = arg.layout.backend_repr + && (matches!(s1.primitive(), Primitive::Float(_)) + || matches!(s2.primitive(), Primitive::Float(_))) + { + // This case can only be reached for the Rust ABI, so we can do whatever we want here as + // long as it does not depend on target features (i.e., as long as we do not use float + // registers). So we pass small things in integer registers and large things via pointer + // indirection. This means we lose the nice "pass it as two arguments" optimization, but we + // currently just have to way to combine a `PassMode::Cast` with that optimization (and we + // need a cast since we want to pass the float as an int). + if arg.layout.size.bits() <= target.pointer_width.into() { + arg.cast_to(Reg { kind: RegKind::Integer, size: arg.layout.size }); + } else { + arg.make_indirect(); + } + } +} + fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, kind: AbiKind) where Ty: TyAbiInterface<'a, C> + Copy, - C: HasDataLayout, + C: HasDataLayout + HasTargetSpec, { if !ret.layout.is_sized() { // Not touching this... @@ -51,6 +90,7 @@ where // See also: ret.extend_integer_width_to(32) } + softfloat_float_abi(cx.target_spec(), ret); return; } if let Some(uniform) = is_homogeneous_aggregate(cx, ret) { @@ -69,7 +109,7 @@ where fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, kind: AbiKind) where Ty: TyAbiInterface<'a, C> + Copy, - C: HasDataLayout, + C: HasDataLayout + HasTargetSpec, { if !arg.layout.is_sized() { // Not touching this... @@ -82,6 +122,8 @@ where // See also: arg.extend_integer_width_to(32); } + softfloat_float_abi(cx.target_spec(), arg); + return; } if let Some(uniform) = is_homogeneous_aggregate(cx, arg) { @@ -112,7 +154,7 @@ where pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, kind: AbiKind) where Ty: TyAbiInterface<'a, C> + Copy, - C: HasDataLayout, + C: HasDataLayout + HasTargetSpec, { if !fn_abi.ret.is_ignore() { classify_ret(cx, &mut fn_abi.ret, kind); @@ -125,3 +167,13 @@ where classify_arg(cx, arg, kind); } } + +pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + for arg in fn_abi.args.iter_mut().chain(iter::once(&mut fn_abi.ret)) { + softfloat_float_abi(cx.target_spec(), arg); + } +} diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index aa639f1624f42..fb0fe4029348e 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -738,6 +738,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { "x86" => x86::compute_rust_abi_info(cx, self, abi), "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self, abi), "loongarch64" => loongarch::compute_rust_abi_info(cx, self, abi), + "aarch64" => aarch64::compute_rust_abi_info(cx, self), _ => {} }; diff --git a/tests/codegen/aarch64-softfloat.rs b/tests/codegen/aarch64-softfloat.rs new file mode 100644 index 0000000000000..14d0054f80cd0 --- /dev/null +++ b/tests/codegen/aarch64-softfloat.rs @@ -0,0 +1,48 @@ +//@ compile-flags: --target aarch64-unknown-none-softfloat -Zmerge-functions=disabled +//@ needs-llvm-components: aarch64 +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} +impl Copy for f32 {} +impl Copy for f64 {} + +// CHECK: i64 @pass_f64_C(i64 {{[^,]*}}) +#[no_mangle] +extern "C" fn pass_f64_C(x: f64) -> f64 { + x +} + +// CHECK: i64 @pass_f32_pair_C(i64 {{[^,]*}}) +#[no_mangle] +extern "C" fn pass_f32_pair_C(x: (f32, f32)) -> (f32, f32) { + x +} + +// CHECK: [2 x i64] @pass_f64_pair_C([2 x i64] {{[^,]*}}) +#[no_mangle] +extern "C" fn pass_f64_pair_C(x: (f64, f64)) -> (f64, f64) { + x +} + +// CHECK: i64 @pass_f64_Rust(i64 {{[^,]*}}) +#[no_mangle] +fn pass_f64_Rust(x: f64) -> f64 { + x +} + +// CHECK: i64 @pass_f32_pair_Rust(i64 {{[^,]*}}) +#[no_mangle] +fn pass_f32_pair_Rust(x: (f32, f32)) -> (f32, f32) { + x +} + +// CHECK: void @pass_f64_pair_Rust(ptr {{[^,]*}}, ptr {{[^,]*}}) +#[no_mangle] +fn pass_f64_pair_Rust(x: (f64, f64)) -> (f64, f64) { + x +} From 7e79f913903a5c9f82e3f2e8afffa535159fcf54 Mon Sep 17 00:00:00 2001 From: binarycat Date: Wed, 20 Nov 2024 15:10:15 -0600 Subject: [PATCH 06/12] implement OsString::truncate --- library/std/src/ffi/os_str.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 79dfb47d0c499..328185d1f2b0c 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -550,11 +550,15 @@ impl OsString { OsStr::from_inner_mut(self.inner.leak()) } - /// Provides plumbing to core `Vec::truncate`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Truncate the the `OsString` to the specified length. + /// + /// # Panics + /// Panics if `len` does not lie on a valid `OsStr` boundary + /// (as described in [`OsStr::slice_encoded_bytes`]). #[inline] - pub(crate) fn truncate(&mut self, len: usize) { + #[unstable(feature = "os_string_truncate", issue = "133262")] + pub fn truncate(&mut self, len: usize) { + self.as_os_str().inner.check_public_boundary(len); self.inner.truncate(len); } From 0465f71d600dbf9591b27ac569fa428cd5f7c013 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 21 Nov 2024 01:34:50 +0000 Subject: [PATCH 07/12] Stop being so bail-y in candidate assembly --- .../src/traits/select/candidate_assembly.rs | 28 ------ .../src/traits/select/mod.rs | 4 - compiler/rustc_ty_utils/src/ty.rs | 6 +- tests/crashes/124350.rs | 17 ---- tests/crashes/125758.rs | 26 ------ tests/crashes/127351.rs | 17 ---- tests/crashes/127353.rs | 18 ---- tests/crashes/127742.rs | 11 --- tests/crashes/130521.rs | 2 +- .../generic_const_exprs/bad-multiply.rs | 18 ++++ .../generic_const_exprs/bad-multiply.stderr | 18 ++++ tests/ui/const-generics/kind_mismatch.rs | 1 - tests/ui/const-generics/kind_mismatch.stderr | 24 +----- .../generic-associated-types/issue-71176.rs | 4 +- .../issue-71176.stderr | 19 +++- .../layout/ice-type-error-in-tail-124031.rs | 3 + .../ice-type-error-in-tail-124031.stderr | 16 +++- .../ui/lazy-type-alias/bad-lazy-type-alias.rs | 18 ++++ .../bad-lazy-type-alias.stderr | 28 ++++++ .../region-error-ice-109072.rs | 1 - .../region-error-ice-109072.stderr | 11 +-- .../issue-68830-spurious-diagnostics.rs | 1 - .../issue-68830-spurious-diagnostics.stderr | 14 +-- ...alller-supplied-obligation-issue-121941.rs | 1 + ...er-supplied-obligation-issue-121941.stderr | 16 +++- tests/ui/traits/issue-78372.rs | 1 - tests/ui/traits/issue-78372.stderr | 24 +----- ...onicalize-fresh-infer-vars-issue-103626.rs | 1 + ...alize-fresh-infer-vars-issue-103626.stderr | 25 +++++- tests/ui/traits/span-bug-issue-121414.rs | 3 +- tests/ui/traits/span-bug-issue-121414.stderr | 20 +---- .../bad-tait-no-substs.rs | 21 +++++ .../bad-tait-no-substs.stderr | 86 +++++++++++++++++++ .../bad-transmute-itiat.rs | 22 +++++ .../bad-transmute-itiat.stderr | 10 +++ .../drop-analysis-on-unconstrained-tait.rs} | 5 +- ...drop-analysis-on-unconstrained-tait.stderr | 10 +++ .../wf/wf-in-foreign-fn-decls-issue-80468.rs | 1 - .../wf-in-foreign-fn-decls-issue-80468.stderr | 17 +--- 39 files changed, 328 insertions(+), 240 deletions(-) delete mode 100644 tests/crashes/124350.rs delete mode 100644 tests/crashes/125758.rs delete mode 100644 tests/crashes/127351.rs delete mode 100644 tests/crashes/127353.rs delete mode 100644 tests/crashes/127742.rs create mode 100644 tests/ui/const-generics/generic_const_exprs/bad-multiply.rs create mode 100644 tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr create mode 100644 tests/ui/lazy-type-alias/bad-lazy-type-alias.rs create mode 100644 tests/ui/lazy-type-alias/bad-lazy-type-alias.stderr create mode 100644 tests/ui/type-alias-impl-trait/bad-tait-no-substs.rs create mode 100644 tests/ui/type-alias-impl-trait/bad-tait-no-substs.stderr create mode 100644 tests/ui/type-alias-impl-trait/bad-transmute-itiat.rs create mode 100644 tests/ui/type-alias-impl-trait/bad-transmute-itiat.stderr rename tests/{crashes/130956.rs => ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.rs} (88%) create mode 100644 tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.stderr diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 345e1cc31f32b..41d430f06df4a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -91,14 +91,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else if tcx.is_lang_item(def_id, LangItem::Sized) { // Sized is never implementable by end-users, it is // always automatically computed. - - // FIXME: Consider moving this check to the top level as it - // may also be useful for predicates other than `Sized` - // Error type cannot possibly implement `Sized` (fixes #123154) - if let Err(e) = obligation.predicate.skip_binder().self_ty().error_reported() { - return Err(SelectionError::Overflow(e.into())); - } - let sized_conditions = self.sized_conditions(obligation); self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates); } else if tcx.is_lang_item(def_id, LangItem::Unsize) { @@ -230,13 +222,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<(), SelectionError<'tcx>> { debug!(?stack.obligation); - // An error type will unify with anything. So, avoid - // matching an error type with `ParamCandidate`. - // This helps us avoid spurious errors like issue #121941. - if stack.obligation.predicate.references_error() { - return Ok(()); - } - let bounds = stack .obligation .param_env @@ -563,19 +548,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PolyTraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - // Essentially any user-written impl will match with an error type, - // so creating `ImplCandidates` isn't useful. However, we might - // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized`) - // This helps us avoid overflow: see issue #72839 - // Since compilation is already guaranteed to fail, this is just - // to try to show the 'nicest' possible errors to the user. - // We don't check for errors in the `ParamEnv` - in practice, - // it seems to cause us to be overly aggressive in deciding - // to give up searching for candidates, leading to spurious errors. - if obligation.predicate.references_error() { - return; - } - let drcx = DeepRejectCtxt::relate_rigid_infer(self.tcx()); let obligation_args = obligation.predicate.skip_binder().trait_ref.args; self.tcx().for_each_relevant_impl( diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5b4e895189b0e..e0c862a81f341 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2487,10 +2487,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let impl_args = self.infcx.fresh_args_for_item(obligation.cause.span, impl_def_id); let trait_ref = impl_trait_header.trait_ref.instantiate(self.tcx(), impl_args); - if trait_ref.references_error() { - return Err(()); - } - debug!(?impl_trait_header); let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 2127ba8a42321..292e777f28802 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -6,8 +6,7 @@ use rustc_index::bit_set::BitSet; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, - TypeVisitor, Upcast, + self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast, }; use rustc_span::DUMMY_SP; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; @@ -95,9 +94,6 @@ fn adt_sized_constraint<'tcx>( let tail_ty = tcx.type_of(tail_def.did).instantiate_identity(); let constraint_ty = sized_constraint_for_ty(tcx, tail_ty)?; - if let Err(guar) = constraint_ty.error_reported() { - return Some(ty::EarlyBinder::bind(Ty::new_error(tcx, guar))); - } // perf hack: if there is a `constraint_ty: Sized` bound, then we know // that the type is sized and do not need to check it on the impl. diff --git a/tests/crashes/124350.rs b/tests/crashes/124350.rs deleted file mode 100644 index d6038f280cf81..0000000000000 --- a/tests/crashes/124350.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ known-bug: #124350 - -struct Node {} - -impl Node -where - SmallVec<{ D * 2 }>:, -{ - fn new() -> Self { - let mut node = Node::new(); - (&a, 0)(); - - node - } -} - -struct SmallVec {} diff --git a/tests/crashes/125758.rs b/tests/crashes/125758.rs deleted file mode 100644 index 86c3b80abab9d..0000000000000 --- a/tests/crashes/125758.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ known-bug: rust-lang/rust#125758 -#![feature(impl_trait_in_assoc_type)] - -trait Trait: Sized { - type Assoc2; -} - -impl Trait for Bar { - type Assoc2 = impl std::fmt::Debug; -} - -struct Foo { - field: ::Assoc2, -} - -enum Bar { - C = 42, - D = 99, -} - -static BAR: u8 = 42; - -static FOO2: (&Foo, &::Assoc2) = - unsafe { (std::mem::transmute(&BAR), std::mem::transmute(&BAR)) }; - -fn main() {} diff --git a/tests/crashes/127351.rs b/tests/crashes/127351.rs deleted file mode 100644 index e3f415948852d..0000000000000 --- a/tests/crashes/127351.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ known-bug: #127351 -#![feature(lazy_type_alias)] -#![allow(incomplete_features)] - -struct Outer0<'a, T>(ExplicitTypeOutlives<'a, T>); -type ExplicitTypeOutlives<'a, T: 'a> = (&'a (), T); - -pub struct Warns { - _significant_drop: ExplicitTypeOutlives, - field: String, -} - -pub fn test(w: Warns) { - _ = || drop(w.field); -} - -fn main() {} diff --git a/tests/crashes/127353.rs b/tests/crashes/127353.rs deleted file mode 100644 index 9bcb90b5c57f8..0000000000000 --- a/tests/crashes/127353.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ known-bug: #127353 -#![feature(type_alias_impl_trait)] -trait Trait {} -type Alias<'a, U> = impl Trait; - -fn f<'a>() -> Alias<'a, ()> {} - -pub enum UninhabitedVariants { - Tuple(Alias), -} - -struct A; - -fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { - match x {} -} - -fn main() {} diff --git a/tests/crashes/127742.rs b/tests/crashes/127742.rs deleted file mode 100644 index 24add45413566..0000000000000 --- a/tests/crashes/127742.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #127742 -struct Vtable(dyn Cap); // missing lifetime - -trait Cap<'a> {} - -union Transmute { - t: u64, // ICEs with u64, u128, or usize. Correctly errors with u32. - u: &'static Vtable, -} - -const G: &'static Vtable = unsafe { Transmute { t: 1 }.u }; diff --git a/tests/crashes/130521.rs b/tests/crashes/130521.rs index 7c078ab579094..ccc2b444b822a 100644 --- a/tests/crashes/130521.rs +++ b/tests/crashes/130521.rs @@ -6,7 +6,7 @@ struct Vtable(dyn Cap); trait Cap<'a> {} union Transmute { - t: u64, + t: u128, u: &'static Vtable, } diff --git a/tests/ui/const-generics/generic_const_exprs/bad-multiply.rs b/tests/ui/const-generics/generic_const_exprs/bad-multiply.rs new file mode 100644 index 0000000000000..1af6d5742b1f6 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/bad-multiply.rs @@ -0,0 +1,18 @@ +// regression test for #124350 + +struct Node {} + +impl Node +where + SmallVec<{ D * 2 }>:, + //~^ ERROR generic parameters may not be used in const operations + //~| ERROR constant provided when a type was expected +{ + fn new() -> Self { + Node::new() + } +} + +struct SmallVec(T1); + +fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr b/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr new file mode 100644 index 0000000000000..a8d6cebabe718 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr @@ -0,0 +1,18 @@ +error: generic parameters may not be used in const operations + --> $DIR/bad-multiply.rs:7:16 + | +LL | SmallVec<{ D * 2 }>:, + | ^ cannot perform const operation using `D` + | + = help: const parameters may only be used as standalone arguments, i.e. `D` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error[E0747]: constant provided when a type was expected + --> $DIR/bad-multiply.rs:7:14 + | +LL | SmallVec<{ D * 2 }>:, + | ^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0747`. diff --git a/tests/ui/const-generics/kind_mismatch.rs b/tests/ui/const-generics/kind_mismatch.rs index bab58d5952a5f..ecdc01a5ef901 100644 --- a/tests/ui/const-generics/kind_mismatch.rs +++ b/tests/ui/const-generics/kind_mismatch.rs @@ -20,5 +20,4 @@ pub fn remove_key>() -> S { fn main() { let map: KeyHolder<0> = remove_key::<_, _>(); - //~^ ERROR: the trait bound `KeyHolder<0>: SubsetExcept<_>` is not satisfied } diff --git a/tests/ui/const-generics/kind_mismatch.stderr b/tests/ui/const-generics/kind_mismatch.stderr index e13bc6ee058d0..1487b18961986 100644 --- a/tests/ui/const-generics/kind_mismatch.stderr +++ b/tests/ui/const-generics/kind_mismatch.stderr @@ -14,26 +14,6 @@ LL | impl ContainsKey for KeyHolder {} | | | help: consider changing this type parameter to a const parameter: `const K: u8` -error[E0277]: the trait bound `KeyHolder<0>: SubsetExcept<_>` is not satisfied - --> $DIR/kind_mismatch.rs:22:45 - | -LL | let map: KeyHolder<0> = remove_key::<_, _>(); - | ^ the trait `ContainsKey<0>` is not implemented for `KeyHolder<0>` - | -note: required for `KeyHolder<0>` to implement `SubsetExcept<_>` - --> $DIR/kind_mismatch.rs:15:28 - | -LL | impl> SubsetExcept

for T {} - | -------------- ^^^^^^^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here -note: required by a bound in `remove_key` - --> $DIR/kind_mismatch.rs:17:25 - | -LL | pub fn remove_key>() -> S { - | ^^^^^^^^^^^^^^^ required by this bound in `remove_key` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0277, E0747. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0747`. diff --git a/tests/ui/generic-associated-types/issue-71176.rs b/tests/ui/generic-associated-types/issue-71176.rs index b33fda8e15443..7fffe312f4b7b 100644 --- a/tests/ui/generic-associated-types/issue-71176.rs +++ b/tests/ui/generic-associated-types/issue-71176.rs @@ -16,6 +16,8 @@ struct Holder { fn main() { Holder { - inner: Box::new(()), //~ ERROR: the trait `Provider` cannot be made into an object + inner: Box::new(()), + //~^ ERROR: the trait `Provider` cannot be made into an object + //~| ERROR: the trait `Provider` cannot be made into an object }; } diff --git a/tests/ui/generic-associated-types/issue-71176.stderr b/tests/ui/generic-associated-types/issue-71176.stderr index 15d5a3df6f276..1cd2ed0d313dc 100644 --- a/tests/ui/generic-associated-types/issue-71176.stderr +++ b/tests/ui/generic-associated-types/issue-71176.stderr @@ -80,7 +80,24 @@ LL | type A<'a>; = help: consider moving `A` to another trait = help: only type `()` implements the trait, consider using it directly instead -error: aborting due to 5 previous errors +error[E0038]: the trait `Provider` cannot be made into an object + --> $DIR/issue-71176.rs:19:16 + | +LL | inner: Box::new(()), + | ^^^^^^^^^^^^ `Provider` cannot be made into an object + | +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/issue-71176.rs:2:10 + | +LL | trait Provider { + | -------- this trait cannot be made into an object... +LL | type A<'a>; + | ^ ...because it contains the generic associated type `A` + = help: consider moving `A` to another trait + = help: only type `()` implements the trait, consider using it directly instead + = note: required for the cast from `Box<()>` to `Box<(dyn Provider = _> + 'static), {type error}>` + +error: aborting due to 6 previous errors Some errors have detailed explanations: E0038, E0107. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/layout/ice-type-error-in-tail-124031.rs b/tests/ui/layout/ice-type-error-in-tail-124031.rs index 0a2be11740358..ecd6f3d56f3f4 100644 --- a/tests/ui/layout/ice-type-error-in-tail-124031.rs +++ b/tests/ui/layout/ice-type-error-in-tail-124031.rs @@ -1,3 +1,5 @@ +//@ normalize-stderr-test: "\d+ bits" -> "$$BITS bits" + // Regression test for issue #124031 // Checks that we don't ICE when the tail // of an ADT has a type error @@ -16,5 +18,6 @@ struct Other { fn main() { unsafe { std::mem::transmute::, Option<&Other>>(None); + //~^ ERROR cannot transmute between types of different sizes } } diff --git a/tests/ui/layout/ice-type-error-in-tail-124031.stderr b/tests/ui/layout/ice-type-error-in-tail-124031.stderr index 57dc83f92dfda..a066e8574dc50 100644 --- a/tests/ui/layout/ice-type-error-in-tail-124031.stderr +++ b/tests/ui/layout/ice-type-error-in-tail-124031.stderr @@ -1,5 +1,5 @@ error[E0046]: not all trait items implemented, missing: `RefTarget` - --> $DIR/ice-type-error-in-tail-124031.rs:9:1 + --> $DIR/ice-type-error-in-tail-124031.rs:11:1 | LL | type RefTarget; | -------------- `RefTarget` from trait @@ -7,6 +7,16 @@ LL | type RefTarget; LL | impl Trait for () {} | ^^^^^^^^^^^^^^^^^ missing `RefTarget` in implementation -error: aborting due to 1 previous error +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/ice-type-error-in-tail-124031.rs:20:9 + | +LL | std::mem::transmute::, Option<&Other>>(None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `Option<()>` ($BITS bits) + = note: target type: `Option<&Other>` ($BITS bits) + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0046`. +Some errors have detailed explanations: E0046, E0512. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/lazy-type-alias/bad-lazy-type-alias.rs b/tests/ui/lazy-type-alias/bad-lazy-type-alias.rs new file mode 100644 index 0000000000000..6ded9118700c0 --- /dev/null +++ b/tests/ui/lazy-type-alias/bad-lazy-type-alias.rs @@ -0,0 +1,18 @@ +// regression test for #127351 + +#![feature(lazy_type_alias)] +//~^ WARN the feature `lazy_type_alias` is incomplete + +type ExplicitTypeOutlives = T; + +pub struct Warns { + _significant_drop: ExplicitTypeOutlives, + //~^ ERROR missing generics for type alias `ExplicitTypeOutlives` + field: String, +} + +pub fn test(w: Warns) { + let _ = || drop(w.field); +} + +fn main() {} diff --git a/tests/ui/lazy-type-alias/bad-lazy-type-alias.stderr b/tests/ui/lazy-type-alias/bad-lazy-type-alias.stderr new file mode 100644 index 0000000000000..3a5ded60241b1 --- /dev/null +++ b/tests/ui/lazy-type-alias/bad-lazy-type-alias.stderr @@ -0,0 +1,28 @@ +warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/bad-lazy-type-alias.rs:3:12 + | +LL | #![feature(lazy_type_alias)] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #112792 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0107]: missing generics for type alias `ExplicitTypeOutlives` + --> $DIR/bad-lazy-type-alias.rs:9:24 + | +LL | _significant_drop: ExplicitTypeOutlives, + | ^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument + | +note: type alias defined here, with 1 generic parameter: `T` + --> $DIR/bad-lazy-type-alias.rs:6:6 + | +LL | type ExplicitTypeOutlives = T; + | ^^^^^^^^^^^^^^^^^^^^ - +help: add missing generic argument + | +LL | _significant_drop: ExplicitTypeOutlives, + | +++ + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/nll/user-annotations/region-error-ice-109072.rs b/tests/ui/nll/user-annotations/region-error-ice-109072.rs index bcdc6651cf5bb..3f2ad3ccbf582 100644 --- a/tests/ui/nll/user-annotations/region-error-ice-109072.rs +++ b/tests/ui/nll/user-annotations/region-error-ice-109072.rs @@ -11,5 +11,4 @@ impl Lt<'missing> for () { //~ ERROR undeclared lifetime fn main() { let _: <() as Lt<'_>>::T = &(); - //~^ ERROR the trait bound `(): Lt<'_>` is not satisfied } diff --git a/tests/ui/nll/user-annotations/region-error-ice-109072.stderr b/tests/ui/nll/user-annotations/region-error-ice-109072.stderr index c187c17d98c68..d90971bed25ba 100644 --- a/tests/ui/nll/user-annotations/region-error-ice-109072.stderr +++ b/tests/ui/nll/user-annotations/region-error-ice-109072.stderr @@ -21,13 +21,6 @@ help: consider introducing lifetime `'missing` here LL | impl<'missing> Lt<'missing> for () { | ++++++++++ -error[E0277]: the trait bound `(): Lt<'_>` is not satisfied - --> $DIR/region-error-ice-109072.rs:13:13 - | -LL | let _: <() as Lt<'_>>::T = &(); - | ^^ the trait `Lt<'_>` is not implemented for `()` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0261, E0277. -For more information about an error, try `rustc --explain E0261`. +For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/specialization/issue-68830-spurious-diagnostics.rs b/tests/ui/specialization/issue-68830-spurious-diagnostics.rs index a7487b8aecb9c..d11ec79833217 100644 --- a/tests/ui/specialization/issue-68830-spurious-diagnostics.rs +++ b/tests/ui/specialization/issue-68830-spurious-diagnostics.rs @@ -17,7 +17,6 @@ impl MyTrait for D { } impl MyTrait for BadStruct { -//~^ ERROR: conflicting implementations of trait `MyTrait<_>` for type `BadStruct` fn foo() {} } diff --git a/tests/ui/specialization/issue-68830-spurious-diagnostics.stderr b/tests/ui/specialization/issue-68830-spurious-diagnostics.stderr index 13f6ae0805dad..0ecec03a023eb 100644 --- a/tests/ui/specialization/issue-68830-spurious-diagnostics.stderr +++ b/tests/ui/specialization/issue-68830-spurious-diagnostics.stderr @@ -4,16 +4,6 @@ error[E0412]: cannot find type `MissingType` in this scope LL | err: MissingType | ^^^^^^^^^^^ not found in this scope -error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `BadStruct` - --> $DIR/issue-68830-spurious-diagnostics.rs:19:1 - | -LL | impl MyTrait for D { - | --------------------------- first implementation here -... -LL | impl MyTrait for BadStruct { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `BadStruct` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0119, E0412. -For more information about an error, try `rustc --explain E0119`. +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.rs b/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.rs index a08407683d8fe..85c70a21f6839 100644 --- a/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.rs +++ b/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.rs @@ -1,5 +1,6 @@ fn function() { foo == 2; //~ ERROR cannot find value `foo` in this scope [E0425] + //~^ ERROR mismatched types } fn main() {} diff --git a/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.stderr b/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.stderr index 2da731dcc4b14..8010c0842ba97 100644 --- a/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.stderr +++ b/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.stderr @@ -4,6 +4,18 @@ error[E0425]: cannot find value `foo` in this scope LL | foo == 2; | ^^^ not found in this scope -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.rs:2:12 + | +LL | fn function() { + | - expected this type parameter +LL | foo == 2; + | ^ expected type parameter `T`, found integer + | + = note: expected type parameter `T` + found type `{integer}` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0425`. +Some errors have detailed explanations: E0308, E0425. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/issue-78372.rs b/tests/ui/traits/issue-78372.rs index 82b13cc0b6238..f03baf2ceca36 100644 --- a/tests/ui/traits/issue-78372.rs +++ b/tests/ui/traits/issue-78372.rs @@ -10,5 +10,4 @@ trait X { } trait Marker {} impl Marker for dyn Foo {} -//~^ ERROR cannot be made into an object fn main() {} diff --git a/tests/ui/traits/issue-78372.stderr b/tests/ui/traits/issue-78372.stderr index 4cc2c59fd8dc5..86234d15a5d4b 100644 --- a/tests/ui/traits/issue-78372.stderr +++ b/tests/ui/traits/issue-78372.stderr @@ -55,24 +55,6 @@ LL | impl DispatchFromDyn> for T {} = help: add `#![feature(dispatch_from_dyn)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/issue-78372.rs:12:17 - | -LL | fn foo(self: Smaht); - | -------------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self` -... -LL | impl Marker for dyn Foo {} - | ^^^^^^^ `Foo` cannot be made into an object - | -note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-78372.rs:9:18 - | -LL | trait Foo: X {} - | --- this trait cannot be made into an object... -LL | trait X { -LL | fn foo(self: Smaht); - | ^^^^^^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on - error[E0307]: invalid `self` parameter type: `Smaht` --> $DIR/issue-78372.rs:9:18 | @@ -88,7 +70,7 @@ error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion LL | impl DispatchFromDyn> for T {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0038, E0307, E0378, E0412, E0658. -For more information about an error, try `rustc --explain E0038`. +Some errors have detailed explanations: E0307, E0378, E0412, E0658. +For more information about an error, try `rustc --explain E0307`. diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs index 3af299e5b115a..4aadd45c49c1e 100644 --- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs @@ -10,6 +10,7 @@ fn w<'a, T: 'a, F: Fn(&'a T)>() { let b: &dyn FromResidual = &(); //~^ ERROR: the trait `FromResidual` cannot be made into an object //~| ERROR: the trait `FromResidual` cannot be made into an object + //~| ERROR: the trait `FromResidual` cannot be made into an object } fn main() {} diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr index 960802e2f8f82..c67a8c05379cd 100644 --- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr @@ -6,6 +6,29 @@ LL | let b: &dyn FromResidual = &(); | = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause +error[E0038]: the trait `FromResidual` cannot be made into an object + --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:32 + | +LL | let b: &dyn FromResidual = &(); + | ^^^ `FromResidual` cannot be made into an object + | +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8 + | +LL | trait FromResidual::Residual> { + | ------------ this trait cannot be made into an object... +LL | fn from_residual(residual: R) -> Self; + | ^^^^^^^^^^^^^ ...because associated function `from_residual` has no `self` parameter + = note: required for the cast from `&()` to `&dyn FromResidual<{type error}>` +help: consider turning `from_residual` into a method by giving it a `&self` argument + | +LL | fn from_residual(&self, residual: R) -> Self; + | ++++++ +help: alternatively, consider constraining `from_residual` so it does not apply to trait objects + | +LL | fn from_residual(residual: R) -> Self where Self: Sized; + | +++++++++++++++++ + error[E0038]: the trait `FromResidual` cannot be made into an object --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:12 | @@ -28,6 +51,6 @@ help: alternatively, consider constraining `from_residual` so it does not apply LL | fn from_residual(residual: R) -> Self where Self: Sized; | +++++++++++++++++ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/span-bug-issue-121414.rs b/tests/ui/traits/span-bug-issue-121414.rs index ec38d8c2de6a6..2f4ad34f0c858 100644 --- a/tests/ui/traits/span-bug-issue-121414.rs +++ b/tests/ui/traits/span-bug-issue-121414.rs @@ -6,8 +6,7 @@ impl<'a> Bar for Foo<'f> { //~ ERROR undeclared lifetime type Type = u32; } -fn test() //~ ERROR the trait bound `for<'a> Foo<'a>: Bar` is not satisfied - //~| ERROR the trait bound `for<'a> Foo<'a>: Bar` is not satisfied +fn test() where for<'a> as Bar>::Type: Sized, { diff --git a/tests/ui/traits/span-bug-issue-121414.stderr b/tests/ui/traits/span-bug-issue-121414.stderr index e2ef6672cd57a..744806a341506 100644 --- a/tests/ui/traits/span-bug-issue-121414.stderr +++ b/tests/ui/traits/span-bug-issue-121414.stderr @@ -6,22 +6,6 @@ LL | impl<'a> Bar for Foo<'f> { | | | help: consider introducing lifetime `'f` here: `'f,` -error[E0277]: the trait bound `for<'a> Foo<'a>: Bar` is not satisfied - --> $DIR/span-bug-issue-121414.rs:9:1 - | -LL | / fn test() -LL | | -LL | | where -LL | | for<'a> as Bar>::Type: Sized, - | |__________________________________________^ the trait `for<'a> Bar` is not implemented for `Foo<'a>` - -error[E0277]: the trait bound `for<'a> Foo<'a>: Bar` is not satisfied - --> $DIR/span-bug-issue-121414.rs:9:4 - | -LL | fn test() - | ^^^^ the trait `for<'a> Bar` is not implemented for `Foo<'a>` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0261, E0277. -For more information about an error, try `rustc --explain E0261`. +For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/type-alias-impl-trait/bad-tait-no-substs.rs b/tests/ui/type-alias-impl-trait/bad-tait-no-substs.rs new file mode 100644 index 0000000000000..18cfb1c1f93be --- /dev/null +++ b/tests/ui/type-alias-impl-trait/bad-tait-no-substs.rs @@ -0,0 +1,21 @@ +// regression test for #127353 + +#![feature(type_alias_impl_trait)] +trait Trait {} +type Alias<'a, U> = impl Trait; +//~^ ERROR unconstrained opaque type + +pub enum UninhabitedVariants { + Tuple(Alias), + //~^ ERROR missing lifetime specifier + //~| ERROR missing generics + //~| ERROR non-defining opaque type use in defining scope +} + +fn uwu(x: UninhabitedVariants) { + //~^ ERROR item does not constrain + match x {} + //~^ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/bad-tait-no-substs.stderr b/tests/ui/type-alias-impl-trait/bad-tait-no-substs.stderr new file mode 100644 index 0000000000000..cf366c55ea816 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/bad-tait-no-substs.stderr @@ -0,0 +1,86 @@ +error[E0106]: missing lifetime specifier + --> $DIR/bad-tait-no-substs.rs:9:11 + | +LL | Tuple(Alias), + | ^^^^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL ~ pub enum UninhabitedVariants<'a> { +LL ~ Tuple(Alias<'a>), + | + +error[E0107]: missing generics for type alias `Alias` + --> $DIR/bad-tait-no-substs.rs:9:11 + | +LL | Tuple(Alias), + | ^^^^^ expected 1 generic argument + | +note: type alias defined here, with 1 generic parameter: `U` + --> $DIR/bad-tait-no-substs.rs:5:6 + | +LL | type Alias<'a, U> = impl Trait; + | ^^^^^ - +help: add missing generic argument + | +LL | Tuple(Alias), + | +++ + +error[E0792]: non-defining opaque type use in defining scope + --> $DIR/bad-tait-no-substs.rs:9:11 + | +LL | Tuple(Alias), + | ^^^^^ argument `'_` is not a generic parameter + | +note: for this opaque type + --> $DIR/bad-tait-no-substs.rs:5:21 + | +LL | type Alias<'a, U> = impl Trait; + | ^^^^^^^^^^^^^ + +error: item does not constrain `Alias::{opaque#0}`, but has it in its signature + --> $DIR/bad-tait-no-substs.rs:15:4 + | +LL | fn uwu(x: UninhabitedVariants) { + | ^^^ + | + = note: consider moving the opaque type's declaration and defining uses into a separate module +note: this opaque type is in the signature + --> $DIR/bad-tait-no-substs.rs:5:21 + | +LL | type Alias<'a, U> = impl Trait; + | ^^^^^^^^^^^^^ + +error: unconstrained opaque type + --> $DIR/bad-tait-no-substs.rs:5:21 + | +LL | type Alias<'a, U> = impl Trait; + | ^^^^^^^^^^^^^ + | + = note: `Alias` must be used in combination with a concrete type within the same module + +error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` not covered + --> $DIR/bad-tait-no-substs.rs:17:11 + | +LL | match x {} + | ^ pattern `UninhabitedVariants::Tuple(_)` not covered + | +note: `UninhabitedVariants` defined here + --> $DIR/bad-tait-no-substs.rs:8:10 + | +LL | pub enum UninhabitedVariants { + | ^^^^^^^^^^^^^^^^^^^ +LL | Tuple(Alias), + | ----- not covered + = note: the matched value is of type `UninhabitedVariants` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ match x { +LL + UninhabitedVariants::Tuple(_) => todo!(), +LL + } + | + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0004, E0106, E0107, E0792. +For more information about an error, try `rustc --explain E0004`. diff --git a/tests/ui/type-alias-impl-trait/bad-transmute-itiat.rs b/tests/ui/type-alias-impl-trait/bad-transmute-itiat.rs new file mode 100644 index 0000000000000..8314b28eeac4b --- /dev/null +++ b/tests/ui/type-alias-impl-trait/bad-transmute-itiat.rs @@ -0,0 +1,22 @@ +// regression test for rust-lang/rust#125758 + +#![feature(impl_trait_in_assoc_type)] + +trait Trait { + type Assoc2; +} + +struct Bar; +impl Trait for Bar { + type Assoc2 = impl std::fmt::Debug; + //~^ ERROR unconstrained opaque type +} + +struct Foo { + field: ::Assoc2, +} + +static BAR: u8 = 42; +static FOO2: &Foo = unsafe { std::mem::transmute(&BAR) }; + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/bad-transmute-itiat.stderr b/tests/ui/type-alias-impl-trait/bad-transmute-itiat.stderr new file mode 100644 index 0000000000000..6cbf6c83ff4ce --- /dev/null +++ b/tests/ui/type-alias-impl-trait/bad-transmute-itiat.stderr @@ -0,0 +1,10 @@ +error: unconstrained opaque type + --> $DIR/bad-transmute-itiat.rs:11:19 + | +LL | type Assoc2 = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `Assoc2` must be used in combination with a concrete type within the same impl + +error: aborting due to 1 previous error + diff --git a/tests/crashes/130956.rs b/tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.rs similarity index 88% rename from tests/crashes/130956.rs rename to tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.rs index ebb986d123f91..4332f1264a80b 100644 --- a/tests/crashes/130956.rs +++ b/tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.rs @@ -1,8 +1,11 @@ -//@ known-bug: #130956 +// Regression test for #130956 + +#![feature(type_alias_impl_trait)] mod impl_trait_mod { use super::*; pub type OpaqueBlock = impl Trait; + //~^ ERROR unconstrained opaque type pub type OpaqueIf = impl Trait; pub struct BlockWrapper(OpaqueBlock); diff --git a/tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.stderr b/tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.stderr new file mode 100644 index 0000000000000..8e5838d5ddf55 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.stderr @@ -0,0 +1,10 @@ +error: unconstrained opaque type + --> $DIR/drop-analysis-on-unconstrained-tait.rs:7:28 + | +LL | pub type OpaqueBlock = impl Trait; + | ^^^^^^^^^^ + | + = note: `OpaqueBlock` must be used in combination with a concrete type within the same module + +error: aborting due to 1 previous error + diff --git a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs index e6d4e2ee01a27..0be5127dcc4da 100644 --- a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs +++ b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs @@ -14,5 +14,4 @@ impl Trait for Ref {} //~ ERROR: implicit elided lifetime not allowed here extern "C" { pub fn repro(_: Wrapper); - //~^ ERROR the trait bound `Ref<'_>: Trait` is not satisfied } diff --git a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr index 59b55b2732d30..0af4ab022e1eb 100644 --- a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr +++ b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr @@ -9,19 +9,6 @@ help: indicate the anonymous lifetime LL | impl Trait for Ref<'_> {} | ++++ -error[E0277]: the trait bound `Ref<'_>: Trait` is not satisfied - --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:21 - | -LL | pub fn repro(_: Wrapper); - | ^^^^^^^^^^^^ the trait `Trait` is not implemented for `Ref<'_>` - | -note: required by a bound in `Wrapper` - --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:8:23 - | -LL | pub struct Wrapper(T); - | ^^^^^ required by this bound in `Wrapper` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0277, E0726. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0726`. From 9dfc682834e950890b9bf883e3a1ca8c3888aaf1 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Tue, 19 Nov 2024 11:37:30 +0000 Subject: [PATCH 08/12] generate-copyright: Now generates a library file too. We only run reuse once, so the output has to be filtered to find only the files that are relevant to the library tree. Outputs build/COPYRIGHT.html and build/COPYRIGHT-library.html. --- src/bootstrap/src/core/build_steps/run.rs | 3 +- .../generate-copyright/src/cargo_metadata.rs | 3 +- src/tools/generate-copyright/src/main.rs | 149 +++++++++++++++--- .../templates/COPYRIGHT-library.html | 53 +++++++ 4 files changed, 180 insertions(+), 28 deletions(-) create mode 100644 src/tools/generate-copyright/templates/COPYRIGHT-library.html diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index a6dff7fde8054..1a0a90564e6ad 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -211,12 +211,13 @@ impl Step for GenerateCopyright { fn run(self, builder: &Builder<'_>) -> Self::Output { let license_metadata = builder.ensure(CollectLicenseMetadata); - // Temporary location, it will be moved to the proper one once it's accurate. let dest = builder.out.join("COPYRIGHT.html"); + let dest_libstd = builder.out.join("COPYRIGHT-library.html"); let mut cmd = builder.tool_cmd(Tool::GenerateCopyright); cmd.env("LICENSE_METADATA", &license_metadata); cmd.env("DEST", &dest); + cmd.env("DEST_LIBSTD", &dest_libstd); cmd.env("OUT_DIR", &builder.out); cmd.env("CARGO", &builder.initial_cargo); cmd.run(builder); diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs index 31b18c3dc1035..5fadee8544895 100644 --- a/src/tools/generate-copyright/src/cargo_metadata.rs +++ b/src/tools/generate-copyright/src/cargo_metadata.rs @@ -52,14 +52,13 @@ pub struct PackageMetadata { /// assume `reuse` has covered it already. pub fn get_metadata_and_notices( cargo: &Path, - dest: &Path, + vendor_path: &Path, root_path: &Path, manifest_paths: &[&Path], ) -> Result, Error> { let mut output = get_metadata(cargo, root_path, manifest_paths)?; // Now do a cargo-vendor and grab everything - let vendor_path = dest.join("vendor"); println!("Vendoring deps into {}...", vendor_path.display()); run_cargo_vendor(cargo, &vendor_path, manifest_paths)?; diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs index afa75d0d67140..f9d96b594626d 100644 --- a/src/tools/generate-copyright/src/main.rs +++ b/src/tools/generate-copyright/src/main.rs @@ -6,13 +6,6 @@ use rinja::Template; mod cargo_metadata; -#[derive(Template)] -#[template(path = "COPYRIGHT.html")] -struct CopyrightTemplate { - in_tree: Node, - dependencies: BTreeMap, -} - /// The entry point to the binary. /// /// You should probably let `bootstrap` execute this program instead of running it directly. @@ -20,49 +13,89 @@ struct CopyrightTemplate { /// Run `x.py run generate-copyright` fn main() -> Result<(), Error> { let dest_file = env_path("DEST")?; + let libstd_dest_file = env_path("DEST_LIBSTD")?; let out_dir = env_path("OUT_DIR")?; let cargo = env_path("CARGO")?; let license_metadata = env_path("LICENSE_METADATA")?; - let collected_tree_metadata: Metadata = - serde_json::from_slice(&std::fs::read(&license_metadata)?)?; - let root_path = std::path::absolute(".")?; - let workspace_paths = [ - Path::new("./Cargo.toml"), - Path::new("./src/tools/cargo/Cargo.toml"), - Path::new("./library/Cargo.toml"), - ]; - let mut collected_cargo_metadata = - cargo_metadata::get_metadata_and_notices(&cargo, &out_dir, &root_path, &workspace_paths)?; - let stdlib_set = - cargo_metadata::get_metadata(&cargo, &root_path, &[Path::new("./library/std/Cargo.toml")])?; + // Scan Cargo dependencies + let mut collected_cargo_metadata = + cargo_metadata::get_metadata_and_notices(&cargo, &out_dir.join("vendor"), &root_path, &[ + Path::new("./Cargo.toml"), + Path::new("./src/tools/cargo/Cargo.toml"), + Path::new("./library/Cargo.toml"), + ])?; + + let library_collected_cargo_metadata = cargo_metadata::get_metadata_and_notices( + &cargo, + &out_dir.join("library-vendor"), + &root_path, + &[Path::new("./library/Cargo.toml")], + )?; for (key, value) in collected_cargo_metadata.iter_mut() { - value.is_in_libstd = Some(stdlib_set.contains_key(key)); + value.is_in_libstd = Some(library_collected_cargo_metadata.contains_key(key)); } + // Load JSON output by reuse + let collected_tree_metadata: Metadata = + serde_json::from_slice(&std::fs::read(&license_metadata)?)?; + + // Find libstd sub-set + let library_collected_tree_metadata = Metadata { + files: collected_tree_metadata + .files + .trim_clone(&Path::new("./library"), &Path::new(".")) + .unwrap(), + }; + + // Output main file let template = CopyrightTemplate { in_tree: collected_tree_metadata.files, dependencies: collected_cargo_metadata, }; - let output = template.render()?; - std::fs::write(&dest_file, output)?; + // Output libstd subset file + let template = LibraryCopyrightTemplate { + in_tree: library_collected_tree_metadata.files, + dependencies: library_collected_cargo_metadata, + }; + let output = template.render()?; + std::fs::write(&libstd_dest_file, output)?; + Ok(()) } +/// The HTML template for the toolchain copyright file +#[derive(Template)] +#[template(path = "COPYRIGHT.html")] +struct CopyrightTemplate { + in_tree: Node, + dependencies: BTreeMap, +} + +/// The HTML template for the library copyright file +#[derive(Template)] +#[template(path = "COPYRIGHT-library.html")] +struct LibraryCopyrightTemplate { + in_tree: Node, + dependencies: BTreeMap, +} + /// Describes a tree of metadata for our filesystem tree -#[derive(serde::Deserialize)] +/// +/// Must match the JSON emitted by the `CollectLicenseMetadata` bootstrap tool. +#[derive(serde::Deserialize, Clone, Debug, PartialEq, Eq)] struct Metadata { files: Node, } /// Describes one node in our metadata tree -#[derive(serde::Deserialize, rinja::Template)] +#[derive(serde::Deserialize, rinja::Template, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "kebab-case", tag = "type")] #[template(path = "Node.html")] pub(crate) enum Node { @@ -72,8 +105,74 @@ pub(crate) enum Node { Group { files: Vec, directories: Vec, license: License }, } +impl Node { + /// Clone, this node, but only if the path to the item is within the match path + fn trim_clone(&self, match_path: &Path, parent_path: &Path) -> Option { + match self { + Node::Root { children } => { + let mut filtered_children = Vec::new(); + for node in children { + if let Some(child_node) = node.trim_clone(match_path, parent_path) { + filtered_children.push(child_node); + } + } + if filtered_children.is_empty() { + None + } else { + Some(Node::Root { children: filtered_children }) + } + } + Node::Directory { name, children, license } => { + let child_name = parent_path.join(name); + if !(child_name.starts_with(match_path) || match_path.starts_with(&child_name)) { + return None; + } + let mut filtered_children = Vec::new(); + for node in children { + if let Some(child_node) = node.trim_clone(match_path, &child_name) { + filtered_children.push(child_node); + } + } + Some(Node::Directory { + name: name.clone(), + children: filtered_children, + license: license.clone(), + }) + } + Node::File { name, license } => { + let child_name = parent_path.join(name); + if !(child_name.starts_with(match_path) || match_path.starts_with(&child_name)) { + return None; + } + Some(Node::File { name: name.clone(), license: license.clone() }) + } + Node::Group { files, directories, license } => { + let mut filtered_child_files = Vec::new(); + for child in files { + let child_name = parent_path.join(child); + if child_name.starts_with(match_path) || match_path.starts_with(&child_name) { + filtered_child_files.push(child.clone()); + } + } + let mut filtered_child_dirs = Vec::new(); + for child in directories { + let child_name = parent_path.join(child); + if child_name.starts_with(match_path) || match_path.starts_with(&child_name) { + filtered_child_dirs.push(child.clone()); + } + } + Some(Node::Group { + files: filtered_child_files, + directories: filtered_child_dirs, + license: license.clone(), + }) + } + } + } +} + /// A License has an SPDX license name and a list of copyright holders. -#[derive(serde::Deserialize)] +#[derive(serde::Deserialize, Clone, Debug, PartialEq, Eq)] struct License { spdx: String, copyright: Vec, diff --git a/src/tools/generate-copyright/templates/COPYRIGHT-library.html b/src/tools/generate-copyright/templates/COPYRIGHT-library.html new file mode 100644 index 0000000000000..2c1eba741db0a --- /dev/null +++ b/src/tools/generate-copyright/templates/COPYRIGHT-library.html @@ -0,0 +1,53 @@ + + + + + Copyright notices for The Rust Standard Library + + + +

Copyright notices for The Rust Standard Library

+ +

This file describes the copyright and licensing information for the Rust +Standard Library source code within The Rust Project git tree, and the +third-party dependencies used when building the Rust Standard Library.

+ +

Table of Contents

+ + +

In-tree files

+ +

The following licenses cover the in-tree source files that were used in this +release:

+ +{{ in_tree|safe }} + +

Out-of-tree dependencies

+ +

The following licenses cover the out-of-tree crates that were used in the +Rust Standard Library in this release:

+ +{% for (key, value) in dependencies %} +

📦 {{key.name}}-{{key.version}}

+

URL: https://crates.io/crates/{{ key.name }}/{{ key.version }}

+

Authors: {{ value.authors|join(", ") }}

+

License: {{ value.license }}

+ {% let len = value.notices.len() %} + {% if len > 0 %} +

Notices: + {% for (notice_name, notice_text) in value.notices %} +

+ {{ notice_name }} +
+{{ notice_text }}
+                
+
+ {% endfor %} +

+ {% endif %} +{% endfor %} + + \ No newline at end of file From d8e8fc5575ba3f3aa31cb8c7f47df73e06a38e92 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 21 Nov 2024 09:39:00 -0800 Subject: [PATCH 09/12] Keep list of submodules close to list of vendored workspaces This moves the list of submodules needed to vendor close to the list of cargo workspaces with the intent to help ensure they keep up-to-date and in sync. --- src/bootstrap/src/core/build_steps/dist.rs | 2 +- src/bootstrap/src/core/build_steps/vendor.rs | 49 +++++++++++--------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index c022285211fab..0c1cc9420ba6b 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1026,7 +1026,7 @@ impl Step for PlainSourceTarball { let mut cmd = command(&builder.initial_cargo); cmd.arg("vendor").arg("--versioned-dirs"); - for p in default_paths_to_vendor(builder) { + for (p, _) in default_paths_to_vendor(builder) { cmd.arg("--sync").arg(p); } diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs index d6e6e3462d2af..ce044c4a4a7a4 100644 --- a/src/bootstrap/src/core/build_steps/vendor.rs +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -4,24 +4,26 @@ use crate::core::build_steps::tool::SUBMODULES_FOR_RUSTBOOK; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::utils::exec::command; -/// List of default paths used for vendoring for `x vendor` and dist tarballs. -pub fn default_paths_to_vendor(builder: &Builder<'_>) -> Vec { - let mut paths = vec![]; - for p in [ - "src/tools/cargo/Cargo.toml", - "src/tools/rust-analyzer/Cargo.toml", - "compiler/rustc_codegen_cranelift/Cargo.toml", - "compiler/rustc_codegen_gcc/Cargo.toml", - "library/Cargo.toml", - "src/bootstrap/Cargo.toml", - "src/tools/rustbook/Cargo.toml", - "src/tools/rustc-perf/Cargo.toml", - "src/tools/opt-dist/Cargo.toml", - ] { - paths.push(builder.src.join(p)); - } - - paths +/// Returns the cargo workspaces to vendor for `x vendor` and dist tarballs. +/// +/// Returns a `Vec` of `(path_to_manifest, submodules_required)` where +/// `path_to_manifest` is the cargo workspace, and `submodules_required` is +/// the set of submodules that must be available. +pub fn default_paths_to_vendor(builder: &Builder<'_>) -> Vec<(PathBuf, Vec<&'static str>)> { + [ + ("src/tools/cargo/Cargo.toml", vec!["src/tools/cargo"]), + ("src/tools/rust-analyzer/Cargo.toml", vec![]), + ("compiler/rustc_codegen_cranelift/Cargo.toml", vec![]), + ("compiler/rustc_codegen_gcc/Cargo.toml", vec![]), + ("library/Cargo.toml", vec![]), + ("src/bootstrap/Cargo.toml", vec![]), + ("src/tools/rustbook/Cargo.toml", SUBMODULES_FOR_RUSTBOOK.into()), + ("src/tools/rustc-perf/Cargo.toml", vec!["src/tools/rustc-perf"]), + ("src/tools/opt-dist/Cargo.toml", vec![]), + ] + .into_iter() + .map(|(path, submodules)| (builder.src.join(path), submodules)) + .collect() } #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -56,15 +58,16 @@ impl Step for Vendor { cmd.arg("--versioned-dirs"); } + let to_vendor = default_paths_to_vendor(builder); // These submodules must be present for `x vendor` to work. - for submodule in - SUBMODULES_FOR_RUSTBOOK.iter().chain(["src/tools/cargo", "src/tools/rustc-perf"].iter()) - { - builder.build.require_submodule(submodule, None); + for (_, submodules) in &to_vendor { + for submodule in submodules { + builder.build.require_submodule(submodule, None); + } } // Sync these paths by default. - for p in default_paths_to_vendor(builder) { + for (p, _) in &to_vendor { cmd.arg("--sync").arg(p); } From 29328334149f02ffe39ee047d34a1a046cd21537 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Fri, 22 Nov 2024 10:14:40 +0000 Subject: [PATCH 10/12] generate-copyright: Fixup comment for get_metadata_and_notices. --- src/tools/generate-copyright/src/cargo_metadata.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs index 5fadee8544895..420579372acb0 100644 --- a/src/tools/generate-copyright/src/cargo_metadata.rs +++ b/src/tools/generate-copyright/src/cargo_metadata.rs @@ -45,7 +45,7 @@ pub struct PackageMetadata { /// Use `cargo metadata` and `cargo vendor` to get a list of dependencies and their license data. /// -/// This will involve running `cargo vendor` into `${BUILD}/vendor` so we can +/// This will involve running `cargo vendor` into `vendor_path` so we can /// grab the license files. /// /// Any dependency with a path beginning with `root_path` is ignored, as we From 7540306a4994df05e4aca27130b2757e55000ac7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 11 Nov 2024 17:36:18 +0000 Subject: [PATCH 11/12] Simplify logic a bit --- compiler/rustc_middle/src/ty/print/pretty.rs | 181 +++++++----------- compiler/rustc_type_ir/src/predicate.rs | 13 -- .../opaque-used-in-extraneous-argument.stderr | 2 +- 3 files changed, 69 insertions(+), 127 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 039c988f5c972..5de089ee014d2 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -16,8 +16,8 @@ use rustc_hir::definitions::{DefKey, DefPathDataName}; use rustc_macros::{Lift, extension}; use rustc_session::Limit; use rustc_session::cstore::{ExternCrate, ExternCrateSource}; -use rustc_span::FileNameDisplayPreference; use rustc_span::symbol::{Ident, Symbol, kw}; +use rustc_span::{FileNameDisplayPreference, sym}; use rustc_type_ir::{Upcast as _, elaborate}; use smallvec::SmallVec; @@ -26,8 +26,8 @@ use super::*; use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; use crate::query::{IntoQueryParam, Providers}; use crate::ty::{ - ConstInt, Expr, GenericArgKind, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, - TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, + ConstInt, Expr, GenericArgKind, ParamConst, ScalarInt, Term, TermKind, TraitPredicate, + TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; macro_rules! p { @@ -1007,24 +1007,22 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } self.insert_trait_and_projection( - trait_ref, - pred.polarity, + bound_predicate.rebind(pred), None, &mut traits, &mut fn_traits, ); } ty::ClauseKind::Projection(pred) => { - let proj_ref = bound_predicate.rebind(pred); - let trait_ref = proj_ref.required_poly_trait_ref(tcx); - - // Projection type entry -- the def-id for naming, and the ty. - let proj_ty = (proj_ref.projection_def_id(), proj_ref.term()); + let proj = bound_predicate.rebind(pred); + let trait_ref = proj.map_bound(|proj| TraitPredicate { + trait_ref: proj.projection_term.trait_ref(tcx), + polarity: ty::PredicatePolarity::Positive, + }); self.insert_trait_and_projection( trait_ref, - ty::PredicatePolarity::Positive, - Some(proj_ty), + Some((proj.projection_def_id(), proj.term())), &mut traits, &mut fn_traits, ); @@ -1042,88 +1040,63 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound; - for (fn_once_trait_ref, entry) in fn_traits { + for (bound_args, entry) in fn_traits { write!(self, "{}", if first { "" } else { " + " })?; write!(self, "{}", if paren_needed { "(" } else { "" })?; - self.wrap_binder(&fn_once_trait_ref, |trait_ref, cx| { - define_scoped_cx!(cx); - // Get the (single) generic ty (the args) of this FnOnce trait ref. - let generics = tcx.generics_of(trait_ref.def_id); - let own_args = generics.own_args_no_defaults(tcx, trait_ref.args); - - match (entry.return_ty, own_args[0].expect_ty()) { - // We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded - // a return type. - (Some(return_ty), arg_tys) if matches!(arg_tys.kind(), ty::Tuple(_)) => { - let name = if entry.fn_trait_ref.is_some() { - "Fn" - } else if entry.fn_mut_trait_ref.is_some() { - "FnMut" - } else { - "FnOnce" - }; - - p!(write("{}(", name)); + let trait_def_id = + tcx.fn_trait_kind_to_def_id(entry.kind).expect("expected Fn lang items"); - for (idx, ty) in arg_tys.tuple_fields().iter().enumerate() { - if idx > 0 { - p!(", "); - } - p!(print(ty)); - } + if let Some(return_ty) = entry.return_ty { + self.wrap_binder(&bound_args, |args, cx| { + define_scoped_cx!(cx); + p!(write("{}", tcx.item_name(trait_def_id))); + p!("("); - p!(")"); - if let Some(ty) = return_ty.skip_binder().as_type() { - if !ty.is_unit() { - p!(" -> ", print(return_ty)); - } + for (idx, ty) in args.iter().enumerate() { + if idx > 0 { + p!(", "); } - p!(write("{}", if paren_needed { ")" } else { "" })); - - first = false; + p!(print(ty)); } - // If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the - // trait_refs we collected in the OpaqueFnEntry as normal trait refs. - _ => { - if entry.has_fn_once { - traits - .entry((fn_once_trait_ref, ty::PredicatePolarity::Positive)) - .or_default() - .extend( - // Group the return ty with its def id, if we had one. - entry.return_ty.map(|ty| { - (tcx.require_lang_item(LangItem::FnOnceOutput, None), ty) - }), - ); - } - if let Some(trait_ref) = entry.fn_mut_trait_ref { - traits.entry((trait_ref, ty::PredicatePolarity::Positive)).or_default(); - } - if let Some(trait_ref) = entry.fn_trait_ref { - traits.entry((trait_ref, ty::PredicatePolarity::Positive)).or_default(); + + p!(")"); + if let Some(ty) = return_ty.skip_binder().as_type() { + if !ty.is_unit() { + p!(" -> ", print(return_ty)); } } - } + p!(write("{}", if paren_needed { ")" } else { "" })); - Ok(()) - })?; + first = false; + Ok(()) + })?; + } else { + // Otherwise, render this like a regular trait. + traits.insert( + bound_args.map_bound(|args| ty::TraitPredicate { + polarity: ty::PredicatePolarity::Positive, + trait_ref: ty::TraitRef::new(tcx, trait_def_id, [Ty::new_tup(tcx, args)]), + }), + FxIndexMap::default(), + ); + } } // Print the rest of the trait types (that aren't Fn* family of traits) - for ((trait_ref, polarity), assoc_items) in traits { + for (trait_pred, assoc_items) in traits { write!(self, "{}", if first { "" } else { " + " })?; - self.wrap_binder(&trait_ref, |trait_ref, cx| { + self.wrap_binder(&trait_pred, |trait_pred, cx| { define_scoped_cx!(cx); - if polarity == ty::PredicatePolarity::Negative { + if trait_pred.polarity == ty::PredicatePolarity::Negative { p!("!"); } - p!(print(trait_ref.print_only_trait_name())); + p!(print(trait_pred.trait_ref.print_only_trait_name())); - let generics = tcx.generics_of(trait_ref.def_id); - let own_args = generics.own_args_no_defaults(tcx, trait_ref.args); + let generics = tcx.generics_of(trait_pred.def_id()); + let own_args = generics.own_args_no_defaults(tcx, trait_pred.trait_ref.args); if !own_args.is_empty() || !assoc_items.is_empty() { let mut first = true; @@ -1230,51 +1203,37 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { /// traits map or fn_traits map, depending on if the trait is in the Fn* family of traits. fn insert_trait_and_projection( &mut self, - trait_ref: ty::PolyTraitRef<'tcx>, - polarity: ty::PredicatePolarity, + trait_pred: ty::PolyTraitPredicate<'tcx>, proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>, traits: &mut FxIndexMap< - (ty::PolyTraitRef<'tcx>, ty::PredicatePolarity), + ty::PolyTraitPredicate<'tcx>, FxIndexMap>>, >, - fn_traits: &mut FxIndexMap, OpaqueFnEntry<'tcx>>, + fn_traits: &mut FxIndexMap>>, OpaqueFnEntry<'tcx>>, ) { - let trait_def_id = trait_ref.def_id(); + let tcx = self.tcx(); + let trait_def_id = trait_pred.def_id(); - // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce - // super-trait ref and record it there. - // We skip negative Fn* bounds since they can't use parenthetical notation anyway. - if polarity == ty::PredicatePolarity::Positive - && let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait() + if trait_pred.polarity() == ty::PredicatePolarity::Positive + && let Some(kind) = tcx.fn_trait_kind_from_def_id(trait_def_id) + && let ty::Tuple(types) = *trait_pred.skip_binder().trait_ref.args.type_at(1).kind() { - // If we have a FnOnce, then insert it into - if trait_def_id == fn_once_trait { - let entry = fn_traits.entry(trait_ref).or_default(); - // Optionally insert the return_ty as well. - if let Some((_, ty)) = proj_ty { - entry.return_ty = Some(ty); - } - entry.has_fn_once = true; - return; - } else if self.tcx().is_lang_item(trait_def_id, LangItem::FnMut) { - let super_trait_ref = elaborate::supertraits(self.tcx(), trait_ref) - .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait) - .unwrap(); - - fn_traits.entry(super_trait_ref).or_default().fn_mut_trait_ref = Some(trait_ref); - return; - } else if self.tcx().is_lang_item(trait_def_id, LangItem::Fn) { - let super_trait_ref = elaborate::supertraits(self.tcx(), trait_ref) - .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait) - .unwrap(); - - fn_traits.entry(super_trait_ref).or_default().fn_trait_ref = Some(trait_ref); - return; + let entry = fn_traits + .entry(trait_pred.rebind(types)) + .or_insert_with(|| OpaqueFnEntry { kind, return_ty: None }); + if kind.extends(entry.kind) { + entry.kind = kind; + } + if let Some((proj_def_id, proj_ty)) = proj_ty + && tcx.item_name(proj_def_id) == sym::Output + { + entry.return_ty = Some(proj_ty); } + return; } // Otherwise, just group our traits and projection types. - traits.entry((trait_ref, polarity)).or_default().extend(proj_ty); + traits.entry(trait_pred).or_default().extend(proj_ty); } fn pretty_print_inherent_projection( @@ -3415,11 +3374,7 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { trimmed_def_paths, ..*providers }; } -#[derive(Default)] pub struct OpaqueFnEntry<'tcx> { - // The trait ref is already stored as a key, so just track if we have it as a real predicate - has_fn_once: bool, - fn_mut_trait_ref: Option>, - fn_trait_ref: Option>, + kind: ty::ClosureKind, return_ty: Option>>, } diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 8a8e624e72a2d..5e3a3df003843 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -684,19 +684,6 @@ impl ty::Binder> { self.skip_binder().projection_term.trait_def_id(cx) } - /// Get the trait ref required for this projection to be well formed. - /// Note that for generic associated types the predicates of the associated - /// type also need to be checked. - #[inline] - pub fn required_poly_trait_ref(&self, cx: I) -> ty::Binder> { - // Note: unlike with `TraitRef::to_poly_trait_ref()`, - // `self.0.trait_ref` is permitted to have escaping regions. - // This is because here `self` has a `Binder` and so does our - // return value, so we are preserving the number of binding - // levels. - self.map_bound(|predicate| predicate.projection_term.trait_ref(cx)) - } - pub fn term(&self) -> ty::Binder { self.map_bound(|predicate| predicate.term) } diff --git a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr index caaac5434c56a..6f0f287fe122e 100644 --- a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr +++ b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr @@ -74,7 +74,7 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/opaque-used-in-extraneous-argument.rs:20:5 | LL | open_parent(&old_path) - | ^^^^^^^^^^^ --------- unexpected argument of type `&impl FnOnce<{type error}, Output = {type error}> + Fn<{type error}> + 'static` + | ^^^^^^^^^^^ --------- unexpected argument of type `&impl Fn<{type error}> + FnOnce<{type error}, Output = {type error}> + 'static` | note: function defined here --> $DIR/opaque-used-in-extraneous-argument.rs:12:4 From 4c53ad5f244c840049fa706e6e334c1efc19fe7d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 11 Nov 2024 17:42:35 +0000 Subject: [PATCH 12/12] Pretty print AsyncFn traits too --- .../rustc_middle/src/middle/lang_items.rs | 11 ++++++ compiler/rustc_middle/src/ty/print/pretty.rs | 34 +++++++++++++------ .../fn-exception-target-features.stderr | 4 +-- .../async-closures/fn-exception.stderr | 8 ++--- .../async-closures/pretty-async-fn-opaque.rs | 14 ++++++++ .../pretty-async-fn-opaque.stderr | 17 ++++++++++ 6 files changed, 71 insertions(+), 17 deletions(-) create mode 100644 tests/ui/async-await/async-closures/pretty-async-fn-opaque.rs create mode 100644 tests/ui/async-await/async-closures/pretty-async-fn-opaque.stderr diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index b20673fe8daf5..7a91bfad4836c 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -68,6 +68,17 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Given a [`ty::ClosureKind`], get the [`DefId`] of its corresponding `Fn`-family + /// trait, if it is defined. + pub fn async_fn_trait_kind_to_def_id(self, kind: ty::ClosureKind) -> Option { + let items = self.lang_items(); + match kind { + ty::ClosureKind::Fn => items.async_fn_trait(), + ty::ClosureKind::FnMut => items.async_fn_mut_trait(), + ty::ClosureKind::FnOnce => items.async_fn_once_trait(), + } + } + /// Returns `true` if `id` is a `DefId` of [`Fn`], [`FnMut`] or [`FnOnce`] traits. pub fn is_fn_trait(self, id: DefId) -> bool { self.fn_trait_kind_from_def_id(id).is_some() diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 5de089ee014d2..cd4123f0a3f56 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -993,10 +993,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { match bound_predicate.skip_binder() { ty::ClauseKind::Trait(pred) => { - let trait_ref = bound_predicate.rebind(pred.trait_ref); - // Don't print `+ Sized`, but rather `+ ?Sized` if absent. - if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) { + if tcx.is_lang_item(pred.def_id(), LangItem::Sized) { match pred.polarity { ty::PredicatePolarity::Positive => { has_sized_bound = true; @@ -1040,12 +1038,15 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound; - for (bound_args, entry) in fn_traits { + for ((bound_args, is_async), entry) in fn_traits { write!(self, "{}", if first { "" } else { " + " })?; write!(self, "{}", if paren_needed { "(" } else { "" })?; - let trait_def_id = - tcx.fn_trait_kind_to_def_id(entry.kind).expect("expected Fn lang items"); + let trait_def_id = if is_async { + tcx.async_fn_trait_kind_to_def_id(entry.kind).expect("expected AsyncFn lang items") + } else { + tcx.fn_trait_kind_to_def_id(entry.kind).expect("expected Fn lang items") + }; if let Some(return_ty) = entry.return_ty { self.wrap_binder(&bound_args, |args, cx| { @@ -1209,17 +1210,28 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::PolyTraitPredicate<'tcx>, FxIndexMap>>, >, - fn_traits: &mut FxIndexMap>>, OpaqueFnEntry<'tcx>>, + fn_traits: &mut FxIndexMap< + (ty::Binder<'tcx, &'tcx ty::List>>, bool), + OpaqueFnEntry<'tcx>, + >, ) { let tcx = self.tcx(); let trait_def_id = trait_pred.def_id(); + let fn_trait_and_async = if let Some(kind) = tcx.fn_trait_kind_from_def_id(trait_def_id) { + Some((kind, false)) + } else if let Some(kind) = tcx.async_fn_trait_kind_from_def_id(trait_def_id) { + Some((kind, true)) + } else { + None + }; + if trait_pred.polarity() == ty::PredicatePolarity::Positive - && let Some(kind) = tcx.fn_trait_kind_from_def_id(trait_def_id) + && let Some((kind, is_async)) = fn_trait_and_async && let ty::Tuple(types) = *trait_pred.skip_binder().trait_ref.args.type_at(1).kind() { let entry = fn_traits - .entry(trait_pred.rebind(types)) + .entry((trait_pred.rebind(types), is_async)) .or_insert_with(|| OpaqueFnEntry { kind, return_ty: None }); if kind.extends(entry.kind) { entry.kind = kind; @@ -3148,10 +3160,10 @@ define_print_and_forward_display! { TraitRefPrintSugared<'tcx> { if !with_reduced_queries() - && let Some(kind) = cx.tcx().fn_trait_kind_from_def_id(self.0.def_id) + && cx.tcx().trait_def(self.0.def_id).paren_sugar && let ty::Tuple(args) = self.0.args.type_at(1).kind() { - p!(write("{}", kind.as_str()), "("); + p!(write("{}", cx.tcx().item_name(self.0.def_id)), "("); for (i, arg) in args.iter().enumerate() { if i > 0 { p!(", "); diff --git a/tests/ui/async-await/async-closures/fn-exception-target-features.stderr b/tests/ui/async-await/async-closures/fn-exception-target-features.stderr index 396167f407055..e965c40fb5b86 100644 --- a/tests/ui/async-await/async-closures/fn-exception-target-features.stderr +++ b/tests/ui/async-await/async-closures/fn-exception-target-features.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `fn() -> Pin + 'static)>> {target_feature}: AsyncFn<()>` is not satisfied +error[E0277]: the trait bound `fn() -> Pin + 'static)>> {target_feature}: AsyncFn()` is not satisfied --> $DIR/fn-exception-target-features.rs:16:10 | LL | test(target_feature); - | ---- ^^^^^^^^^^^^^^ the trait `AsyncFn<()>` is not implemented for fn item `fn() -> Pin + 'static)>> {target_feature}` + | ---- ^^^^^^^^^^^^^^ the trait `AsyncFn()` is not implemented for fn item `fn() -> Pin + 'static)>> {target_feature}` | | | required by a bound introduced by this call | diff --git a/tests/ui/async-await/async-closures/fn-exception.stderr b/tests/ui/async-await/async-closures/fn-exception.stderr index bacd079af0f2d..20132e428332a 100644 --- a/tests/ui/async-await/async-closures/fn-exception.stderr +++ b/tests/ui/async-await/async-closures/fn-exception.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `unsafe fn() -> Pin + 'static)>> {unsafety}: AsyncFn<()>` is not satisfied +error[E0277]: the trait bound `unsafe fn() -> Pin + 'static)>> {unsafety}: AsyncFn()` is not satisfied --> $DIR/fn-exception.rs:19:10 | LL | test(unsafety); - | ---- ^^^^^^^^ the trait `AsyncFn<()>` is not implemented for fn item `unsafe fn() -> Pin + 'static)>> {unsafety}` + | ---- ^^^^^^^^ the trait `AsyncFn()` is not implemented for fn item `unsafe fn() -> Pin + 'static)>> {unsafety}` | | | required by a bound introduced by this call | @@ -12,11 +12,11 @@ note: required by a bound in `test` LL | fn test(f: impl async Fn()) {} | ^^^^^^^^^^ required by this bound in `test` -error[E0277]: the trait bound `extern "C" fn() -> Pin + 'static)>> {abi}: AsyncFn<()>` is not satisfied +error[E0277]: the trait bound `extern "C" fn() -> Pin + 'static)>> {abi}: AsyncFn()` is not satisfied --> $DIR/fn-exception.rs:20:10 | LL | test(abi); - | ---- ^^^ the trait `AsyncFn<()>` is not implemented for fn item `extern "C" fn() -> Pin + 'static)>> {abi}` + | ---- ^^^ the trait `AsyncFn()` is not implemented for fn item `extern "C" fn() -> Pin + 'static)>> {abi}` | | | required by a bound introduced by this call | diff --git a/tests/ui/async-await/async-closures/pretty-async-fn-opaque.rs b/tests/ui/async-await/async-closures/pretty-async-fn-opaque.rs new file mode 100644 index 0000000000000..2e7cf1b09fd00 --- /dev/null +++ b/tests/ui/async-await/async-closures/pretty-async-fn-opaque.rs @@ -0,0 +1,14 @@ +//@ edition: 2021 + +#![feature(async_closure)] + +use std::ops::AsyncFnMut; + +fn produce() -> impl AsyncFnMut() -> &'static str { + async || "" +} + +fn main() { + let x: i32 = produce(); + //~^ ERROR mismatched types +} diff --git a/tests/ui/async-await/async-closures/pretty-async-fn-opaque.stderr b/tests/ui/async-await/async-closures/pretty-async-fn-opaque.stderr new file mode 100644 index 0000000000000..863e61eb35ad4 --- /dev/null +++ b/tests/ui/async-await/async-closures/pretty-async-fn-opaque.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/pretty-async-fn-opaque.rs:12:18 + | +LL | fn produce() -> impl AsyncFnMut() -> &'static str { + | --------------------------------- the found opaque type +... +LL | let x: i32 = produce(); + | --- ^^^^^^^^^ expected `i32`, found opaque type + | | + | expected due to this + | + = note: expected type `i32` + found opaque type `impl AsyncFnMut() -> &'static str` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`.