From 0c6077984f944193c457fc41ee6777c6f359c4f4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 12 Apr 2024 16:16:40 +0000 Subject: [PATCH 01/22] Avoid an intermediate Option and just create the resulting enum directly --- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 64b816553dff9..7dcaa16b6ffa0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -301,18 +301,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { formal_input_ty, coerced_ty, ); - let subtyping_error = match supertype_error { + + // If neither check failed, the types are compatible + match supertype_error { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); - None + Compatibility::Compatible } - Err(err) => Some(err), - }; - - // If neither check failed, the types are compatible - match subtyping_error { - None => Compatibility::Compatible, - Some(_) => Compatibility::Incompatible(subtyping_error), + Err(err) => Compatibility::Incompatible(Some(err)), } }; From 24653a56640305a64d31da8f87c4575112ff7184 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 12 Apr 2024 16:17:31 +0000 Subject: [PATCH 02/22] Remove a HACK by instead inferring opaque types during expected/formal type checking --- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 26 ------------------- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index f1e82543a993a..681af1a14c2c7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -711,32 +711,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let formal_ret = self.resolve_vars_with_obligations(formal_ret); let ret_ty = expected_ret.only_has_type(self)?; - // HACK(oli-obk): This is a hack to keep RPIT and TAIT in sync wrt their behaviour. - // Without it, the inference - // variable will get instantiated with the opaque type. The inference variable often - // has various helpful obligations registered for it that help closures figure out their - // signature. If we infer the inference var to the opaque type, the closure won't be able - // to find those obligations anymore, and it can't necessarily find them from the opaque - // type itself. We could be more powerful with inference if we *combined* the obligations - // so that we got both the obligations from the opaque type and the ones from the inference - // variable. That will accept more code than we do right now, so we need to carefully consider - // the implications. - // Note: this check is pessimistic, as the inference type could be matched with something other - // than the opaque type, but then we need a new `TypeRelation` just for this specific case and - // can't re-use `sup` below. - // See tests/ui/impl-trait/hidden-type-is-opaque.rs and - // tests/ui/impl-trait/hidden-type-is-opaque-2.rs for examples that hit this path. - if formal_ret.has_infer_types() { - for ty in ret_ty.walk() { - if let ty::GenericArgKind::Type(ty) = ty.unpack() - && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind() - && self.can_define_opaque_ty(def_id) - { - return None; - } - } - } - let expect_args = self .fudge_inference_if_ok(|| { let ocx = ObligationCtxt::new(self); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 7dcaa16b6ffa0..13226d304c8f0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -297,7 +297,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 3. Check if the formal type is a supertype of the checked one // and register any such obligations for future type checks let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup( - DefineOpaqueTypes::No, + DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty, ); From e4f4e58dc3c20617f4a245a38237ed5fe0224911 Mon Sep 17 00:00:00 2001 From: JeanCASPAR <55629512+JeanCASPAR@users.noreply.github.com> Date: Sun, 24 Mar 2024 12:43:53 +0000 Subject: [PATCH 03/22] Port build_reduce_graph --- compiler/rustc_resolve/messages.ftl | 60 ++++++- .../rustc_resolve/src/build_reduced_graph.rs | 63 ++----- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_resolve/src/errors.rs | 161 +++++++++++++++++- 4 files changed, 235 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index a03bb6acd41a7..b26cf9aa3363d 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -11,6 +11,8 @@ resolve_added_macro_use = resolve_ancestor_only = visibilities can only be restricted to ancestor modules +resolve_arguments_macro_use_not_allowed = arguments to `macro_use` are not allowed here + resolve_associated_const_with_similar_name_exists = there is an associated constant with a similar name @@ -20,6 +22,10 @@ resolve_associated_fn_with_similar_name_exists = resolve_associated_type_with_similar_name_exists = there is an associated type with a similar name +resolve_attempt_to_define_builtin_macro_twice = + attempted to define built-in macro more than once + .note = previously defined here + resolve_attempt_to_use_non_constant_value_in_constant = attempt to use a non-constant value in a constant @@ -32,6 +38,8 @@ resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion = resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion = this would need to be a `{$suggestion}` +resolve_bad_macro_import = bad macro import + resolve_binding_in_never_pattern = never patterns cannot contain variable bindings .suggestion = use a wildcard `_` instead @@ -100,13 +108,31 @@ resolve_const_param_in_non_trivial_anon_const = resolve_const_param_in_ty_of_const_param = const parameters may not be used in the type of const parameters -resolve_expected_found = +resolve_elided_anonymous_lifetime_report_error = + `&` without an explicit lifetime name cannot be used here + .label = explicit lifetime name needed here + +resolve_elided_anonymous_lifetime_report_error_suggestion = + consider introducing a higher-ranked lifetime here + +resolve_expected_module_found = expected module, found {$res} `{$path_str}` .label = not a module +resolve_explicit_anonymous_lifetime_report_error = + `'_` cannot be used here + .label = `'_` is a reserved lifetime name + resolve_explicit_unsafe_traits = unsafe traits like `{$ident}` should be implemented explicitly +resolve_extern_crate_loading_macro_not_at_crate_root = + an `extern crate` loading macros must be at the crate root + +resolve_extern_crate_self_requires_renaming = + `extern crate self;` requires renaming + .suggestion = rename the `self` crate to be able to import it + resolve_forward_declared_generic_param = generic parameters with a default cannot use forward declared identifiers .label = defaulted generic parameters cannot be forward declared @@ -135,17 +161,20 @@ resolve_generic_params_from_outer_item_static = a `static` is a separate item fr resolve_generic_params_from_outer_item_ty_param = type parameter from outer item - resolve_ident_bound_more_than_once_in_parameter_list = identifier `{$identifier}` is bound more than once in this parameter list .label = used as parameter more than once +resolve_implicit_elided_lifetimes_not_allowed_here = implicit elided lifetime not allowed here + resolve_ident_bound_more_than_once_in_same_pattern = identifier `{$identifier}` is bound more than once in the same pattern .label = used in a pattern more than once resolve_imported_crate = `$crate` may not be imported +resolve_imported_macro_not_found = imported macro not found + resolve_imports_cannot_refer_to = imports cannot refer to {$what} @@ -183,11 +212,22 @@ resolve_lowercase_self = resolve_macro_defined_later = a macro with the same name exists, but it appears later at here +resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments = + macro-expanded `extern crate` items cannot shadow names passed with `--extern` + resolve_macro_expected_found = expected {$expected}, found {$found} `{$macro_path}` +resolve_macro_extern_deprecated = + `#[macro_escape]` is a deprecated synonym for `#[macro_use]` + .help = try an outer attribute: `#[macro_use]` + resolve_macro_use_extern_crate_self = `#[macro_use]` is not supported on `extern crate self` +resolve_macro_use_name_already_in_use = + `{$name}` is already in scope + .note = macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560) + resolve_method_not_member_of_trait = method `{$method}` is not a member of trait `{$trait_}` .label = not a member of trait `{$trait_}` @@ -217,6 +257,8 @@ resolve_param_in_ty_of_const_param = the type of const parameters must not depend on other generic parameters .label = the type must not depend on the parameter `{$name}` +resolve_pattern_doesnt_bind_name = pattern doesn't bind `{$name}` + resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it .help = you can define integration tests in a directory named `tests` @@ -254,6 +296,9 @@ resolve_self_in_generic_param_default = generic parameters cannot use `Self` in their defaults .label = `Self` in generic parameter default +resolve_static_lifetime_is_reserved = invalid lifetime parameter name: `{$ident}` + .label = 'static is a reserved lifetime name + resolve_tool_module_imported = cannot use a tool module through an import .note = the tool module imported here @@ -284,12 +329,18 @@ resolve_undeclared_label = use of undeclared label `{$name}` .label = undeclared label `{$name}` +resolve_underscore_lifetime_is_reserved = `'_` cannot be used here + .label = `'_` is a reserved lifetime name + resolve_unexpected_res_change_ty_to_const_param_sugg = you might have meant to write a const parameter here resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg = if you meant to collect the rest of the slice in `{$ident}`, use the at operator +resolve_unnamed_crate_root_import = + crate root imports need to be explicitly named: `use crate as name;` + resolve_unreachable_label = use of unreachable label `{$name}` .label = unreachable label `{$name}` @@ -312,3 +363,8 @@ resolve_variable_bound_with_different_mode = variable `{$variable_name}` is bound inconsistently across alternatives separated by `|` .label = bound in different ways .first_binding_span = first binding + +resolve_variable_is_not_bound_in_all_patterns = + variable `{$name}` is not bound in all patterns + +resolve_variable_not_in_all_patterns = variable not in all patterns diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 375f20dd809f2..1b6387acf71e2 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -19,7 +19,6 @@ use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind}; use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId}; use rustc_attr as attr; use rustc_data_structures::sync::Lrc; -use rustc_errors::{codes::*, struct_span_code_err, Applicability}; use rustc_expand::expand::AstFragment; use rustc_hir::def::{self, *}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; @@ -529,11 +528,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } if ident.name == kw::Crate { - self.r.dcx().span_err( - ident.span, - "crate root imports need to be explicitly named: \ - `use crate as name;`", - ); + self.r.dcx().emit_err(errors::UnnamedCrateRootImport { span: ident.span }); } let kind = ImportKind::Single { @@ -848,16 +843,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let expansion = parent_scope.expansion; let (used, module, binding) = if orig_name.is_none() && ident.name == kw::SelfLower { - self.r - .dcx() - .struct_span_err(item.span, "`extern crate self;` requires renaming") - .with_span_suggestion( - item.span, - "rename the `self` crate to be able to import it", - "extern crate self as name;", - Applicability::HasPlaceholders, - ) - .emit(); + self.r.dcx().emit_err(errors::ExternCrateSelfRequiresRenaming { span: sp }); return; } else if orig_name == Some(kw::SelfLower) { Some(self.r.graph_root) @@ -897,9 +883,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { if parent == self.r.graph_root { if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) { if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() { - let msg = "macro-expanded `extern crate` items cannot \ - shadow names passed with `--extern`"; - self.r.dcx().span_err(item.span, msg); + self.r.dcx().emit_err( + errors::MacroExpandedExternCrateCannotShadowExternArguments { + span: item.span, + }, + ); // `return` is intended to discard this binding because it's an // unregistered ambiguity error which would result in a panic // caused by inconsistency `path_res` @@ -1030,10 +1018,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { allow_shadowing: bool, ) { if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing { - let msg = format!("`{name}` is already in scope"); - let note = - "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; - self.r.dcx().struct_span_err(span, msg).with_note(note).emit(); + self.r.dcx().emit_err(errors::MacroUseNameAlreadyInUse { span, name }); } } @@ -1044,13 +1029,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { for attr in &item.attrs { if attr.has_name(sym::macro_use) { if self.parent_scope.module.parent.is_some() { - struct_span_code_err!( - self.r.dcx(), - item.span, - E0468, - "an `extern crate` loading macros must be at the crate root" - ) - .emit(); + self.r.dcx().emit_err(errors::ExternCrateLoadingMacroNotAtCrateRoot { + span: item.span, + }); } if let ItemKind::ExternCrate(Some(orig_name)) = item.kind { if orig_name == kw::SelfLower { @@ -1058,7 +1039,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } let ill_formed = |span| { - struct_span_code_err!(self.r.dcx(), span, E0466, "bad macro import").emit(); + self.r.dcx().emit_err(errors::BadMacroImport { span }); }; match attr.meta() { Some(meta) => match meta.kind { @@ -1143,13 +1124,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { allow_shadowing, ); } else { - struct_span_code_err!( - self.r.dcx(), - ident.span, - E0469, - "imported macro not found" - ) - .emit(); + self.r.dcx().emit_err(errors::ImportedMacroNotFound { span: ident.span }); } } } @@ -1160,18 +1135,16 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { for attr in attrs { if attr.has_name(sym::macro_escape) { - let msg = "`#[macro_escape]` is a deprecated synonym for `#[macro_use]`"; - let mut err = self.r.dcx().struct_span_warn(attr.span, msg); - if let ast::AttrStyle::Inner = attr.style { - err.help("try an outer attribute: `#[macro_use]`"); - } - err.emit(); + let inner_attribute = matches!(attr.style, ast::AttrStyle::Inner).then_some(()); + self.r + .dcx() + .emit_warn(errors::MacroExternDeprecated { span: attr.span, inner_attribute }); } else if !attr.has_name(sym::macro_use) { continue; } if !attr.is_word() { - self.r.dcx().span_err(attr.span, "arguments to `macro_use` are not allowed here"); + self.r.dcx().emit_err(errors::ArgumentsMacroUseNotAllowed { span: attr.span }); } return true; } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 4057bc9ffbd07..1a14558468dd2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1005,7 +1005,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ResolutionError::FailedToResolve { segment: None, label, suggestion, module: None }, ), VisResolutionError::ExpectedFound(span, path_str, res) => { - self.dcx().create_err(errs::ExpectedFound { span, res, path_str }) + self.dcx().create_err(errs::ExpectedModuleFound { span, res, path_str }) } VisResolutionError::Indeterminate(span) => { self.dcx().create_err(errs::Indeterminate(span)) diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 5eee6a51fd2da..665abc2b06729 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,4 +1,5 @@ -use rustc_errors::{codes::*, Applicability}; +#![allow(dead_code)] // TODO : non +use rustc_errors::{codes::*, Applicability, MultiSpan}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{ symbol::{Ident, Symbol}, @@ -495,8 +496,8 @@ pub(crate) struct Relative2018 { pub(crate) struct AncestorOnly(#[primary_span] pub(crate) Span); #[derive(Diagnostic)] -#[diag(resolve_expected_found, code = E0577)] -pub(crate) struct ExpectedFound { +#[diag(resolve_expected_module_found, code = E0577)] +pub(crate) struct ExpectedModuleFound { #[primary_span] #[label] pub(crate) span: Span, @@ -801,3 +802,157 @@ pub(crate) struct UnexpectedResUseAtOpInSlicePatWithRangeSugg { pub ident: Ident, pub snippet: String, } + +#[derive(Diagnostic)] +#[diag(resolve_extern_crate_loading_macro_not_at_crate_root, code = E0468)] +pub(crate) struct ExternCrateLoadingMacroNotAtCrateRoot { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_bad_macro_import, code = E0466)] +pub(crate) struct BadMacroImport { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_extern_crate_self_requires_renaming)] +pub(crate) struct ExternCrateSelfRequiresRenaming { + #[primary_span] + #[suggestion(code = "extern crate self as name;", applicability = "has-placeholders")] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_macro_use_name_already_in_use)] +#[note] +pub(crate) struct MacroUseNameAlreadyInUse { + #[primary_span] + pub(crate) span: Span, + pub(crate) name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(resolve_imported_macro_not_found, code = E0469)] +pub(crate) struct ImportedMacroNotFound { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_macro_extern_deprecated)] +pub(crate) struct MacroExternDeprecated { + #[primary_span] + pub(crate) span: Span, + #[help] + pub inner_attribute: Option<()>, +} + +#[derive(Diagnostic)] +#[diag(resolve_arguments_macro_use_not_allowed)] +pub(crate) struct ArgumentsMacroUseNotAllowed { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_unnamed_crate_root_import)] +pub(crate) struct UnnamedCrateRootImport { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments)] +pub(crate) struct MacroExpandedExternCrateCannotShadowExternArguments { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_elided_anonymous_lifetime_report_error, code = E0637)] +pub(crate) struct ElidedAnonymousLivetimeReportError { + #[primary_span] + #[label] + pub(crate) span: Span, + #[subdiagnostic] + pub(crate) suggestion: Option, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + resolve_elided_anonymous_lifetime_report_error_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion { + #[suggestion_part(code = "for<'a> ")] + pub(crate) lo: Span, + #[suggestion_part(code = "'a ")] + pub(crate) hi: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_explicit_anonymous_lifetime_report_error, code = E0637)] +pub(crate) struct ExplicitAnonymousLivetimeReportError { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_implicit_elided_lifetimes_not_allowed_here, code = E0726)] +pub(crate) struct ImplicitElidedLifetimeNotAllowedHere { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_underscore_lifetime_is_reserved, code = E0637)] +pub(crate) struct UnderscoreLifetimeIsReserved { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_static_lifetime_is_reserved, code = E0262)] +pub(crate) struct StaticLifetimeIsReserved { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) lifetime: Ident, +} + +#[derive(Diagnostic)] +#[diag(resolve_attempt_to_define_builtin_macro_twice, code = E0773)] +pub(crate) struct AttemptToDefineBuiltinMacroTwice { + #[primary_span] + pub(crate) span: Span, + #[note] + pub(crate) note_span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_variable_is_not_bound_in_all_patterns, code = E0408)] +pub(crate) struct VariableIsNotBoundInAllPatterns { + #[primary_span] + pub(crate) multispan: MultiSpan, + pub(crate) name: Symbol, +} + +#[derive(Subdiagnostic, Debug, Clone)] +#[label(resolve_pattern_doesnt_bind_name)] +pub(crate) struct PatternDoesntBindName { + #[primary_span] + pub(crate) span: Span, + pub(crate) name: Symbol, +} + +#[derive(Subdiagnostic, Debug, Clone)] +#[label(resolve_variable_not_in_all_patterns)] +pub(crate) struct VariableNotInAllPatterns { + #[primary_span] + pub(crate) span: Span, +} \ No newline at end of file From 4226dc2045717ba8570e56c446557ce808b10916 Mon Sep 17 00:00:00 2001 From: Jean CASPAR Date: Sun, 24 Mar 2024 15:11:27 +0000 Subject: [PATCH 04/22] Migrate some diagnostics --- compiler/rustc_resolve/messages.ftl | 2 +- compiler/rustc_resolve/src/diagnostics.rs | 22 ++++--- compiler/rustc_resolve/src/errors.rs | 3 +- compiler/rustc_resolve/src/late.rs | 77 +++++++++-------------- compiler/rustc_resolve/src/macros.rs | 14 ++--- 5 files changed, 48 insertions(+), 70 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index b26cf9aa3363d..c737ad86e466b 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -296,7 +296,7 @@ resolve_self_in_generic_param_default = generic parameters cannot use `Self` in their defaults .label = `Self` in generic parameter default -resolve_static_lifetime_is_reserved = invalid lifetime parameter name: `{$ident}` +resolve_static_lifetime_is_reserved = invalid lifetime parameter name: `{$lifetime}` .label = 'static is a reserved lifetime name resolve_tool_module_imported = diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 1a14558468dd2..a367a5f21db2d 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -29,8 +29,8 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span, SyntaxContext}; use thin_vec::{thin_vec, ThinVec}; -use crate::errors::{AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion}; -use crate::errors::{ +use crate::errors::{self, + AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive, ExplicitUnsafeTraits, MacroDefinedLater, MacroSuggMovePosition, MaybeMissingMacroRulesName, }; @@ -677,18 +677,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let origin_sp = origin.iter().copied().collect::>(); let msp = MultiSpan::from_spans(target_sp.clone()); - let mut err = struct_span_code_err!( - self.dcx(), - msp, - E0408, - "variable `{}` is not bound in all patterns", + let mut err = self.dcx().create_err(errors::VariableIsNotBoundInAllPatterns { + multispan: msp, name, - ); + }); for sp in target_sp { - err.span_label(sp, format!("pattern doesn't bind `{name}`")); + err.subdiagnostic(self.dcx(), errors::PatternDoesntBindName { + span: sp, + name, + }); } for sp in origin_sp { - err.span_label(sp, "variable not in all patterns"); + err.subdiagnostic(self.dcx(), errors::VariableNotInAllPatterns { + span: sp, + }); } if could_be_path { let import_suggestions = self.lookup_import_candidates( diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 665abc2b06729..9a140f98c7fb8 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,4 +1,3 @@ -#![allow(dead_code)] // TODO : non use rustc_errors::{codes::*, Applicability, MultiSpan}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{ @@ -955,4 +954,4 @@ pub(crate) struct PatternDoesntBindName { pub(crate) struct VariableNotInAllPatterns { #[primary_span] pub(crate) span: Span, -} \ No newline at end of file +} diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 49b4a6efd3c3e..ec11bfd96daa7 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -6,8 +6,7 @@ //! If you wonder why there's no `early.rs`, that's because it's split into three files - //! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`. -use crate::errors::ImportsCannotReferTo; -use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding}; +use crate::{errors, path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding}; use crate::{BindingKey, Used}; use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult}; use crate::{ResolutionError, Resolver, Segment, UseError}; @@ -17,7 +16,7 @@ use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor} use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::{ - codes::*, struct_span_code_err, Applicability, DiagArgValue, IntoDiagArg, StashKey, + codes::*, Applicability, DiagArgValue, IntoDiagArg, StashKey, }; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; @@ -1666,18 +1665,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ); } LifetimeRibKind::AnonymousReportError => { - let (msg, note) = if elided { - ( - "`&` without an explicit lifetime name cannot be used here", - "explicit lifetime name needed here", - ) - } else { - ("`'_` cannot be used here", "`'_` is a reserved lifetime name") - }; - let mut diag = - struct_span_code_err!(self.r.dcx(), lifetime.ident.span, E0637, "{}", msg,); - diag.span_label(lifetime.ident.span, note); if elided { + let mut suggestion = None; for rib in self.lifetime_ribs[i..].iter().rev() { if let LifetimeRibKind::Generics { span, @@ -1685,19 +1674,23 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { .. } = &rib.kind { - diag.multipart_suggestion( - "consider introducing a higher-ranked lifetime here", - vec![ - (span.shrink_to_lo(), "for<'a> ".into()), - (lifetime.ident.span.shrink_to_hi(), "'a ".into()), - ], - Applicability::MachineApplicable, - ); + suggestion = + Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion { + lo: span.shrink_to_lo(), + hi: lifetime.ident.span.shrink_to_hi(), + }); break; } } - } - diag.emit(); + self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError { + span: lifetime.ident.span, + suggestion, + }); + } else { + self.r.dcx().emit_err(errors::ExplicitAnonymousLivetimeReportError { + span: lifetime.ident.span, + }); + }; self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate); return; } @@ -1863,13 +1856,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // async fn foo(_: std::cell::Ref) { ... } LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } | LifetimeRibKind::AnonymousWarn(_) => { + let mut err = + self.r.dcx().create_err(errors::ImplicitElidedLifetimeNotAllowedHere { + span: path_span, + }); let sess = self.r.tcx.sess; - let mut err = struct_span_code_err!( - sess.dcx(), - path_span, - E0726, - "implicit elided lifetime not allowed here" - ); rustc_errors::add_elided_lifetime_in_path_suggestion( sess.source_map(), &mut err, @@ -2313,7 +2304,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let report_error = |this: &Self, ns| { if this.should_report_errs() { let what = if ns == TypeNS { "type parameters" } else { "local variables" }; - this.r.dcx().emit_err(ImportsCannotReferTo { span: ident.span, what }); + this.r.dcx().emit_err(errors::ImportsCannotReferTo { span: ident.span, what }); } }; @@ -2633,29 +2624,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } if param.ident.name == kw::UnderscoreLifetime { - struct_span_code_err!( - self.r.dcx(), - param.ident.span, - E0637, - "`'_` cannot be used here" - ) - .with_span_label(param.ident.span, "`'_` is a reserved lifetime name") - .emit(); + self.r + .dcx() + .emit_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span }); // Record lifetime res, so lowering knows there is something fishy. self.record_lifetime_param(param.id, LifetimeRes::Error); continue; } if param.ident.name == kw::StaticLifetime { - struct_span_code_err!( - self.r.dcx(), - param.ident.span, - E0262, - "invalid lifetime parameter name: `{}`", - param.ident, - ) - .with_span_label(param.ident.span, "'static is a reserved lifetime name") - .emit(); + self.r.dcx().emit_err(errors::StaticLifetimeIsReserved { + span: param.ident.span, + lifetime: param.ident, + }); // Record lifetime res, so lowering knows there is something fishy. self.record_lifetime_param(param.id, LifetimeRes::Error); continue; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index dbca2f9895d20..bedf79400e36b 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -14,7 +14,7 @@ use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; -use rustc_errors::{codes::*, struct_span_code_err, Applicability, StashKey}; +use rustc_errors::{Applicability, StashKey}; use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand}; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::compile_declarative_macro; @@ -916,14 +916,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { rule_spans = Vec::new(); } BuiltinMacroState::AlreadySeen(span) => { - struct_span_code_err!( - self.dcx(), - item.span, - E0773, - "attempted to define built-in macro more than once" - ) - .with_span_note(span, "previously defined here") - .emit(); + self.dcx().emit_err(errors::AttemptToDefineBuiltinMacroTwice { + span: item.span, + note_span: span, + }); } } } else { From cec9f7f71659360e66933d4fb782d37938d00f09 Mon Sep 17 00:00:00 2001 From: Jean CASPAR Date: Sun, 24 Mar 2024 21:53:18 +0000 Subject: [PATCH 05/22] Migrate more diagnostics --- compiler/rustc_resolve/messages.ftl | 106 +++++++++ compiler/rustc_resolve/src/diagnostics.rs | 273 +++++++++++----------- compiler/rustc_resolve/src/errors.rs | 267 +++++++++++++++++++++ compiler/rustc_resolve/src/late.rs | 4 +- compiler/rustc_resolve/src/macros.rs | 61 +++-- 5 files changed, 537 insertions(+), 174 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index c737ad86e466b..95592b1c1dd6f 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -38,6 +38,9 @@ resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion = resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion = this would need to be a `{$suggestion}` +resolve_attributes_starting_with_rustc_are_reserved = + attributes starting with `rustc` are reserved for use by the `rustc` compiler + resolve_bad_macro_import = bad macro import resolve_binding_in_never_pattern = @@ -70,12 +73,19 @@ resolve_cannot_determine_macro_resolution = cannot determine resolution for the {$kind} `{$path}` .note = import resolution is stuck, try simplifying macro imports +resolve_cannot_find_builtin_macro_with_name = + cannot find a built-in macro with name `{$ident}` + resolve_cannot_find_ident_in_this_scope = cannot find {$expected} `{$ident}` in this scope resolve_cannot_glob_import_possible_crates = cannot glob-import all possible crates +resolve_cannot_use_through_an_import = + cannot use {$article} {$descr} through an import + .note = the {$descr} imported here + resolve_change_import_binding = you can use `as` to change the binding name of the import @@ -88,6 +98,12 @@ resolve_consider_adding_macro_export = resolve_consider_declaring_with_pub = consider declaring type or module `{$ident}` with `pub` +resolve_consider_making_the_field_public = + { $number_of_fields -> + [one] consider making the field publicly accessible + *[other] consider making the fields publicly accessible + } + resolve_consider_marking_as_pub = consider marking `{$ident}` as `pub` in the imported module @@ -108,6 +124,9 @@ resolve_const_param_in_non_trivial_anon_const = resolve_const_param_in_ty_of_const_param = const parameters may not be used in the type of const parameters +resolve_constructor_private_if_any_field_private = + a constructor is private if any of the fields is private + resolve_elided_anonymous_lifetime_report_error = `&` without an explicit lifetime name cannot be used here .label = explicit lifetime name needed here @@ -133,10 +152,20 @@ resolve_extern_crate_self_requires_renaming = `extern crate self;` requires renaming .suggestion = rename the `self` crate to be able to import it +resolve_failed_resolve_unresolve_import = failed to resolve: unresolved import + +resolve_failed_resolve_unresolve_import_label = unresolved import + resolve_forward_declared_generic_param = generic parameters with a default cannot use forward declared identifiers .label = defaulted generic parameters cannot be forward declared +resolve_found_an_item_configured_out = + found an item that was configured out + +resolve_generic_arguments_in_macro_path = + generic arguments in macro path + resolve_generic_params_from_outer_item = can't use {$is_self -> [true] `Self` @@ -171,6 +200,12 @@ resolve_ident_bound_more_than_once_in_same_pattern = identifier `{$identifier}` is bound more than once in the same pattern .label = used in a pattern more than once +resolve_ident_imported_here_but_it_is_desc = + `{$imported_ident}` is imported here, but it is {$imported_ident_desc} + +resolve_ident_in_scope_but_it_is_desc = + `{$imported_ident}` is in scope, but it is {$imported_ident_desc} + resolve_imported_crate = `$crate` may not be imported resolve_imported_macro_not_found = imported macro not found @@ -190,6 +225,13 @@ resolve_is_not_directly_importable = `{$target}` is not directly importable .label = cannot be imported directly +resolve_is_private = + {$ident_descr} `{$ident}` is private + .label = private {$ident_descr} + +resolve_item_was_behind_feature = + the item is gated behind the `{$feature}` feature + resolve_items_in_traits_are_not_importable = items in traits are not importable @@ -217,6 +259,7 @@ resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments = resolve_macro_expected_found = expected {$expected}, found {$found} `{$macro_path}` + .label = not {$article} {$expected} resolve_macro_extern_deprecated = `#[macro_escape]` is a deprecated synonym for `#[macro_use]` @@ -237,11 +280,45 @@ resolve_missing_macro_rules_name = maybe you have forgotten to define a name for resolve_module_only = visibility must resolve to a module +resolve_name_defined_multiple_time = + the name `{$name}` is defined multiple times + .note = `{$name}` must be defined only once in the {$descr} namespace of this {$container} + +resolve_name_defined_multiple_time_old_binding_definition = + previous definition of the {$old_kind} `{$name}` here + +resolve_name_defined_multiple_time_old_binding_import = + previous import of the {$old_kind} `{$name}` here + +resolve_name_defined_multiple_time_redefined = + `{$name}` redefined here + +resolve_name_defined_multiple_time_reimported = + `{$name}` reimported here + resolve_name_is_already_used_as_generic_parameter = the name `{$name}` is already used for a generic parameter in this item's generic parameters .label = already used .first_use_of_name = first use of `{$name}` +resolve_name_reserved_in_attribute_namespace = + name `{$ident}` is reserved in attribute namespace + +resolve_note_and_refers_to_the_item_defined_here = + {$first -> + [true] {$dots -> + [true] the {$binding_descr} `{$binding_name}` is defined here... + *[false] the {$binding_descr} `{$binding_name}` is defined here + } + *[false] {$dots -> + [true] ...and refers to the {$binding_descr} `{$binding_name}` which is defined here... + *[false] ...and refers to the {$binding_descr} `{$binding_name}` which is defined here + } + } + +resolve_outer_ident_is_not_publicly_reexported = + {$outer_ident_descr} `{$outer_ident}` is not publicly re-exported + resolve_param_in_enum_discriminant = generic parameters may not be used in enum discriminant values .label = cannot perform const operation using `{$name}` @@ -275,6 +352,8 @@ resolve_relative_2018 = resolve_remove_surrounding_derive = remove from the surrounding `derive()` +resolve_remove_unnecessary_import = remove unnecessary import + resolve_self_import_can_only_appear_once_in_the_list = `self` import can only appear once in an import list .label = can only appear once in an import list @@ -296,13 +375,33 @@ resolve_self_in_generic_param_default = generic parameters cannot use `Self` in their defaults .label = `Self` in generic parameter default +resolve_similarly_named_defined_here = + similarly named {$candidate_descr} `{$candidate}` defined here + +resolve_single_item_defined_here = + {$candidate_descr} `{$candidate}` defined here + resolve_static_lifetime_is_reserved = invalid lifetime parameter name: `{$lifetime}` .label = 'static is a reserved lifetime name +resolve_suggestion_import_ident_directly = + import `{$ident}` directly + +resolve_suggestion_import_ident_through_reexport = + import `{$ident}` through the re-export + resolve_tool_module_imported = cannot use a tool module through an import .note = the tool module imported here +resolve_tool_only_accepts_identifiers = + `{$tool}` only accepts identifiers + .label = not an identifier + +resolve_tool_was_already_registered = + tool `{$tool}` was already registered + .label = already registered here + resolve_trait_impl_duplicate = duplicate definitions with name `{$name}`: .label = duplicate definition @@ -368,3 +467,10 @@ resolve_variable_is_not_bound_in_all_patterns = variable `{$name}` is not bound in all patterns resolve_variable_not_in_all_patterns = variable not in all patterns + +resolve_you_could_import_this_desc = you could import this {$desc} + +resolve_trait_impl_mismatch = + item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}` + .label = does not match trait + .trait_impl_mismatch_label_item = item in trait \ No newline at end of file diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index a367a5f21db2d..12484462f82f4 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -6,8 +6,8 @@ use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - codes::*, pluralize, report_ambiguity_error, struct_span_code_err, Applicability, Diag, - DiagCtxt, ErrorGuaranteed, MultiSpan, SuggestionStyle, + codes::*, report_ambiguity_error, struct_span_code_err, Applicability, Diag, DiagCtxt, + ErrorGuaranteed, MultiSpan, SuggestionStyle, }; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; @@ -29,10 +29,9 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span, SyntaxContext}; use thin_vec::{thin_vec, ThinVec}; -use crate::errors::{self, - AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, - ConsiderAddingADerive, ExplicitUnsafeTraits, MacroDefinedLater, MacroSuggMovePosition, - MaybeMissingMacroRulesName, +use crate::errors::{ + self, AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive, + ExplicitUnsafeTraits, MacroDefinedLater, MacroSuggMovePosition, MaybeMissingMacroRulesName, }; use crate::imports::{Import, ImportKind}; use crate::late::{PatternSource, Rib}; @@ -226,16 +225,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ModuleKind::Block => "block", }; - let old_noun = match old_binding.is_import_user_facing() { - true => "import", - false => "definition", - }; - - let new_participle = match new_binding.is_import_user_facing() { - true => "imported", - false => "defined", - }; - let (name, span) = (ident.name, self.tcx.sess.source_map().guess_head_span(new_binding.span)); @@ -254,35 +243,51 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { (TypeNS, _) => "type", }; - let msg = format!("the name `{name}` is defined multiple times"); - - let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) { - (true, true) => struct_span_code_err!(self.dcx(), span, E0259, "{}", msg), + let code = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) { + (true, true) => E0259, (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() { - true => struct_span_code_err!(self.dcx(), span, E0254, "{}", msg), - false => struct_span_code_err!(self.dcx(), span, E0260, "{}", msg), + true => E0254, + false => E0260, }, _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) { - (false, false) => struct_span_code_err!(self.dcx(), span, E0428, "{}", msg), - (true, true) => struct_span_code_err!(self.dcx(), span, E0252, "{}", msg), - _ => struct_span_code_err!(self.dcx(), span, E0255, "{}", msg), + (false, false) => E0428, + (true, true) => E0252, + _ => E0255, }, }; - err.note(format!( - "`{}` must be defined only once in the {} namespace of this {}", - name, - ns.descr(), - container - )); - - err.span_label(span, format!("`{name}` re{new_participle} here")); - if !old_binding.span.is_dummy() && old_binding.span != span { - err.span_label( - self.tcx.sess.source_map().guess_head_span(old_binding.span), - format!("previous {old_noun} of the {old_kind} `{name}` here"), - ); - } + let label = match new_binding.is_import_user_facing() { + true => errors::NameDefinedMultipleTimeLabel::Reimported { span, name }, + false => errors::NameDefinedMultipleTimeLabel::Redefined { span, name }, + }; + + let old_binding_label = + (!old_binding.span.is_dummy() && old_binding.span != span).then(|| { + let span = self.tcx.sess.source_map().guess_head_span(old_binding.span); + match old_binding.is_import_user_facing() { + true => errors::NameDefinedMultipleTimeOldBindingLabel::Import { + span, + name, + old_kind, + }, + false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition { + span, + name, + old_kind, + }, + } + }); + + let mut err = self + .dcx() + .create_err(errors::NameDefinedMultipleTime { + span, + descr: ns.descr(), + container, + label, + old_binding_label, + }) + .with_code(code); // See https://github.com/rust-lang/rust/issues/32354 use NameBindingKind::Import; @@ -330,20 +335,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match import { Some((import, span, true)) if should_remove_import && import.is_nested() => { - self.add_suggestion_for_duplicate_nested_use(&mut err, import, span) + self.add_suggestion_for_duplicate_nested_use(&mut err, import, span); } Some((import, _, true)) if should_remove_import && !import.is_glob() => { // Simple case - remove the entire import. Due to the above match arm, this can // only be a single use so just remove it entirely. - err.tool_only_span_suggestion( - import.use_span_with_attributes, - "remove unnecessary import", - "", - Applicability::MaybeIncorrect, + err.subdiagnostic( + self.tcx.dcx(), + errors::ToolOnlyRemoveUnnecessaryImport { + span: import.use_span_with_attributes, + }, ); } Some((import, span, _)) => { - self.add_suggestion_for_rename_of_use(&mut err, name, import, span) + self.add_suggestion_for_rename_of_use(&mut err, name, import, span); } _ => {} } @@ -444,7 +449,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { binding_span: Span, ) { assert!(import.is_nested()); - let message = "remove unnecessary import"; // Two examples will be used to illustrate the span manipulations we're doing: // @@ -460,22 +464,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // previous imports. if found_closing_brace { if let Some(span) = extend_span_to_previous_binding(self.tcx.sess, span) { - err.tool_only_span_suggestion(span, message, "", Applicability::MaybeIncorrect); + err.subdiagnostic(self.dcx(), errors::ToolOnlyRemoveUnnecessaryImport { span }); } else { // Remove the entire line if we cannot extend the span back, this indicates an // `issue_52891::{self}` case. - err.span_suggestion( - import.use_span_with_attributes, - message, - "", - Applicability::MaybeIncorrect, + err.subdiagnostic( + self.dcx(), + errors::RemoveUnnecessaryImport { span: import.use_span_with_attributes }, ); } return; } - err.span_suggestion(span, message, "", Applicability::MachineApplicable); + err.subdiagnostic(self.dcx(), errors::RemoveUnnecessaryImport { span }); } pub(crate) fn lint_if_path_starts_with_module( @@ -571,14 +573,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { resolution_error: ResolutionError<'a>, ) -> Diag<'_> { match resolution_error { - ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params, def_kind) => { + ResolutionError::GenericParamsFromOuterItem( + outer_res, + has_generic_params, + def_kind, + ) => { use errs::GenericParamsFromOuterItemLabel as Label; let static_or_const = match def_kind { - DefKind::Static{ .. } => Some(errs::GenericParamsFromOuterItemStaticOrConst::Static), + DefKind::Static { .. } => { + Some(errs::GenericParamsFromOuterItemStaticOrConst::Static) + } DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const), _ => None, }; - let is_self = matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }); + let is_self = + matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }); let mut err = errs::GenericParamsFromOuterItem { span, label: None, @@ -677,20 +686,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let origin_sp = origin.iter().copied().collect::>(); let msp = MultiSpan::from_spans(target_sp.clone()); - let mut err = self.dcx().create_err(errors::VariableIsNotBoundInAllPatterns { - multispan: msp, - name, - }); + let mut err = self + .dcx() + .create_err(errors::VariableIsNotBoundInAllPatterns { multispan: msp, name }); for sp in target_sp { - err.subdiagnostic(self.dcx(), errors::PatternDoesntBindName { - span: sp, - name, - }); + err.subdiagnostic(self.dcx(), errors::PatternDoesntBindName { span: sp, name }); } for sp in origin_sp { - err.subdiagnostic(self.dcx(), errors::VariableNotInAllPatterns { - span: sp, - }); + err.subdiagnostic(self.dcx(), errors::VariableNotInAllPatterns { span: sp }); } if could_be_path { let import_suggestions = self.lookup_import_candidates( @@ -963,17 +966,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { code, trait_item_span, trait_path, - } => { - self.dcx().struct_span_err( + } => self + .dcx() + .create_err(errors::TraitImplMismatch { span, - format!( - "item `{name}` is an associated {kind}, which doesn't match its trait `{trait_path}`", - ), - ) - .with_code(code) - .with_span_label(span, "does not match trait") - .with_span_label(trait_item_span, "item in trait") - } + name, + kind, + trait_path, + trait_item_span, + }) + .with_code(code), ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self .dcx() .create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }), @@ -1534,17 +1536,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }; if let crate::NameBindingKind::Import { import, .. } = binding.kind { if !import.span.is_dummy() { - err.span_note( - import.span, - format!("`{ident}` is imported here, but it is {desc}"), - ); + let note = errors::IdentImporterHereButItIsDesc { + span: import.span, + imported_ident: ident, + imported_ident_desc: &desc, + }; + err.subdiagnostic(self.tcx.dcx(), note); // Silence the 'unused import' warning we might get, // since this diagnostic already covers that import. self.record_use(ident, binding, Used::Other); return; } } - err.note(format!("`{ident}` is in scope, but it is {desc}")); + let note = errors::IdentInScopeButItIsDesc { + imported_ident: ident, + imported_ident_desc: &desc, + }; + err.subdiagnostic(self.tcx.dcx(), note); return; } } @@ -1584,20 +1592,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // | ^ return false; } - let prefix = match suggestion.target { - SuggestionTarget::SimilarlyNamed => "similarly named ", - SuggestionTarget::SingleItem => "", + let span = self.tcx.sess.source_map().guess_head_span(def_span); + let candidate_descr = suggestion.res.descr(); + let candidate = suggestion.candidate; + let label = match suggestion.target { + SuggestionTarget::SimilarlyNamed => { + errors::DefinedHere::SimilarlyNamed { span, candidate_descr, candidate } + } + SuggestionTarget::SingleItem => { + errors::DefinedHere::SingleItem { span, candidate_descr, candidate } + } }; - - err.span_label( - self.tcx.sess.source_map().guess_head_span(def_span), - format!( - "{}{} `{}` defined here", - prefix, - suggestion.res.descr(), - suggestion.candidate, - ), - ); + err.subdiagnostic(self.tcx.dcx(), label); } let (span, sugg, post) = if let SuggestionTarget::SimilarlyNamed = suggestion.target @@ -1751,16 +1757,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { |b: NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr }; // Print the primary message. - let descr = get_descr(binding); - let mut err = struct_span_code_err!( - self.dcx(), - ident.span, - E0603, - "{} `{}` is private", - descr, - ident - ); - err.span_label(ident.span, format!("private {descr}")); + let ident_descr = get_descr(binding); + let mut err = + self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident }); let mut not_publicly_reexported = false; if let Some((this_res, outer_ident)) = outermost_res { @@ -1784,10 +1783,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // If we suggest importing a public re-export, don't point at the definition. if point_to_def && ident.span != outer_ident.span { not_publicly_reexported = true; - err.span_label( - outer_ident.span, - format!("{} `{outer_ident}` is not publicly re-exported", this_res.descr()), - ); + let label = errors::OuterIdentIsNotPubliclyReexported { + span: outer_ident.span, + outer_ident_descr: this_res.descr(), + outer_ident, + }; + err.subdiagnostic(self.tcx.dcx(), label); } } @@ -1801,18 +1802,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { { non_exhaustive = Some(attr.span); } else if let Some(span) = ctor_fields_span { - err.span_label(span, "a constructor is private if any of the fields is private"); + let label = errors::ConstructorPrivateIfAnyFieldPrivate { span }; + err.subdiagnostic(self.tcx.dcx(), label); if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) { - err.multipart_suggestion_verbose( - format!( - "consider making the field{} publicly accessible", - pluralize!(fields.len()) - ), - fields.iter().map(|span| (*span, "pub ".to_string())).collect(), - Applicability::MaybeIncorrect, - ); + let spans = fields.iter().map(|span| *span).collect(); + let sugg = + errors::ConsiderMakingTheFieldPublic { spans, number_of_fields: fields.len() }; + err.subdiagnostic(self.tcx.dcx(), sugg); } } @@ -1895,13 +1893,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { NameBindingKind::Res(_) | NameBindingKind::Module(_) => {} } let first = binding == first_binding; - let msg = format!( - "{and_refers_to}the {item} `{name}`{which} is defined here{dots}", - and_refers_to = if first { "" } else { "...and refers to " }, - item = get_descr(binding), - which = if first { "" } else { " which" }, - dots = if next_binding.is_some() { "..." } else { "" }, - ); let def_span = self.tcx.sess.source_map().guess_head_span(binding.span); let mut note_span = MultiSpan::from_span(def_span); if !first && binding.vis.is_public() { @@ -1921,7 +1912,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { "cannot be constructed because it is `#[non_exhaustive]`", ); } - err.span_note(note_span, msg); + let note = errors::NoteAndRefersToTheItemDefinedHere { + span: note_span, + binding_descr: get_descr(binding), + binding_name: name, + first, + dots: next_binding.is_some(), + }; + err.subdiagnostic(self.tcx.dcx(), note); } // We prioritize shorter paths, non-core imports and direct imports over the alternatives. sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport)); @@ -1935,15 +1933,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { continue; } let path = sugg.join("::"); - err.span_suggestion_verbose( - dedup_span, - format!( - "import `{ident}` {}", - if reexport { "through the re-export" } else { "directly" } - ), - path, - Applicability::MachineApplicable, - ); + let sugg = if reexport { + errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path } + } else { + errors::ImportIdent::Directly { span: dedup_span, ident, path } + }; + err.subdiagnostic(self.tcx.dcx(), sugg); break; } @@ -2523,13 +2518,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { continue; } - err.span_note(name.span, "found an item that was configured out"); + let note = errors::FoundItemConfigureOut { span: name.span }; + err.subdiagnostic(self.tcx.dcx(), note); if let MetaItemKind::List(nested) = &cfg.kind && let NestedMetaItem::MetaItem(meta_item) = &nested[0] && let MetaItemKind::NameValue(feature_name) = &meta_item.kind { - err.note(format!("the item is gated behind the `{}` feature", feature_name.symbol)); + let note = errors::ItemWasBehindFeature { feature: feature_name.symbol }; + err.subdiagnostic(self.tcx.dcx(), note); } } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 9a140f98c7fb8..e1ab5b57c3cca 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] use rustc_errors::{codes::*, Applicability, MultiSpan}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{ @@ -525,8 +526,10 @@ pub(crate) struct ModuleOnly(#[primary_span] pub(crate) Span); #[diag(resolve_macro_expected_found)] pub(crate) struct MacroExpectedFound<'a> { #[primary_span] + #[label] pub(crate) span: Span, pub(crate) found: &'a str, + pub(crate) article: &'static str, pub(crate) expected: &'a str, pub(crate) macro_path: &'a str, #[subdiagnostic] @@ -955,3 +958,267 @@ pub(crate) struct VariableNotInAllPatterns { #[primary_span] pub(crate) span: Span, } + +#[derive(Diagnostic)] +#[diag(resolve_name_defined_multiple_time)] +#[note] +pub(crate) struct NameDefinedMultipleTime { + #[primary_span] + pub(crate) span: Span, + pub(crate) descr: &'static str, + pub(crate) container: &'static str, + #[subdiagnostic] + pub(crate) label: NameDefinedMultipleTimeLabel, + #[subdiagnostic] + pub(crate) old_binding_label: Option, +} + +#[derive(Subdiagnostic)] +pub(crate) enum NameDefinedMultipleTimeLabel { + #[label(resolve_name_defined_multiple_time_reimported)] + Reimported { + #[primary_span] + span: Span, + name: Symbol, + }, + #[label(resolve_name_defined_multiple_time_redefined)] + Redefined { + #[primary_span] + span: Span, + name: Symbol, + }, +} + +#[derive(Subdiagnostic)] +pub(crate) enum NameDefinedMultipleTimeOldBindingLabel { + #[label(resolve_name_defined_multiple_time_old_binding_import)] + Import { + #[primary_span] + span: Span, + name: Symbol, + old_kind: &'static str, + }, + #[label(resolve_name_defined_multiple_time_old_binding_definition)] + Definition { + #[primary_span] + span: Span, + name: Symbol, + old_kind: &'static str, + }, +} + +#[derive(Diagnostic)] +#[diag(resolve_is_private, code = E0603)] +pub(crate) struct IsPrivate<'a> { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) ident_descr: &'a str, + pub(crate) ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(resolve_generic_arguments_in_macro_path)] +pub(crate) struct GenericArgumentsInMacroPath { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_attributes_starting_with_rustc_are_reserved)] +pub(crate) struct AttributesStartingWithRustcAreReserved { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_cannot_use_through_an_import)] +pub(crate) struct CannotUseThroughAnImport { + #[primary_span] + pub(crate) span: Span, + pub(crate) article: &'static str, + pub(crate) descr: &'static str, + #[note] + pub(crate) binding_span: Option, +} + +#[derive(Diagnostic)] +#[diag(resolve_name_reserved_in_attribute_namespace)] +pub(crate) struct NameReservedInAttributeNamespace { + #[primary_span] + pub(crate) span: Span, + pub(crate) ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(resolve_cannot_find_builtin_macro_with_name)] +pub(crate) struct CannotFindBuiltinMacroWithName { + #[primary_span] + pub(crate) span: Span, + pub(crate) ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(resolve_tool_was_already_registered)] +pub(crate) struct ToolWasAlreadyRegistered { + #[primary_span] + pub(crate) span: Span, + pub(crate) tool: Ident, + #[label] + pub(crate) old_ident_span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_tool_only_accepts_identifiers)] +pub(crate) struct ToolOnlyAcceptsIdentifiers { + #[label] + #[primary_span] + pub(crate) span: Span, + pub(crate) tool: Symbol, +} + +#[derive(Subdiagnostic)] +pub(crate) enum DefinedHere { + #[label(resolve_similarly_named_defined_here)] + SimilarlyNamed { + #[primary_span] + span: Span, + candidate_descr: &'static str, + candidate: Symbol, + }, + #[label(resolve_single_item_defined_here)] + SingleItem { + #[primary_span] + span: Span, + candidate_descr: &'static str, + candidate: Symbol, + }, +} + +#[derive(Subdiagnostic)] +#[label(resolve_outer_ident_is_not_publicly_reexported)] +pub(crate) struct OuterIdentIsNotPubliclyReexported { + #[primary_span] + pub(crate) span: Span, + pub(crate) outer_ident_descr: &'static str, + pub(crate) outer_ident: Ident, +} + +#[derive(Subdiagnostic)] +#[label(resolve_constructor_private_if_any_field_private)] +pub(crate) struct ConstructorPrivateIfAnyFieldPrivate { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + resolve_consider_making_the_field_public, + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct ConsiderMakingTheFieldPublic { + #[suggestion_part(code = "pub ")] + pub(crate) spans: Vec, + pub(crate) number_of_fields: usize, +} + +#[derive(Subdiagnostic)] +pub(crate) enum ImportIdent { + #[suggestion( + resolve_suggestion_import_ident_through_reexport, + code = "{path}", + applicability = "machine-applicable", + style = "verbose" + )] + ThroughReExport { + #[primary_span] + span: Span, + ident: Ident, + path: String, + }, + #[suggestion( + resolve_suggestion_import_ident_directly, + code = "{path}", + applicability = "machine-applicable", + style = "verbose" + )] + Directly { + #[primary_span] + span: Span, + ident: Ident, + path: String, + }, +} + +#[derive(Subdiagnostic)] +#[note(resolve_note_and_refers_to_the_item_defined_here)] +pub(crate) struct NoteAndRefersToTheItemDefinedHere<'a> { + #[primary_span] + pub(crate) span: MultiSpan, + pub(crate) binding_descr: &'a str, + pub(crate) binding_name: Ident, + pub(crate) first: bool, + pub(crate) dots: bool, +} + +#[derive(Subdiagnostic)] +#[suggestion(resolve_remove_unnecessary_import, code = "", applicability = "maybe-incorrect")] +pub(crate) struct RemoveUnnecessaryImport { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion( + resolve_remove_unnecessary_import, + code = "", + applicability = "maybe-incorrect", + style = "tool-only" +)] +pub(crate) struct ToolOnlyRemoveUnnecessaryImport { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[note(resolve_ident_imported_here_but_it_is_desc)] +pub(crate) struct IdentImporterHereButItIsDesc<'a> { + #[primary_span] + pub(crate) span: Span, + pub(crate) imported_ident: Ident, + pub(crate) imported_ident_desc: &'a str, +} + +#[derive(Subdiagnostic)] +#[note(resolve_ident_in_scope_but_it_is_desc)] +pub(crate) struct IdentInScopeButItIsDesc<'a> { + pub(crate) imported_ident: Ident, + pub(crate) imported_ident_desc: &'a str, +} + +#[derive(Subdiagnostic)] +#[note(resolve_found_an_item_configured_out)] +pub(crate) struct FoundItemConfigureOut { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[note(resolve_item_was_behind_feature)] +pub(crate) struct ItemWasBehindFeature { + pub(crate) feature: Symbol, +} + +#[derive(Diagnostic)] +#[diag(resolve_trait_impl_mismatch)] +pub(crate) struct TraitImplMismatch { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) name: Symbol, + pub(crate) kind: &'static str, + pub(crate) trait_path: String, + #[label(resolve_trait_impl_mismatch_label_item)] + pub(crate) trait_item_span: Span, +} diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ec11bfd96daa7..33c9c7fcc6208 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -15,9 +15,7 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_errors::{ - codes::*, Applicability, DiagArgValue, IntoDiagArg, StashKey, -}; +use rustc_errors::{codes::*, Applicability, DiagArgValue, IntoDiagArg, StashKey}; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index bedf79400e36b..2a23ed71753fa 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -123,20 +123,18 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { match nested_meta.ident() { Some(ident) => { if let Some(old_ident) = registered_tools.replace(ident) { - let msg = format!("{} `{}` was already registered", "tool", ident); - tcx.dcx() - .struct_span_err(ident.span, msg) - .with_span_label(old_ident.span, "already registered here") - .emit(); + tcx.dcx().emit_err(errors::ToolWasAlreadyRegistered { + span: ident.span, + tool: ident, + old_ident_span: old_ident.span, + }); } } None => { - let msg = format!("`{}` only accepts identifiers", sym::register_tool); - let span = nested_meta.span(); - tcx.dcx() - .struct_span_err(span, msg) - .with_span_label(span, "not an identifier") - .emit(); + tcx.dcx().emit_err(errors::ToolOnlyAcceptsIdentifiers { + span: nested_meta.span(), + tool: sym::register_tool, + }); } } } @@ -485,13 +483,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Report errors for the resolved macro. for segment in &path.segments { if let Some(args) = &segment.args { - self.dcx().span_err(args.span(), "generic arguments in macro path"); + self.dcx().emit_err(errors::GenericArgumentsInMacroPath { span: args.span() }); } if kind == MacroKind::Attr && segment.ident.as_str().starts_with("rustc") { - self.dcx().span_err( - segment.ident.span, - "attributes starting with `rustc` are reserved for use by the `rustc` compiler", - ); + self.dcx().emit_err(errors::AttributesStartingWithRustcAreReserved { + span: segment.ident.span, + }); } } @@ -535,6 +532,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut err = MacroExpectedFound { span: path.span, expected, + article, found: res.descr(), macro_path: &path_str, remove_surrounding_derive: None, @@ -550,10 +548,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str }); } - self.dcx() - .create_err(err) - .with_span_label(path.span, format!("not {article} {expected}")) - .emit(); + self.dcx().emit_err(err); return Ok((self.dummy_ext(kind), Res::Err)); } @@ -872,13 +867,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ) { if let Some(Res::NonMacroAttr(kind)) = res { if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) { - let msg = - format!("cannot use {} {} through an import", kind.article(), kind.descr()); - let mut err = self.dcx().struct_span_err(span, msg); - if let Some(binding) = binding { - err.span_note(binding.span, format!("the {} imported here", kind.descr())); - } - err.emit(); + let binding_span = binding.map(|binding| binding.span); + self.dcx().emit_err(errors::CannotUseThroughAnImport { + span, + article: kind.article(), + descr: kind.descr(), + binding_span, + }); } } } @@ -889,10 +884,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if ident.name == sym::cfg || ident.name == sym::cfg_attr { let macro_kind = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kind()); if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) { - self.dcx().span_err( - ident.span, - format!("name `{ident}` is reserved in attribute namespace"), - ); + self.dcx() + .emit_err(errors::NameReservedInAttributeNamespace { span: ident.span, ident }); } } } @@ -923,8 +916,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } } else { - let msg = format!("cannot find a built-in macro with name `{}`", item.ident); - self.dcx().span_err(item.span, msg); + self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { + span: item.span, + ident: item.ident, + }); } } From 992c5050217d93e3e07002fa978c152447d71910 Mon Sep 17 00:00:00 2001 From: Jean CASPAR Date: Sat, 13 Apr 2024 14:02:10 +0100 Subject: [PATCH 06/22] Reorder error messages --- compiler/rustc_resolve/messages.ftl | 19 ++++++------------- compiler/rustc_resolve/src/errors.rs | 1 - 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 95592b1c1dd6f..f824e4faf5d06 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -152,10 +152,6 @@ resolve_extern_crate_self_requires_renaming = `extern crate self;` requires renaming .suggestion = rename the `self` crate to be able to import it -resolve_failed_resolve_unresolve_import = failed to resolve: unresolved import - -resolve_failed_resolve_unresolve_import_label = unresolved import - resolve_forward_declared_generic_param = generic parameters with a default cannot use forward declared identifiers .label = defaulted generic parameters cannot be forward declared @@ -194,8 +190,6 @@ resolve_ident_bound_more_than_once_in_parameter_list = identifier `{$identifier}` is bound more than once in this parameter list .label = used as parameter more than once -resolve_implicit_elided_lifetimes_not_allowed_here = implicit elided lifetime not allowed here - resolve_ident_bound_more_than_once_in_same_pattern = identifier `{$identifier}` is bound more than once in the same pattern .label = used in a pattern more than once @@ -206,6 +200,8 @@ resolve_ident_imported_here_but_it_is_desc = resolve_ident_in_scope_but_it_is_desc = `{$imported_ident}` is in scope, but it is {$imported_ident_desc} +resolve_implicit_elided_lifetimes_not_allowed_here = implicit elided lifetime not allowed here + resolve_imported_crate = `$crate` may not be imported resolve_imported_macro_not_found = imported macro not found @@ -408,6 +404,10 @@ resolve_trait_impl_duplicate = .old_span_label = previous definition here .trait_item_span = item in trait +resolve_trait_impl_mismatch = + item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}` + .label = does not match trait + .trait_impl_mismatch_label_item = item in trait resolve_try_using_similarly_named_label = try using similarly named label @@ -467,10 +467,3 @@ resolve_variable_is_not_bound_in_all_patterns = variable `{$name}` is not bound in all patterns resolve_variable_not_in_all_patterns = variable not in all patterns - -resolve_you_could_import_this_desc = you could import this {$desc} - -resolve_trait_impl_mismatch = - item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}` - .label = does not match trait - .trait_impl_mismatch_label_item = item in trait \ No newline at end of file diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index e1ab5b57c3cca..b0329702d1143 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,4 +1,3 @@ -#![allow(dead_code)] use rustc_errors::{codes::*, Applicability, MultiSpan}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{ From ec3ac1dcd6f8c4cdd648246aa2169cf7ea05027f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Apr 2024 11:31:51 +0200 Subject: [PATCH 07/22] =?UTF-8?q?builtin-derive:=20tag=20=E2=86=92=20discr?= =?UTF-8?q?iminant?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/deriving/clone.rs | 4 +- .../src/deriving/cmp/partial_ord.rs | 20 ++-- .../src/deriving/debug.rs | 2 +- .../src/deriving/generic/mod.rs | 88 ++++++++--------- .../rustc_builtin_macros/src/deriving/hash.rs | 6 +- tests/ui/deriving/deriving-all-codegen.stdout | 94 +++++++++---------- 6 files changed, 107 insertions(+), 107 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 0a44bd42b9173..cb1c9ef90bde7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -181,8 +181,8 @@ fn cs_clone( all_fields = af; vdata = &variant.data; } - EnumTag(..) | AllFieldlessEnum(..) => { - cx.dcx().span_bug(trait_span, format!("enum tags in `derive({name})`",)) + EnumDiscr(..) | AllFieldlessEnum(..) => { + cx.dcx().span_bug(trait_span, format!("enum discriminants in `derive({name})`",)) } StaticEnum(..) | StaticStruct(..) => { cx.dcx().span_bug(trait_span, format!("associated function in `derive({name})`")) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 49fe89b18b091..63311c897aba9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -20,12 +20,12 @@ pub fn expand_deriving_partial_ord( Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std)); // Order in which to perform matching - let tag_then_data = if let Annotatable::Item(item) = item + let discr_then_data = if let Annotatable::Item(item) = item && let ItemKind::Enum(def, _) = &item.kind { let dataful: Vec = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect(); match dataful.iter().filter(|&&b| b).count() { - // No data, placing the tag check first makes codegen simpler + // No data, placing the discriminant check first makes codegen simpler 0 => true, 1..=2 => false, _ => (0..dataful.len() - 1).any(|i| { @@ -50,7 +50,7 @@ pub fn expand_deriving_partial_ord( attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_partial_cmp(cx, span, substr, tag_then_data) + cs_partial_cmp(cx, span, substr, discr_then_data) })), }; @@ -72,7 +72,7 @@ fn cs_partial_cmp( cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>, - tag_then_data: bool, + discr_then_data: bool, ) -> BlockOrExpr { let test_id = Ident::new(sym::cmp, span); let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); @@ -108,12 +108,12 @@ fn cs_partial_cmp( // cmp => cmp // } // ``` - // where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match` - // against the enum variants. This means that we begin by comparing the enum tags, + // where `expr2` is `partial_cmp(self_discr, other_discr)`, and `expr1` is a `match` + // against the enum variants. This means that we begin by comparing the enum discriminants, // before either inspecting their contents (if they match), or returning - // the `cmp::Ordering` of comparing the enum tags. + // the `cmp::Ordering` of comparing the enum discriminants. // ``` - // match partial_cmp(self_tag, other_tag) { + // match partial_cmp(self_discr, other_discr) { // Some(Ordering::Equal) => match (self, other) { // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), // (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0), @@ -126,12 +126,12 @@ fn cs_partial_cmp( // ``` // match (self, other) { // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), - // _ => partial_cmp(self_tag, other_tag) + // _ => partial_cmp(self_discr, other_discr) // } // ``` // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354 - if !tag_then_data + if !discr_then_data && let ExprKind::Match(_, arms, _) = &mut expr1.kind && let Some(last) = arms.last_mut() && let PatKind::Wild = last.pat.kind diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index e442b3520b275..8b681db967050 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -53,7 +53,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> Struct(vdata, fields) => (substr.type_ident, *vdata, fields), EnumMatching(_, v, fields) => (v.ident, &v.data, fields), AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr), - EnumTag(..) | StaticStruct(..) | StaticEnum(..) => { + EnumDiscr(..) | StaticStruct(..) | StaticEnum(..) => { cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") } }; diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index e16d74eed4e07..f73106c18358d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -21,7 +21,7 @@ //! `struct T(i32, char)`). //! - `EnumMatching`, when `Self` is an enum and all the arguments are the //! same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`) -//! - `EnumTag` when `Self` is an enum, for comparing the enum tags. +//! - `EnumDiscr` when `Self` is an enum, for comparing the enum discriminants. //! - `StaticEnum` and `StaticStruct` for static methods, where the type //! being derived upon is either an enum or struct respectively. (Any //! argument with type Self is just grouped among the non-self @@ -143,11 +143,11 @@ //! ) //! ``` //! -//! For the tags, +//! For the discriminants, //! //! ```text -//! EnumTag( -//! &[, ], +//! EnumDiscr( +//! &[, ], //! , //! ) //! ``` @@ -315,10 +315,10 @@ pub enum SubstructureFields<'a> { /// variant. EnumMatching(usize, &'a ast::Variant, Vec), - /// The tag of an enum. The first field is a `FieldInfo` for the tags, as + /// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as /// if they were fields. The second field is the expression to combine the - /// tag expression with; it will be `None` if no match is necessary. - EnumTag(FieldInfo, Option>), + /// discriminant expression with; it will be `None` if no match is necessary. + EnumDiscr(FieldInfo, Option>), /// A static method where `Self` is a struct. StaticStruct(&'a ast::VariantData, StaticFields), @@ -1137,9 +1137,9 @@ impl<'a> MethodDef<'a> { /// impl ::core::cmp::PartialEq for A { /// #[inline] /// fn eq(&self, other: &A) -> bool { - /// let __self_tag = ::core::intrinsics::discriminant_value(self); - /// let __arg1_tag = ::core::intrinsics::discriminant_value(other); - /// __self_tag == __arg1_tag + /// let __self_discr = ::core::intrinsics::discriminant_value(self); + /// let __arg1_discr = ::core::intrinsics::discriminant_value(other); + /// __self_discr == __arg1_discr /// && match (self, other) { /// (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0, /// _ => true, @@ -1148,7 +1148,7 @@ impl<'a> MethodDef<'a> { /// } /// ``` /// - /// Creates a tag check combined with a match for a tuple of all + /// Creates a discriminant check combined with a match for a tuple of all /// `selflike_args`, with an arm for each variant with fields, possibly an /// arm for each fieldless variant (if `unify_fieldless_variants` is not /// `Unify`), and possibly a default arm. @@ -1169,7 +1169,7 @@ impl<'a> MethodDef<'a> { let span = trait_.span; let variants = &enum_def.variants; - // Traits that unify fieldless variants always use the tag(s). + // Traits that unify fieldless variants always use the discriminant(s). let unify_fieldless_variants = self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify; @@ -1199,25 +1199,25 @@ impl<'a> MethodDef<'a> { // // e.g. for `PartialEq::eq` builds two statements: // ``` - // let __self_tag = ::core::intrinsics::discriminant_value(self); - // let __arg1_tag = ::core::intrinsics::discriminant_value(other); + // let __self_discr = ::core::intrinsics::discriminant_value(self); + // let __arg1_discr = ::core::intrinsics::discriminant_value(other); // ``` - let get_tag_pieces = |cx: &ExtCtxt<'_>| { - let tag_idents: Vec<_> = prefixes + let get_discr_pieces = |cx: &ExtCtxt<'_>| { + let discr_idents: Vec<_> = prefixes .iter() - .map(|name| Ident::from_str_and_span(&format!("{name}_tag"), span)) + .map(|name| Ident::from_str_and_span(&format!("{name}_discr"), span)) .collect(); - let mut tag_exprs: Vec<_> = tag_idents + let mut discr_exprs: Vec<_> = discr_idents .iter() .map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident))) .collect(); - let self_expr = tag_exprs.remove(0); - let other_selflike_exprs = tag_exprs; - let tag_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs }; + let self_expr = discr_exprs.remove(0); + let other_selflike_exprs = discr_exprs; + let discr_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs }; - let tag_let_stmts: ThinVec<_> = iter::zip(&tag_idents, &selflike_args) + let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args) .map(|(&ident, selflike_arg)| { let variant_value = deriving::call_intrinsic( cx, @@ -1229,7 +1229,7 @@ impl<'a> MethodDef<'a> { }) .collect(); - (tag_field, tag_let_stmts) + (discr_field, discr_let_stmts) }; // There are some special cases involving fieldless enums where no @@ -1239,19 +1239,19 @@ impl<'a> MethodDef<'a> { if variants.len() > 1 { match self.fieldless_variants_strategy { FieldlessVariantsStrategy::Unify => { - // If the type is fieldless and the trait uses the tag and + // If the type is fieldless and the trait uses the discriminant and // there are multiple variants, we need just an operation on - // the tag(s). - let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx); - let mut tag_check = self.call_substructure_method( + // the discriminant(s). + let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx); + let mut discr_check = self.call_substructure_method( cx, trait_, type_ident, nonselflike_args, - &EnumTag(tag_field, None), + &EnumDiscr(discr_field, None), ); - tag_let_stmts.append(&mut tag_check.0); - return BlockOrExpr(tag_let_stmts, tag_check.1); + discr_let_stmts.append(&mut discr_check.0); + return BlockOrExpr(discr_let_stmts, discr_check.1); } FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => { return self.call_substructure_method( @@ -1266,7 +1266,7 @@ impl<'a> MethodDef<'a> { } } else if variants.len() == 1 { // If there is a single variant, we don't need an operation on - // the tag(s). Just use the most degenerate result. + // the discriminant(s). Just use the most degenerate result. return self.call_substructure_method( cx, trait_, @@ -1380,22 +1380,22 @@ impl<'a> MethodDef<'a> { cx.expr_match(span, match_arg, match_arms) }; - // If the trait uses the tag and there are multiple variants, we need - // to add a tag check operation before the match. Otherwise, the match + // If the trait uses the discriminant and there are multiple variants, we need + // to add a discriminant check operation before the match. Otherwise, the match // is enough. if unify_fieldless_variants && variants.len() > 1 { - let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx); + let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx); - // Combine a tag check with the match. - let mut tag_check_plus_match = self.call_substructure_method( + // Combine a discriminant check with the match. + let mut discr_check_plus_match = self.call_substructure_method( cx, trait_, type_ident, nonselflike_args, - &EnumTag(tag_field, Some(get_match_expr(selflike_args))), + &EnumDiscr(discr_field, Some(get_match_expr(selflike_args))), ); - tag_let_stmts.append(&mut tag_check_plus_match.0); - BlockOrExpr(tag_let_stmts, tag_check_plus_match.1) + discr_let_stmts.append(&mut discr_check_plus_match.0); + BlockOrExpr(discr_let_stmts, discr_check_plus_match.1) } else { BlockOrExpr(ThinVec::new(), Some(get_match_expr(selflike_args))) } @@ -1701,16 +1701,16 @@ where rest.iter().rfold(base_expr, op) } } - EnumTag(tag_field, match_expr) => { - let tag_check_expr = f(cx, CsFold::Single(tag_field)); + EnumDiscr(discr_field, match_expr) => { + let discr_check_expr = f(cx, CsFold::Single(discr_field)); if let Some(match_expr) = match_expr { if use_foldl { - f(cx, CsFold::Combine(trait_span, tag_check_expr, match_expr.clone())) + f(cx, CsFold::Combine(trait_span, discr_check_expr, match_expr.clone())) } else { - f(cx, CsFold::Combine(trait_span, match_expr.clone(), tag_check_expr)) + f(cx, CsFold::Combine(trait_span, match_expr.clone(), discr_check_expr)) } } else { - tag_check_expr + discr_check_expr } } StaticEnum(..) | StaticStruct(..) => { diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 6bb61311bd281..41e27f6558668 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -66,9 +66,9 @@ fn hash_substructure(cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<' fields.iter().map(|field| call_hash(field.span, field.self_expr.clone())).collect(); (stmts, None) } - EnumTag(tag_field, match_expr) => { - assert!(tag_field.other_selflike_exprs.is_empty()); - let stmts = thin_vec![call_hash(tag_field.span, tag_field.self_expr.clone())]; + EnumDiscr(discr_field, match_expr) => { + assert!(discr_field.other_selflike_exprs.is_empty()); + let stmts = thin_vec![call_hash(discr_field.span, discr_field.self_expr.clone())]; (stmts, match_expr.clone()) } _ => cx.dcx().span_bug(trait_span, "impossible substructure in `derive(Hash)`"), diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index a027452797554..9f8a9f30ff682 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -1005,8 +1005,8 @@ impl ::core::default::Default for Fieldless { impl ::core::hash::Hash for Fieldless { #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - let __self_tag = ::core::intrinsics::discriminant_value(self); - ::core::hash::Hash::hash(&__self_tag, state) + let __self_discr = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_discr, state) } } #[automatically_derived] @@ -1015,9 +1015,9 @@ impl ::core::marker::StructuralPartialEq for Fieldless { } impl ::core::cmp::PartialEq for Fieldless { #[inline] fn eq(&self, other: &Fieldless) -> bool { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - __self_tag == __arg1_tag + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + __self_discr == __arg1_discr } } #[automatically_derived] @@ -1032,18 +1032,18 @@ impl ::core::cmp::PartialOrd for Fieldless { #[inline] fn partial_cmp(&self, other: &Fieldless) -> ::core::option::Option<::core::cmp::Ordering> { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + ::core::cmp::PartialOrd::partial_cmp(&__self_discr, &__arg1_discr) } } #[automatically_derived] impl ::core::cmp::Ord for Fieldless { #[inline] fn cmp(&self, other: &Fieldless) -> ::core::cmp::Ordering { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) } } @@ -1096,8 +1096,8 @@ impl ::core::default::Default for Mixed { impl ::core::hash::Hash for Mixed { #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - let __self_tag = ::core::intrinsics::discriminant_value(self); - ::core::hash::Hash::hash(&__self_tag, state); + let __self_discr = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_discr, state); match self { Mixed::R(__self_0) => ::core::hash::Hash::hash(__self_0, state), Mixed::S { d1: __self_0, d2: __self_1 } => { @@ -1114,9 +1114,9 @@ impl ::core::marker::StructuralPartialEq for Mixed { } impl ::core::cmp::PartialEq for Mixed { #[inline] fn eq(&self, other: &Mixed) -> bool { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - __self_tag == __arg1_tag && + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + __self_discr == __arg1_discr && match (self, other) { (Mixed::R(__self_0), Mixed::R(__arg1_0)) => *__self_0 == *__arg1_0, @@ -1143,8 +1143,8 @@ impl ::core::cmp::PartialOrd for Mixed { #[inline] fn partial_cmp(&self, other: &Mixed) -> ::core::option::Option<::core::cmp::Ordering> { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); match (self, other) { (Mixed::R(__self_0), Mixed::R(__arg1_0)) => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), @@ -1157,8 +1157,8 @@ impl ::core::cmp::PartialOrd for Mixed { cmp => cmp, }, _ => - ::core::cmp::PartialOrd::partial_cmp(&__self_tag, - &__arg1_tag), + ::core::cmp::PartialOrd::partial_cmp(&__self_discr, + &__arg1_discr), } } } @@ -1166,9 +1166,9 @@ impl ::core::cmp::PartialOrd for Mixed { impl ::core::cmp::Ord for Mixed { #[inline] fn cmp(&self, other: &Mixed) -> ::core::cmp::Ordering { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) { + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) { ::core::cmp::Ordering::Equal => match (self, other) { (Mixed::R(__self_0), Mixed::R(__arg1_0)) => @@ -1225,8 +1225,8 @@ impl ::core::fmt::Debug for Fielded { impl ::core::hash::Hash for Fielded { #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - let __self_tag = ::core::intrinsics::discriminant_value(self); - ::core::hash::Hash::hash(&__self_tag, state); + let __self_discr = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_discr, state); match self { Fielded::X(__self_0) => ::core::hash::Hash::hash(__self_0, state), Fielded::Y(__self_0) => ::core::hash::Hash::hash(__self_0, state), @@ -1240,9 +1240,9 @@ impl ::core::marker::StructuralPartialEq for Fielded { } impl ::core::cmp::PartialEq for Fielded { #[inline] fn eq(&self, other: &Fielded) -> bool { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - __self_tag == __arg1_tag && + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + __self_discr == __arg1_discr && match (self, other) { (Fielded::X(__self_0), Fielded::X(__arg1_0)) => *__self_0 == *__arg1_0, @@ -1270,8 +1270,8 @@ impl ::core::cmp::PartialOrd for Fielded { #[inline] fn partial_cmp(&self, other: &Fielded) -> ::core::option::Option<::core::cmp::Ordering> { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); match (self, other) { (Fielded::X(__self_0), Fielded::X(__arg1_0)) => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), @@ -1280,8 +1280,8 @@ impl ::core::cmp::PartialOrd for Fielded { (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), _ => - ::core::cmp::PartialOrd::partial_cmp(&__self_tag, - &__arg1_tag), + ::core::cmp::PartialOrd::partial_cmp(&__self_discr, + &__arg1_discr), } } } @@ -1289,9 +1289,9 @@ impl ::core::cmp::PartialOrd for Fielded { impl ::core::cmp::Ord for Fielded { #[inline] fn cmp(&self, other: &Fielded) -> ::core::cmp::Ordering { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) { + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) { ::core::cmp::Ordering::Equal => match (self, other) { (Fielded::X(__self_0), Fielded::X(__arg1_0)) => @@ -1346,8 +1346,8 @@ impl ::core::hash::Hash for EnumGeneric { #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - let __self_tag = ::core::intrinsics::discriminant_value(self); - ::core::hash::Hash::hash(&__self_tag, state); + let __self_discr = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_discr, state); match self { EnumGeneric::One(__self_0) => ::core::hash::Hash::hash(__self_0, state), @@ -1363,9 +1363,9 @@ impl ::core::cmp::PartialEq for EnumGeneric { #[inline] fn eq(&self, other: &EnumGeneric) -> bool { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - __self_tag == __arg1_tag && + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + __self_discr == __arg1_discr && match (self, other) { (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => *__self_0 == *__arg1_0, @@ -1392,16 +1392,16 @@ impl #[inline] fn partial_cmp(&self, other: &EnumGeneric) -> ::core::option::Option<::core::cmp::Ordering> { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); match (self, other) { (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), _ => - ::core::cmp::PartialOrd::partial_cmp(&__self_tag, - &__arg1_tag), + ::core::cmp::PartialOrd::partial_cmp(&__self_discr, + &__arg1_discr), } } } @@ -1410,9 +1410,9 @@ impl ::core::cmp::Ord for EnumGeneric { #[inline] fn cmp(&self, other: &EnumGeneric) -> ::core::cmp::Ordering { - let __self_tag = ::core::intrinsics::discriminant_value(self); - let __arg1_tag = ::core::intrinsics::discriminant_value(other); - match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) { + let __self_discr = ::core::intrinsics::discriminant_value(self); + let __arg1_discr = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) { ::core::cmp::Ordering::Equal => match (self, other) { (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => From be7fb2ed554757260b018fda581d416271d2fae3 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Sun, 14 Apr 2024 14:56:41 +0200 Subject: [PATCH 08/22] Update encode.rs --- .../rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index ed7cd8c2da745..40cd0c14b05f4 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -736,7 +736,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { /// ). fn to_disambiguator(num: u64) -> String { if let Some(num) = num.checked_sub(1) { - format!("s{}_", base_n::encode(num as u128, 62)) + format!("s{}_", base_n::encode(num as u128, base_n::ALPHANUMERIC_ONLY)) } else { "s_".to_string() } @@ -746,7 +746,7 @@ fn to_disambiguator(num: u64) -> String { /// ). fn to_seq_id(num: usize) -> String { if let Some(num) = num.checked_sub(1) { - base_n::encode(num as u128, 36).to_uppercase() + base_n::encode(num as u128, base_n::CASE_INSENSITIVE).to_uppercase() } else { "".to_string() } From e5cf30cd63422ac689ec419a3bee0b35d75ca7d8 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Sun, 14 Apr 2024 15:01:04 +0200 Subject: [PATCH 09/22] Update v0.rs --- compiler/rustc_symbol_mangling/src/v0.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index cb255fabfe21a..58b67c77a6150 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -831,7 +831,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { /// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc. pub(crate) fn push_integer_62(x: u64, output: &mut String) { if let Some(x) = x.checked_sub(1) { - base_n::push_str(x as u128, 62, output); + base_n::push_str(x as u128, base_n::ALPHANUMERIC_ONLY, output); } output.push('_'); } From b09c17774399bc93ba098cd05cb6c57155f8360b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 14 Apr 2024 11:36:37 -0400 Subject: [PATCH 10/22] Don't leak unnameable types in -> _ recover --- compiler/rustc_hir_analysis/src/collect.rs | 27 ++++++++----------- .../src/variance/constraints.rs | 2 +- tests/ui/variance/leaking-unnameables.rs | 13 +++++++++ tests/ui/variance/leaking-unnameables.stderr | 12 +++++++++ 4 files changed, 37 insertions(+), 17 deletions(-) create mode 100644 tests/ui/variance/leaking-unnameables.rs create mode 100644 tests/ui/variance/leaking-unnameables.stderr diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index c1bf65367aab5..1085caa310b6d 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1373,16 +1373,16 @@ fn infer_return_ty_for_fn_sig<'tcx>( // Don't leak types into signatures unless they're nameable! // For example, if a function returns itself, we don't want that // recursive function definition to leak out into the fn sig. - let mut should_recover = false; + let mut recovered_ret_ty = None; - if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false, None) { + if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) { diag.span_suggestion( ty.span, "replace with the correct return type", - ret_ty, + suggestable_ret_ty, Applicability::MachineApplicable, ); - should_recover = true; + recovered_ret_ty = Some(suggestable_ret_ty); } else if let Some(sugg) = suggest_impl_trait(&tcx.infer_ctxt().build(), tcx.param_env(def_id), ret_ty) { @@ -1404,18 +1404,13 @@ fn infer_return_ty_for_fn_sig<'tcx>( } let guar = diag.emit(); - - if should_recover { - ty::Binder::dummy(fn_sig) - } else { - ty::Binder::dummy(tcx.mk_fn_sig( - fn_sig.inputs().iter().copied(), - Ty::new_error(tcx, guar), - fn_sig.c_variadic, - fn_sig.unsafety, - fn_sig.abi, - )) - } + ty::Binder::dummy(tcx.mk_fn_sig( + fn_sig.inputs().iter().copied(), + recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)), + fn_sig.c_variadic, + fn_sig.unsafety, + fn_sig.abi, + )) } None => icx.lowerer().lower_fn_ty( hir_id, diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 20e4110e1378d..eeb8b02850521 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -236,7 +236,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) | ty::CoroutineClosure(..) => { - bug!("Unexpected coroutine/closure type in variance computation"); + bug!("Unexpected unnameable type in variance computation: {ty}"); } ty::Ref(region, ty, mutbl) => { diff --git a/tests/ui/variance/leaking-unnameables.rs b/tests/ui/variance/leaking-unnameables.rs new file mode 100644 index 0000000000000..e51d3779d34b5 --- /dev/null +++ b/tests/ui/variance/leaking-unnameables.rs @@ -0,0 +1,13 @@ +// Test variance computation doesn't explode when we leak unnameable +// types due to `-> _` recovery. + +pub struct Type<'a>(&'a ()); + +pub fn g() {} + +pub fn f() -> _ { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures + g +} + +fn main() {} diff --git a/tests/ui/variance/leaking-unnameables.stderr b/tests/ui/variance/leaking-unnameables.stderr new file mode 100644 index 0000000000000..92afe952801d0 --- /dev/null +++ b/tests/ui/variance/leaking-unnameables.stderr @@ -0,0 +1,12 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/leaking-unnameables.rs:8:18 + | +LL | pub fn f() -> _ { + | ^ + | | + | not allowed in type signatures + | help: replace with the correct return type: `fn()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0121`. From 398da593a53161c1ef9ca7dabbc5e9edf67deac6 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 14 Apr 2024 15:15:03 +0000 Subject: [PATCH 11/22] Merge `WithNumNodes` into DirectedGraph --- .../rustc_borrowck/src/constraints/graph.rs | 2 -- .../src/graph/iterate/mod.rs | 24 +++++++++---------- .../rustc_data_structures/src/graph/mod.rs | 13 ++++------ .../src/graph/reference.rs | 2 -- .../src/graph/scc/mod.rs | 14 +++++------ .../rustc_data_structures/src/graph/tests.rs | 10 ++++---- .../src/graph/vec_graph/mod.rs | 4 +--- compiler/rustc_middle/src/mir/basic_blocks.rs | 2 -- .../rustc_middle/src/mir/generic_graphviz.rs | 4 ++-- .../src/coverage/counters.rs | 2 +- .../rustc_mir_transform/src/coverage/graph.rs | 4 +--- .../rustc_mir_transform/src/coverage/spans.rs | 2 +- .../rustc_mir_transform/src/coverage/tests.rs | 2 +- 13 files changed, 33 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs index 8b7d9ec2cd671..470da9cbae611 100644 --- a/compiler/rustc_borrowck/src/constraints/graph.rs +++ b/compiler/rustc_borrowck/src/constraints/graph.rs @@ -216,9 +216,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'s, 'tcx, D> impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> { type Node = RegionVid; -} -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> { fn num_nodes(&self) -> usize { self.constraint_graph.first_constraints.len() } diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 9eb4b5278c079..c46fdb4e4f797 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -1,4 +1,4 @@ -use super::{DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors}; +use super::{DirectedGraph, WithStartNode, WithSuccessors}; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; use std::ops::ControlFlow; @@ -6,14 +6,14 @@ use std::ops::ControlFlow; #[cfg(test)] mod tests; -pub fn post_order_from( +pub fn post_order_from( graph: &G, start_node: G::Node, ) -> Vec { post_order_from_to(graph, start_node, None) } -pub fn post_order_from_to( +pub fn post_order_from_to( graph: &G, start_node: G::Node, end_node: Option, @@ -27,7 +27,7 @@ pub fn post_order_from_to( result } -fn post_order_walk( +fn post_order_walk( graph: &G, node: G::Node, result: &mut Vec, @@ -60,7 +60,7 @@ fn post_order_walk( } } -pub fn reverse_post_order( +pub fn reverse_post_order( graph: &G, start_node: G::Node, ) -> Vec { @@ -72,7 +72,7 @@ pub fn reverse_post_order( /// A "depth-first search" iterator for a directed graph. pub struct DepthFirstSearch<'graph, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, + G: ?Sized + DirectedGraph + WithSuccessors, { graph: &'graph G, stack: Vec, @@ -81,7 +81,7 @@ where impl<'graph, G> DepthFirstSearch<'graph, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, + G: ?Sized + DirectedGraph + WithSuccessors, { pub fn new(graph: &'graph G) -> Self { Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) } @@ -127,7 +127,7 @@ where impl std::fmt::Debug for DepthFirstSearch<'_, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, + G: ?Sized + DirectedGraph + WithSuccessors, { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut f = fmt.debug_set(); @@ -140,7 +140,7 @@ where impl Iterator for DepthFirstSearch<'_, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, + G: ?Sized + DirectedGraph + WithSuccessors, { type Item = G::Node; @@ -201,7 +201,7 @@ struct Event { /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms pub struct TriColorDepthFirstSearch<'graph, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, + G: ?Sized + DirectedGraph + WithSuccessors, { graph: &'graph G, stack: Vec>, @@ -211,7 +211,7 @@ where impl<'graph, G> TriColorDepthFirstSearch<'graph, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, + G: ?Sized + DirectedGraph + WithSuccessors, { pub fn new(graph: &'graph G) -> Self { TriColorDepthFirstSearch { @@ -278,7 +278,7 @@ where impl TriColorDepthFirstSearch<'_, G> where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors + WithStartNode, + G: ?Sized + DirectedGraph + WithSuccessors + WithStartNode, { /// Performs a depth-first search, starting from `G::start_node()`. /// diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index e06ab2fe36b92..853b8f1775e06 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -12,9 +12,7 @@ mod tests; pub trait DirectedGraph { type Node: Idx; -} -pub trait WithNumNodes: DirectedGraph { fn num_nodes(&self) -> usize; } @@ -28,10 +26,7 @@ where { fn successors(&self, node: Self::Node) -> >::Iter; - fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self> - where - Self: WithNumNodes, - { + fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self> { iterate::DepthFirstSearch::new(self).with_start_node(from) } } @@ -60,20 +55,20 @@ pub trait WithStartNode: DirectedGraph { } pub trait ControlFlowGraph: - DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes + DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors { // convenient trait } impl ControlFlowGraph for T where - T: DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes + T: DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors { } /// Returns `true` if the graph has a cycle that is reachable from the start node. pub fn is_cyclic(graph: &G) -> bool where - G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes, + G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors, { iterate::TriColorDepthFirstSearch::new(graph) .run_from_start(&mut iterate::CycleDetector) diff --git a/compiler/rustc_data_structures/src/graph/reference.rs b/compiler/rustc_data_structures/src/graph/reference.rs index c259fe56c1509..d15513c95db5d 100644 --- a/compiler/rustc_data_structures/src/graph/reference.rs +++ b/compiler/rustc_data_structures/src/graph/reference.rs @@ -2,9 +2,7 @@ use super::*; impl<'graph, G: DirectedGraph> DirectedGraph for &'graph G { type Node = G::Node; -} -impl<'graph, G: WithNumNodes> WithNumNodes for &'graph G { fn num_nodes(&self) -> usize { (**self).num_nodes() } diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index b54d75f7ed703..a9967c2ecbb49 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -7,7 +7,7 @@ use crate::fx::FxHashSet; use crate::graph::vec_graph::VecGraph; -use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors}; +use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithSuccessors}; use rustc_index::{Idx, IndexSlice, IndexVec}; use std::ops::Range; @@ -39,7 +39,7 @@ pub struct SccData { } impl Sccs { - pub fn new(graph: &(impl DirectedGraph + WithNumNodes + WithSuccessors)) -> Self { + pub fn new(graph: &(impl DirectedGraph + WithSuccessors)) -> Self { SccsConstruction::construct(graph) } @@ -89,17 +89,15 @@ impl Sccs { } } -impl DirectedGraph for Sccs { +impl DirectedGraph for Sccs { type Node = S; -} -impl WithNumNodes for Sccs { fn num_nodes(&self) -> usize { self.num_sccs() } } -impl WithNumEdges for Sccs { +impl WithNumEdges for Sccs { fn num_edges(&self) -> usize { self.scc_data.all_successors.len() } @@ -158,7 +156,7 @@ impl SccData { } } -struct SccsConstruction<'c, G: DirectedGraph + WithNumNodes + WithSuccessors, S: Idx> { +struct SccsConstruction<'c, G: DirectedGraph + WithSuccessors, S: Idx> { graph: &'c G, /// The state of each node; used during walk to record the stack @@ -218,7 +216,7 @@ enum WalkReturn { impl<'c, G, S> SccsConstruction<'c, G, S> where - G: DirectedGraph + WithNumNodes + WithSuccessors, + G: DirectedGraph + WithSuccessors, S: Idx, { /// Identifies SCCs in the graph `G` and computes the resulting diff --git a/compiler/rustc_data_structures/src/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs index 7f4ef906b361e..df58b965ccf44 100644 --- a/compiler/rustc_data_structures/src/graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/tests.rs @@ -36,6 +36,10 @@ impl TestGraph { impl DirectedGraph for TestGraph { type Node = usize; + + fn num_nodes(&self) -> usize { + self.num_nodes + } } impl WithStartNode for TestGraph { @@ -44,12 +48,6 @@ impl WithStartNode for TestGraph { } } -impl WithNumNodes for TestGraph { - fn num_nodes(&self) -> usize { - self.num_nodes - } -} - impl WithPredecessors for TestGraph { fn predecessors(&self, node: usize) -> >::Iter { self.predecessors[&node].iter().cloned() diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs index 00f6266ce1df7..79efe3fb8e062 100644 --- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs @@ -1,4 +1,4 @@ -use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors}; +use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithSuccessors}; use rustc_index::{Idx, IndexVec}; #[cfg(test)] @@ -80,9 +80,7 @@ impl VecGraph { impl DirectedGraph for VecGraph { type Node = N; -} -impl WithNumNodes for VecGraph { fn num_nodes(&self) -> usize { self.node_starts.len() - 1 } diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 3ecd5b9cd3456..80a9b460f3561 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -141,9 +141,7 @@ impl<'tcx> std::ops::Deref for BasicBlocks<'tcx> { impl<'tcx> graph::DirectedGraph for BasicBlocks<'tcx> { type Node = BasicBlock; -} -impl<'tcx> graph::WithNumNodes for BasicBlocks<'tcx> { #[inline] fn num_nodes(&self) -> usize { self.basic_blocks.len() diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs index 299b50525cb1e..f22f113e49308 100644 --- a/compiler/rustc_middle/src/mir/generic_graphviz.rs +++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs @@ -5,7 +5,7 @@ use std::io::{self, Write}; pub struct GraphvizWriter< 'a, - G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes, + G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode, NodeContentFn: Fn(::Node) -> Vec, EdgeLabelsFn: Fn(::Node) -> Vec, > { @@ -19,7 +19,7 @@ pub struct GraphvizWriter< impl< 'a, - G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes, + G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode, NodeContentFn: Fn(::Node) -> Vec, EdgeLabelsFn: Fn(::Node) -> Vec, > GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn> diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 69dc4f2ddea71..6e73a476421f2 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Debug}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::WithNumNodes; +use rustc_data_structures::graph::DirectedGraph; use rustc_index::IndexVec; use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op}; diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index ed8c4d8283d98..4cbad47cdc872 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -1,7 +1,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::{self, Dominators}; -use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode}; +use rustc_data_structures::graph::{self, DirectedGraph, GraphSuccessors, WithStartNode}; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind}; @@ -193,9 +193,7 @@ impl IndexMut for CoverageGraph { impl graph::DirectedGraph for CoverageGraph { type Node = BasicCoverageBlock; -} -impl graph::WithNumNodes for CoverageGraph { #[inline] fn num_nodes(&self) -> usize { self.bcbs.len() diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 672de1fbe60fd..03ede88668842 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::graph::WithNumNodes; +use rustc_data_structures::graph::DirectedGraph; use rustc_index::bit_set::BitSet; use rustc_middle::mir; use rustc_span::{BytePos, Span}; diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 569998de35e0b..631cc3c6f0505 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -28,8 +28,8 @@ use super::counters; use super::graph::{self, BasicCoverageBlock}; use itertools::Itertools; -use rustc_data_structures::graph::WithNumNodes; use rustc_data_structures::graph::WithSuccessors; +use rustc_data_structures::graph::DirectedGraph; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::*; use rustc_middle::ty; From 0d5fc9bf584f0e8700f0c3d2854bb6c70453f624 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 14 Apr 2024 15:40:26 +0000 Subject: [PATCH 12/22] Merge `{With,Graph}{Successors,Predecessors}` into `{Successors,Predecessors}` Now with GAT! --- .../rustc_borrowck/src/constraints/graph.rs | 13 ++---- compiler/rustc_borrowck/src/dataflow.rs | 2 +- .../src/region_infer/reverse_sccs.rs | 2 +- .../src/type_check/liveness/trace.rs | 2 +- .../src/graph/iterate/mod.rs | 24 +++++------ .../rustc_data_structures/src/graph/mod.rs | 43 ++++++------------- .../src/graph/reference.rs | 22 ++++------ .../src/graph/scc/mod.rs | 18 +++----- .../rustc_data_structures/src/graph/tests.rs | 22 ++++------ .../src/graph/vec_graph/mod.rs | 12 ++---- compiler/rustc_hir_typeck/src/fallback.rs | 2 +- compiler/rustc_middle/src/mir/basic_blocks.rs | 20 +++------ .../rustc_middle/src/mir/generic_graphviz.rs | 4 +- .../rustc_mir_transform/src/coverage/graph.rs | 22 +++------- .../rustc_mir_transform/src/coverage/tests.rs | 3 +- 15 files changed, 78 insertions(+), 133 deletions(-) diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs index 470da9cbae611..2dfaeb3ae7605 100644 --- a/compiler/rustc_borrowck/src/constraints/graph.rs +++ b/compiler/rustc_borrowck/src/constraints/graph.rs @@ -222,15 +222,10 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph } } -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> { - fn successors(&self, node: Self::Node) -> >::Iter { +impl<'s, 'tcx, D: ConstraintGraphDirection> graph::Successors for RegionGraph<'s, 'tcx, D> { + type Successors<'g> = Successors<'s, 'tcx, D> where Self: 'g; + + fn successors(&self, node: Self::Node) -> Self::Successors<'_> { self.outgoing_regions(node) } } - -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::GraphSuccessors<'_> - for RegionGraph<'s, 'tcx, D> -{ - type Item = RegionVid; - type Iter = Successors<'s, 'tcx, D>; -} diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index bc5bd7879563a..c185986a7d8d9 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::graph::WithSuccessors; +use rustc_data_structures::graph::Successors; use rustc_index::bit_set::BitSet; use rustc_middle::mir::{ self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges, diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs index f94001de357a9..7d7a3c09370f8 100644 --- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs +++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs @@ -2,7 +2,7 @@ use crate::constraints::ConstraintSccIndex; use crate::RegionInferenceContext; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::vec_graph::VecGraph; -use rustc_data_structures::graph::WithSuccessors; +use rustc_data_structures::graph::Successors; use rustc_middle::ty::RegionVid; use std::ops::Range; diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 8bdefdfc0ac99..5b92dca430f90 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::graph::WithSuccessors; +use rustc_data_structures::graph::Successors; use rustc_index::bit_set::BitSet; use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index c46fdb4e4f797..3ead608cd0b8d 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -1,4 +1,4 @@ -use super::{DirectedGraph, WithStartNode, WithSuccessors}; +use super::{DirectedGraph, Successors, WithStartNode}; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; use std::ops::ControlFlow; @@ -6,14 +6,14 @@ use std::ops::ControlFlow; #[cfg(test)] mod tests; -pub fn post_order_from( +pub fn post_order_from( graph: &G, start_node: G::Node, ) -> Vec { post_order_from_to(graph, start_node, None) } -pub fn post_order_from_to( +pub fn post_order_from_to( graph: &G, start_node: G::Node, end_node: Option, @@ -27,7 +27,7 @@ pub fn post_order_from_to( result } -fn post_order_walk( +fn post_order_walk( graph: &G, node: G::Node, result: &mut Vec, @@ -60,7 +60,7 @@ fn post_order_walk( } } -pub fn reverse_post_order( +pub fn reverse_post_order( graph: &G, start_node: G::Node, ) -> Vec { @@ -72,7 +72,7 @@ pub fn reverse_post_order( /// A "depth-first search" iterator for a directed graph. pub struct DepthFirstSearch<'graph, G> where - G: ?Sized + DirectedGraph + WithSuccessors, + G: ?Sized + DirectedGraph + Successors, { graph: &'graph G, stack: Vec, @@ -81,7 +81,7 @@ where impl<'graph, G> DepthFirstSearch<'graph, G> where - G: ?Sized + DirectedGraph + WithSuccessors, + G: ?Sized + DirectedGraph + Successors, { pub fn new(graph: &'graph G) -> Self { Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) } @@ -127,7 +127,7 @@ where impl std::fmt::Debug for DepthFirstSearch<'_, G> where - G: ?Sized + DirectedGraph + WithSuccessors, + G: ?Sized + DirectedGraph + Successors, { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut f = fmt.debug_set(); @@ -140,7 +140,7 @@ where impl Iterator for DepthFirstSearch<'_, G> where - G: ?Sized + DirectedGraph + WithSuccessors, + G: ?Sized + DirectedGraph + Successors, { type Item = G::Node; @@ -201,7 +201,7 @@ struct Event { /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms pub struct TriColorDepthFirstSearch<'graph, G> where - G: ?Sized + DirectedGraph + WithSuccessors, + G: ?Sized + DirectedGraph + Successors, { graph: &'graph G, stack: Vec>, @@ -211,7 +211,7 @@ where impl<'graph, G> TriColorDepthFirstSearch<'graph, G> where - G: ?Sized + DirectedGraph + WithSuccessors, + G: ?Sized + DirectedGraph + Successors, { pub fn new(graph: &'graph G) -> Self { TriColorDepthFirstSearch { @@ -278,7 +278,7 @@ where impl TriColorDepthFirstSearch<'_, G> where - G: ?Sized + DirectedGraph + WithSuccessors + WithStartNode, + G: ?Sized + DirectedGraph + Successors + WithStartNode, { /// Performs a depth-first search, starting from `G::start_node()`. /// diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index 853b8f1775e06..ef1dac1509e3c 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -20,55 +20,40 @@ pub trait WithNumEdges: DirectedGraph { fn num_edges(&self) -> usize; } -pub trait WithSuccessors: DirectedGraph -where - Self: for<'graph> GraphSuccessors<'graph, Item = ::Node>, -{ - fn successors(&self, node: Self::Node) -> >::Iter; +pub trait Successors: DirectedGraph { + type Successors<'g>: Iterator + where + Self: 'g; + + fn successors(&self, node: Self::Node) -> Self::Successors<'_>; fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self> { iterate::DepthFirstSearch::new(self).with_start_node(from) } } -#[allow(unused_lifetimes)] -pub trait GraphSuccessors<'graph> { - type Item; - type Iter: Iterator; -} +pub trait Predecessors: DirectedGraph { + type Predecessors<'g>: Iterator + where + Self: 'g; -pub trait WithPredecessors: DirectedGraph -where - Self: for<'graph> GraphPredecessors<'graph, Item = ::Node>, -{ - fn predecessors(&self, node: Self::Node) -> >::Iter; -} - -#[allow(unused_lifetimes)] -pub trait GraphPredecessors<'graph> { - type Item; - type Iter: Iterator; + fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_>; } pub trait WithStartNode: DirectedGraph { fn start_node(&self) -> Self::Node; } -pub trait ControlFlowGraph: - DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors -{ +pub trait ControlFlowGraph: DirectedGraph + WithStartNode + Predecessors + Successors { // convenient trait } -impl ControlFlowGraph for T where - T: DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors -{ -} +impl ControlFlowGraph for T where T: DirectedGraph + WithStartNode + Predecessors + Successors {} /// Returns `true` if the graph has a cycle that is reachable from the start node. pub fn is_cyclic(graph: &G) -> bool where - G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors, + G: ?Sized + DirectedGraph + WithStartNode + Successors, { iterate::TriColorDepthFirstSearch::new(graph) .run_from_start(&mut iterate::CycleDetector) diff --git a/compiler/rustc_data_structures/src/graph/reference.rs b/compiler/rustc_data_structures/src/graph/reference.rs index d15513c95db5d..fb4868f0d474f 100644 --- a/compiler/rustc_data_structures/src/graph/reference.rs +++ b/compiler/rustc_data_structures/src/graph/reference.rs @@ -14,24 +14,18 @@ impl<'graph, G: WithStartNode> WithStartNode for &'graph G { } } -impl<'graph, G: WithSuccessors> WithSuccessors for &'graph G { - fn successors(&self, node: Self::Node) -> >::Iter { +impl<'graph, G: Successors> Successors for &'graph G { + type Successors<'g> = G::Successors<'g> where 'graph: 'g; + + fn successors(&self, node: Self::Node) -> Self::Successors<'_> { (**self).successors(node) } } -impl<'graph, G: WithPredecessors> WithPredecessors for &'graph G { - fn predecessors(&self, node: Self::Node) -> >::Iter { +impl<'graph, G: Predecessors> Predecessors for &'graph G { + type Predecessors<'g> = G::Predecessors<'g> where 'graph: 'g; + + fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> { (**self).predecessors(node) } } - -impl<'iter, 'graph, G: WithPredecessors> GraphPredecessors<'iter> for &'graph G { - type Item = G::Node; - type Iter = >::Iter; -} - -impl<'iter, 'graph, G: WithSuccessors> GraphSuccessors<'iter> for &'graph G { - type Item = G::Node; - type Iter = >::Iter; -} diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index a9967c2ecbb49..f8f2f3cf0ce09 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -7,7 +7,7 @@ use crate::fx::FxHashSet; use crate::graph::vec_graph::VecGraph; -use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithSuccessors}; +use crate::graph::{DirectedGraph, Successors, WithNumEdges}; use rustc_index::{Idx, IndexSlice, IndexVec}; use std::ops::Range; @@ -39,7 +39,7 @@ pub struct SccData { } impl Sccs { - pub fn new(graph: &(impl DirectedGraph + WithSuccessors)) -> Self { + pub fn new(graph: &(impl DirectedGraph + Successors)) -> Self { SccsConstruction::construct(graph) } @@ -103,14 +103,10 @@ impl WithNumEdges for Sccs { } } -impl<'graph, N: Idx, S: Idx> GraphSuccessors<'graph> for Sccs { - type Item = S; +impl Successors for Sccs { + type Successors<'g> = std::iter::Cloned>; - type Iter = std::iter::Cloned>; -} - -impl WithSuccessors for Sccs { - fn successors(&self, node: S) -> >::Iter { + fn successors(&self, node: S) -> Self::Successors<'_> { self.successors(node).iter().cloned() } } @@ -156,7 +152,7 @@ impl SccData { } } -struct SccsConstruction<'c, G: DirectedGraph + WithSuccessors, S: Idx> { +struct SccsConstruction<'c, G: DirectedGraph + Successors, S: Idx> { graph: &'c G, /// The state of each node; used during walk to record the stack @@ -216,7 +212,7 @@ enum WalkReturn { impl<'c, G, S> SccsConstruction<'c, G, S> where - G: DirectedGraph + WithSuccessors, + G: DirectedGraph + Successors, S: Idx, { /// Identifies SCCs in the graph `G` and computes the resulting diff --git a/compiler/rustc_data_structures/src/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs index df58b965ccf44..9cd8261be6ccb 100644 --- a/compiler/rustc_data_structures/src/graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/tests.rs @@ -48,24 +48,18 @@ impl WithStartNode for TestGraph { } } -impl WithPredecessors for TestGraph { - fn predecessors(&self, node: usize) -> >::Iter { +impl Predecessors for TestGraph { + type Predecessors<'g> = iter::Cloned>; + + fn predecessors(&self, node: usize) -> Self::Predecessors<'_> { self.predecessors[&node].iter().cloned() } } -impl WithSuccessors for TestGraph { - fn successors(&self, node: usize) -> >::Iter { +impl Successors for TestGraph { + type Successors<'g> = iter::Cloned>; + + fn successors(&self, node: usize) -> Self::Successors<'_> { self.successors[&node].iter().cloned() } } - -impl<'graph> GraphPredecessors<'graph> for TestGraph { - type Item = usize; - type Iter = iter::Cloned>; -} - -impl<'graph> GraphSuccessors<'graph> for TestGraph { - type Item = usize; - type Iter = iter::Cloned>; -} diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs index 79efe3fb8e062..8b75fd9f63361 100644 --- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs @@ -1,4 +1,4 @@ -use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithSuccessors}; +use crate::graph::{DirectedGraph, Successors, WithNumEdges}; use rustc_index::{Idx, IndexVec}; #[cfg(test)] @@ -92,14 +92,10 @@ impl WithNumEdges for VecGraph { } } -impl<'graph, N: Idx> GraphSuccessors<'graph> for VecGraph { - type Item = N; +impl Successors for VecGraph { + type Successors<'g> = std::iter::Cloned>; - type Iter = std::iter::Cloned>; -} - -impl WithSuccessors for VecGraph { - fn successors(&self, node: N) -> >::Iter { + fn successors(&self, node: N) -> Self::Successors<'_> { self.successors(node).iter().cloned() } } diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index fe1e4e74973f0..4efedb4a4a63c 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -1,6 +1,6 @@ use crate::FnCtxt; use rustc_data_structures::{ - graph::WithSuccessors, + graph::Successors, graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, unord::{UnordBag, UnordMap, UnordSet}, }; diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 80a9b460f3561..5fc2940954f9b 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -155,26 +155,20 @@ impl<'tcx> graph::WithStartNode for BasicBlocks<'tcx> { } } -impl<'tcx> graph::WithSuccessors for BasicBlocks<'tcx> { +impl<'tcx> graph::Successors for BasicBlocks<'tcx> { + type Successors<'b> = Successors<'b> where 'tcx: 'b; + #[inline] - fn successors(&self, node: Self::Node) -> >::Iter { + fn successors(&self, node: Self::Node) -> Self::Successors<'_> { self.basic_blocks[node].terminator().successors() } } -impl<'a, 'b> graph::GraphSuccessors<'b> for BasicBlocks<'a> { - type Item = BasicBlock; - type Iter = Successors<'b>; -} - -impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for BasicBlocks<'tcx> { - type Item = BasicBlock; - type Iter = std::iter::Copied>; -} +impl<'tcx> graph::Predecessors for BasicBlocks<'tcx> { + type Predecessors<'b> = std::iter::Copied> where 'tcx: 'b; -impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> { #[inline] - fn predecessors(&self, node: Self::Node) -> >::Iter { + fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> { self.predecessors()[node].iter().copied() } } diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs index f22f113e49308..b49fdbada5f65 100644 --- a/compiler/rustc_middle/src/mir/generic_graphviz.rs +++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs @@ -5,7 +5,7 @@ use std::io::{self, Write}; pub struct GraphvizWriter< 'a, - G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode, + G: graph::DirectedGraph + graph::Successors + graph::WithStartNode, NodeContentFn: Fn(::Node) -> Vec, EdgeLabelsFn: Fn(::Node) -> Vec, > { @@ -19,7 +19,7 @@ pub struct GraphvizWriter< impl< 'a, - G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode, + G: graph::DirectedGraph + graph::Successors + graph::WithStartNode, NodeContentFn: Fn(::Node) -> Vec, EdgeLabelsFn: Fn(::Node) -> Vec, > GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn> diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 4cbad47cdc872..b51ee3a07233c 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -1,7 +1,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::{self, Dominators}; -use rustc_data_structures::graph::{self, DirectedGraph, GraphSuccessors, WithStartNode}; +use rustc_data_structures::graph::{self, DirectedGraph, WithStartNode}; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind}; @@ -208,28 +208,20 @@ impl graph::WithStartNode for CoverageGraph { } } -type BcbSuccessors<'graph> = std::slice::Iter<'graph, BasicCoverageBlock>; +impl graph::Successors for CoverageGraph { + type Successors<'g> = std::iter::Cloned>; -impl<'graph> graph::GraphSuccessors<'graph> for CoverageGraph { - type Item = BasicCoverageBlock; - type Iter = std::iter::Cloned>; -} - -impl graph::WithSuccessors for CoverageGraph { #[inline] - fn successors(&self, node: Self::Node) -> >::Iter { + fn successors(&self, node: Self::Node) -> Self::Successors<'_> { self.successors[node].iter().cloned() } } -impl<'graph> graph::GraphPredecessors<'graph> for CoverageGraph { - type Item = BasicCoverageBlock; - type Iter = std::iter::Copied>; -} +impl graph::Predecessors for CoverageGraph { + type Predecessors<'g> = std::iter::Copied>; -impl graph::WithPredecessors for CoverageGraph { #[inline] - fn predecessors(&self, node: Self::Node) -> >::Iter { + fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> { self.predecessors[node].iter().copied() } } diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 631cc3c6f0505..cf1a2b399f951 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -28,8 +28,7 @@ use super::counters; use super::graph::{self, BasicCoverageBlock}; use itertools::Itertools; -use rustc_data_structures::graph::WithSuccessors; -use rustc_data_structures::graph::DirectedGraph; +use rustc_data_structures::graph::{DirectedGraph, Successors}; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::*; use rustc_middle::ty; From f5144938bd33af48a1b06fc5e11f7f30132be895 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 14 Apr 2024 15:51:29 +0000 Subject: [PATCH 13/22] Rename `WithNumEdges` => `NumEdges` and `WithStartNode` => `StartNode` --- .../src/graph/iterate/mod.rs | 4 ++-- compiler/rustc_data_structures/src/graph/mod.rs | 16 ++++++++-------- .../rustc_data_structures/src/graph/reference.rs | 2 +- .../rustc_data_structures/src/graph/scc/mod.rs | 4 ++-- .../rustc_data_structures/src/graph/tests.rs | 2 +- .../src/graph/vec_graph/mod.rs | 4 ++-- compiler/rustc_middle/src/mir/basic_blocks.rs | 2 +- .../rustc_middle/src/mir/generic_graphviz.rs | 4 ++-- .../rustc_mir_transform/src/coverage/graph.rs | 4 ++-- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 3ead608cd0b8d..7a77f2c0dbbf1 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -1,4 +1,4 @@ -use super::{DirectedGraph, Successors, WithStartNode}; +use super::{DirectedGraph, StartNode, Successors}; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; use std::ops::ControlFlow; @@ -278,7 +278,7 @@ where impl TriColorDepthFirstSearch<'_, G> where - G: ?Sized + DirectedGraph + Successors + WithStartNode, + G: ?Sized + DirectedGraph + Successors + StartNode, { /// Performs a depth-first search, starting from `G::start_node()`. /// diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index ef1dac1509e3c..5758ffce6760a 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -16,10 +16,14 @@ pub trait DirectedGraph { fn num_nodes(&self) -> usize; } -pub trait WithNumEdges: DirectedGraph { +pub trait NumEdges: DirectedGraph { fn num_edges(&self) -> usize; } +pub trait StartNode: DirectedGraph { + fn start_node(&self) -> Self::Node; +} + pub trait Successors: DirectedGraph { type Successors<'g>: Iterator where @@ -40,20 +44,16 @@ pub trait Predecessors: DirectedGraph { fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_>; } -pub trait WithStartNode: DirectedGraph { - fn start_node(&self) -> Self::Node; -} - -pub trait ControlFlowGraph: DirectedGraph + WithStartNode + Predecessors + Successors { +pub trait ControlFlowGraph: DirectedGraph + StartNode + Predecessors + Successors { // convenient trait } -impl ControlFlowGraph for T where T: DirectedGraph + WithStartNode + Predecessors + Successors {} +impl ControlFlowGraph for T where T: DirectedGraph + StartNode + Predecessors + Successors {} /// Returns `true` if the graph has a cycle that is reachable from the start node. pub fn is_cyclic(graph: &G) -> bool where - G: ?Sized + DirectedGraph + WithStartNode + Successors, + G: ?Sized + DirectedGraph + StartNode + Successors, { iterate::TriColorDepthFirstSearch::new(graph) .run_from_start(&mut iterate::CycleDetector) diff --git a/compiler/rustc_data_structures/src/graph/reference.rs b/compiler/rustc_data_structures/src/graph/reference.rs index fb4868f0d474f..16b019374be7f 100644 --- a/compiler/rustc_data_structures/src/graph/reference.rs +++ b/compiler/rustc_data_structures/src/graph/reference.rs @@ -8,7 +8,7 @@ impl<'graph, G: DirectedGraph> DirectedGraph for &'graph G { } } -impl<'graph, G: WithStartNode> WithStartNode for &'graph G { +impl<'graph, G: StartNode> StartNode for &'graph G { fn start_node(&self) -> Self::Node { (**self).start_node() } diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index f8f2f3cf0ce09..1cd0edfe57fd4 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -7,7 +7,7 @@ use crate::fx::FxHashSet; use crate::graph::vec_graph::VecGraph; -use crate::graph::{DirectedGraph, Successors, WithNumEdges}; +use crate::graph::{DirectedGraph, NumEdges, Successors}; use rustc_index::{Idx, IndexSlice, IndexVec}; use std::ops::Range; @@ -97,7 +97,7 @@ impl DirectedGraph for Sccs { } } -impl WithNumEdges for Sccs { +impl NumEdges for Sccs { fn num_edges(&self) -> usize { self.scc_data.all_successors.len() } diff --git a/compiler/rustc_data_structures/src/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs index 9cd8261be6ccb..118b6bd3eb687 100644 --- a/compiler/rustc_data_structures/src/graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/tests.rs @@ -42,7 +42,7 @@ impl DirectedGraph for TestGraph { } } -impl WithStartNode for TestGraph { +impl StartNode for TestGraph { fn start_node(&self) -> usize { self.start_node } diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs index 8b75fd9f63361..3f9d8ec0acabb 100644 --- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs @@ -1,4 +1,4 @@ -use crate::graph::{DirectedGraph, Successors, WithNumEdges}; +use crate::graph::{DirectedGraph, NumEdges, Successors}; use rustc_index::{Idx, IndexVec}; #[cfg(test)] @@ -86,7 +86,7 @@ impl DirectedGraph for VecGraph { } } -impl WithNumEdges for VecGraph { +impl NumEdges for VecGraph { fn num_edges(&self) -> usize { self.edge_targets.len() } diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 5fc2940954f9b..36e067c130641 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -148,7 +148,7 @@ impl<'tcx> graph::DirectedGraph for BasicBlocks<'tcx> { } } -impl<'tcx> graph::WithStartNode for BasicBlocks<'tcx> { +impl<'tcx> graph::StartNode for BasicBlocks<'tcx> { #[inline] fn start_node(&self) -> Self::Node { START_BLOCK diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs index b49fdbada5f65..809d4cdce8dec 100644 --- a/compiler/rustc_middle/src/mir/generic_graphviz.rs +++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs @@ -5,7 +5,7 @@ use std::io::{self, Write}; pub struct GraphvizWriter< 'a, - G: graph::DirectedGraph + graph::Successors + graph::WithStartNode, + G: graph::DirectedGraph + graph::Successors + graph::StartNode, NodeContentFn: Fn(::Node) -> Vec, EdgeLabelsFn: Fn(::Node) -> Vec, > { @@ -19,7 +19,7 @@ pub struct GraphvizWriter< impl< 'a, - G: graph::DirectedGraph + graph::Successors + graph::WithStartNode, + G: graph::DirectedGraph + graph::Successors + graph::StartNode, NodeContentFn: Fn(::Node) -> Vec, EdgeLabelsFn: Fn(::Node) -> Vec, > GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn> diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index b51ee3a07233c..c187466403f83 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -1,7 +1,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::{self, Dominators}; -use rustc_data_structures::graph::{self, DirectedGraph, WithStartNode}; +use rustc_data_structures::graph::{self, DirectedGraph, StartNode}; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind}; @@ -200,7 +200,7 @@ impl graph::DirectedGraph for CoverageGraph { } } -impl graph::WithStartNode for CoverageGraph { +impl graph::StartNode for CoverageGraph { #[inline] fn start_node(&self) -> Self::Node { self.bcb_from_bb(mir::START_BLOCK) From 3124fa93107d406dc77e56a0b8a5b372349a73ab Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 14 Apr 2024 15:53:38 +0000 Subject: [PATCH 14/22] Document `ControlFlowGraph` --- compiler/rustc_data_structures/src/graph/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index 5758ffce6760a..189474395eec1 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -44,10 +44,8 @@ pub trait Predecessors: DirectedGraph { fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_>; } -pub trait ControlFlowGraph: DirectedGraph + StartNode + Predecessors + Successors { - // convenient trait -} - +/// Alias for [`DirectedGraph`] + [`StartNode`] + [`Predecessors`] + [`Successors`]. +pub trait ControlFlowGraph: DirectedGraph + StartNode + Predecessors + Successors {} impl ControlFlowGraph for T where T: DirectedGraph + StartNode + Predecessors + Successors {} /// Returns `true` if the graph has a cycle that is reachable from the start node. From e8d2221e3bbb4e8971c97395463036ebd6e7b23d Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 14 Apr 2024 16:03:08 +0000 Subject: [PATCH 15/22] Make `depth_first_search` into a standalone function Does not necessarily change much, but we never overwrite it, so I see no reason for it to be in the `Successors` trait. (+we already have a similar `is_cyclic`) --- compiler/rustc_borrowck/src/dataflow.rs | 4 ++-- .../rustc_borrowck/src/region_infer/reverse_sccs.rs | 5 ++--- .../rustc_borrowck/src/type_check/liveness/trace.rs | 6 ++++-- compiler/rustc_data_structures/src/graph/mod.rs | 11 +++++++---- .../src/graph/vec_graph/tests.rs | 4 +++- compiler/rustc_hir_typeck/src/fallback.rs | 8 +++----- 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index c185986a7d8d9..ec7d4582a6013 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::graph::Successors; +use rustc_data_structures::graph; use rustc_index::bit_set::BitSet; use rustc_middle::mir::{ self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges, @@ -262,7 +262,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> { // We first handle the cases where the loan doesn't go out of scope, depending on the issuing // region's successors. - for successor in self.regioncx.region_graph().depth_first_search(issuing_region) { + for successor in graph::depth_first_search(&self.regioncx.region_graph(), issuing_region) { // 1. Via applied member constraints // // The issuing region can flow into the choice regions, and they are either: diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs index 7d7a3c09370f8..97ddc45ee476d 100644 --- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs +++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs @@ -1,8 +1,8 @@ use crate::constraints::ConstraintSccIndex; use crate::RegionInferenceContext; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::graph; use rustc_data_structures::graph::vec_graph::VecGraph; -use rustc_data_structures::graph::Successors; use rustc_middle::ty::RegionVid; use std::ops::Range; @@ -23,8 +23,7 @@ impl ReverseSccGraph { scc0: ConstraintSccIndex, ) -> impl Iterator + 'a { let mut duplicates = FxIndexSet::default(); - self.graph - .depth_first_search(scc0) + graph::depth_first_search(&self.graph, scc0) .flat_map(move |scc1| { self.scc_regions .get(&scc1) diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 5b92dca430f90..6cc0e67c0f801 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -1,5 +1,4 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::graph::Successors; use rustc_index::bit_set::BitSet; use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; @@ -64,7 +63,10 @@ pub(super) fn trace<'mir, 'tcx>( // Traverse each issuing region's constraints, and record the loan as flowing into the // outlived region. for (loan, issuing_region_data) in borrow_set.iter_enumerated() { - for succ in region_graph.depth_first_search(issuing_region_data.region) { + for succ in rustc_data_structures::graph::depth_first_search( + ®ion_graph, + issuing_region_data.region, + ) { // We don't need to mention that a loan flows into its issuing region. if succ == issuing_region_data.region { continue; diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index 189474395eec1..61bee2ee0bba5 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -30,10 +30,6 @@ pub trait Successors: DirectedGraph { Self: 'g; fn successors(&self, node: Self::Node) -> Self::Successors<'_>; - - fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self> { - iterate::DepthFirstSearch::new(self).with_start_node(from) - } } pub trait Predecessors: DirectedGraph { @@ -57,3 +53,10 @@ where .run_from_start(&mut iterate::CycleDetector) .is_some() } + +pub fn depth_first_search(graph: &G, from: G::Node) -> iterate::DepthFirstSearch<'_, G> +where + G: ?Sized + Successors, +{ + iterate::DepthFirstSearch::new(graph).with_start_node(from) +} diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs index 7c866da60090f..87c8d25f09492 100644 --- a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs @@ -1,3 +1,5 @@ +use crate::graph; + use super::*; fn create_graph() -> VecGraph { @@ -37,6 +39,6 @@ fn successors() { #[test] fn dfs() { let graph = create_graph(); - let dfs: Vec<_> = graph.depth_first_search(0).collect(); + let dfs: Vec<_> = graph::depth_first_search(&graph, 0).collect(); assert_eq!(dfs, vec![0, 1, 3, 4, 2]); } diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 4efedb4a4a63c..69399b50695d1 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -1,7 +1,6 @@ use crate::FnCtxt; use rustc_data_structures::{ - graph::Successors, - graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, + graph::{self, iterate::DepthFirstSearch, vec_graph::VecGraph}, unord::{UnordBag, UnordMap, UnordSet}, }; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; @@ -300,7 +299,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { debug!( "calculate_diverging_fallback: root_vid={:?} reaches {:?}", root_vid, - coercion_graph.depth_first_search(root_vid).collect::>() + graph::depth_first_search(&coercion_graph, root_vid).collect::>() ); // drain the iterator to visit all nodes reachable from this node @@ -342,8 +341,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { for &diverging_vid in &diverging_vids { let diverging_ty = Ty::new_var(self.tcx, diverging_vid); let root_vid = self.root_var(diverging_vid); - let can_reach_non_diverging = coercion_graph - .depth_first_search(root_vid) + let can_reach_non_diverging = graph::depth_first_search(&coercion_graph, root_vid) .any(|n| roots_reachable_from_non_diverging.visited(n)); let infer_var_infos: UnordBag<_> = self From 80dc3d14c959f136d7b34ff1dedc572afa179ab1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Apr 2024 18:09:40 +0200 Subject: [PATCH 16/22] move the LargeAssignments lint logic into its own file --- compiler/rustc_monomorphize/src/collector.rs | 146 +---------------- .../src/collector/move_check.rs | 155 ++++++++++++++++++ 2 files changed, 161 insertions(+), 140 deletions(-) create mode 100644 compiler/rustc_monomorphize/src/collector/move_check.rs diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index ee6c154e6e84e..36d623fd93e12 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -205,6 +205,8 @@ //! this is not implemented however: a mono item will be produced //! regardless of whether it is actually needed or not. +mod move_check; + use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{par_for_each_in, LRef, MTLock}; use rustc_hir as hir; @@ -227,7 +229,6 @@ use rustc_middle::ty::{ }; use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_session::config::EntryFnType; -use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; use rustc_session::Limit; use rustc_span::source_map::{dummy_spanned, respan, Spanned}; use rustc_span::symbol::{sym, Ident}; @@ -236,9 +237,9 @@ use rustc_target::abi::Size; use std::path::PathBuf; use crate::errors::{ - self, EncounteredErrorWhileInstantiating, LargeAssignmentsLint, NoOptimizedMir, RecursionLimit, - TypeLengthLimit, + self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit, TypeLengthLimit, }; +use move_check::MoveCheckState; #[derive(PartialEq)] pub enum MonoItemCollectionStrategy { @@ -667,11 +668,8 @@ struct MirUsedCollector<'a, 'tcx> { /// Note that this contains *not-monomorphized* items! used_mentioned_items: &'a mut FxHashSet>, instance: Instance<'tcx>, - /// Spans for move size lints already emitted. Helps avoid duplicate lints. - move_size_spans: Vec, visiting_call_terminator: bool, - /// Set of functions for which it is OK to move large data into. - skip_move_check_fns: Option>, + move_check: move_check::MoveCheckState, } impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { @@ -687,124 +685,6 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { ) } - fn check_operand_move_size(&mut self, operand: &mir::Operand<'tcx>, location: Location) { - let limit = self.tcx.move_size_limit(); - if limit.0 == 0 { - return; - } - - // This function is called by visit_operand() which visits _all_ - // operands, including TerminatorKind::Call operands. But if - // check_fn_args_move_size() has been called, the operands have already - // been visited. Do not visit them again. - if self.visiting_call_terminator { - return; - } - - let source_info = self.body.source_info(location); - debug!(?source_info); - - if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) { - self.lint_large_assignment(limit.0, too_large_size, location, source_info.span); - }; - } - - fn check_fn_args_move_size( - &mut self, - callee_ty: Ty<'tcx>, - args: &[Spanned>], - fn_span: Span, - location: Location, - ) { - let limit = self.tcx.move_size_limit(); - if limit.0 == 0 { - return; - } - - if args.is_empty() { - return; - } - - // Allow large moves into container types that themselves are cheap to move - let ty::FnDef(def_id, _) = *callee_ty.kind() else { - return; - }; - if self - .skip_move_check_fns - .get_or_insert_with(|| build_skip_move_check_fns(self.tcx)) - .contains(&def_id) - { - return; - } - - debug!(?def_id, ?fn_span); - - for arg in args { - // Moving args into functions is typically implemented with pointer - // passing at the llvm-ir level and not by memcpy's. So always allow - // moving args into functions. - let operand: &mir::Operand<'tcx> = &arg.node; - if let mir::Operand::Move(_) = operand { - continue; - } - - if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) { - self.lint_large_assignment(limit.0, too_large_size, location, arg.span); - }; - } - } - - fn operand_size_if_too_large( - &mut self, - limit: Limit, - operand: &mir::Operand<'tcx>, - ) -> Option { - let ty = operand.ty(self.body, self.tcx); - let ty = self.monomorphize(ty); - let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else { - return None; - }; - if layout.size.bytes_usize() > limit.0 { - debug!(?layout); - Some(layout.size) - } else { - None - } - } - - fn lint_large_assignment( - &mut self, - limit: usize, - too_large_size: Size, - location: Location, - span: Span, - ) { - let source_info = self.body.source_info(location); - debug!(?source_info); - for reported_span in &self.move_size_spans { - if reported_span.overlaps(span) { - return; - } - } - let lint_root = source_info.scope.lint_root(&self.body.source_scopes); - debug!(?lint_root); - let Some(lint_root) = lint_root else { - // This happens when the issue is in a function from a foreign crate that - // we monomorphized in the current crate. We can't get a `HirId` for things - // in other crates. - // FIXME: Find out where to report the lint on. Maybe simply crate-level lint root - // but correct span? This would make the lint at least accept crate-level lint attributes. - return; - }; - self.tcx.emit_node_span_lint( - LARGE_ASSIGNMENTS, - lint_root, - span, - LargeAssignmentsLint { span, size: too_large_size.bytes(), limit: limit as u64 }, - ); - self.move_size_spans.push(span); - } - /// Evaluates a *not yet monomorphized* constant. fn eval_constant( &mut self, @@ -1367,19 +1247,6 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> return None; } -fn build_skip_move_check_fns(tcx: TyCtxt<'_>) -> Vec { - let fns = [ - (tcx.lang_items().owned_box(), "new"), - (tcx.get_diagnostic_item(sym::Rc), "new"), - (tcx.get_diagnostic_item(sym::Arc), "new"), - ]; - fns.into_iter() - .filter_map(|(def_id, fn_name)| { - def_id.and_then(|def_id| assoc_fn_of_type(tcx, def_id, Ident::from_str(fn_name))) - }) - .collect::>() -} - /// Scans the MIR in order to find function calls, closures, and drop-glue. /// /// Anything that's found is added to `output`. Furthermore the "mentioned items" of the MIR are returned. @@ -1409,9 +1276,8 @@ fn collect_items_of_instance<'tcx>( used_items, used_mentioned_items: &mut used_mentioned_items, instance, - move_size_spans: vec![], visiting_call_terminator: false, - skip_move_check_fns: None, + move_check: MoveCheckState::new(), }; if mode == CollectionMode::UsedItems { diff --git a/compiler/rustc_monomorphize/src/collector/move_check.rs b/compiler/rustc_monomorphize/src/collector/move_check.rs new file mode 100644 index 0000000000000..4cc7275ab8069 --- /dev/null +++ b/compiler/rustc_monomorphize/src/collector/move_check.rs @@ -0,0 +1,155 @@ +use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; + +use super::*; +use crate::errors::LargeAssignmentsLint; + +pub(super) struct MoveCheckState { + /// Spans for move size lints already emitted. Helps avoid duplicate lints. + move_size_spans: Vec, + /// Set of functions for which it is OK to move large data into. + skip_move_check_fns: Option>, +} + +impl MoveCheckState { + pub(super) fn new() -> Self { + MoveCheckState { move_size_spans: vec![], skip_move_check_fns: None } + } +} + +impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { + pub(super) fn check_operand_move_size( + &mut self, + operand: &mir::Operand<'tcx>, + location: Location, + ) { + let limit = self.tcx.move_size_limit(); + if limit.0 == 0 { + return; + } + + // This function is called by visit_operand() which visits _all_ + // operands, including TerminatorKind::Call operands. But if + // check_fn_args_move_size() has been called, the operands have already + // been visited. Do not visit them again. + if self.visiting_call_terminator { + return; + } + + let source_info = self.body.source_info(location); + debug!(?source_info); + + if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) { + self.lint_large_assignment(limit.0, too_large_size, location, source_info.span); + }; + } + + pub(super) fn check_fn_args_move_size( + &mut self, + callee_ty: Ty<'tcx>, + args: &[Spanned>], + fn_span: Span, + location: Location, + ) { + let limit = self.tcx.move_size_limit(); + if limit.0 == 0 { + return; + } + + if args.is_empty() { + return; + } + + // Allow large moves into container types that themselves are cheap to move + let ty::FnDef(def_id, _) = *callee_ty.kind() else { + return; + }; + if self + .move_check + .skip_move_check_fns + .get_or_insert_with(|| build_skip_move_check_fns(self.tcx)) + .contains(&def_id) + { + return; + } + + debug!(?def_id, ?fn_span); + + for arg in args { + // Moving args into functions is typically implemented with pointer + // passing at the llvm-ir level and not by memcpy's. So always allow + // moving args into functions. + let operand: &mir::Operand<'tcx> = &arg.node; + if let mir::Operand::Move(_) = operand { + continue; + } + + if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) { + self.lint_large_assignment(limit.0, too_large_size, location, arg.span); + }; + } + } + + fn operand_size_if_too_large( + &mut self, + limit: Limit, + operand: &mir::Operand<'tcx>, + ) -> Option { + let ty = operand.ty(self.body, self.tcx); + let ty = self.monomorphize(ty); + let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else { + return None; + }; + if layout.size.bytes_usize() > limit.0 { + debug!(?layout); + Some(layout.size) + } else { + None + } + } + + fn lint_large_assignment( + &mut self, + limit: usize, + too_large_size: Size, + location: Location, + span: Span, + ) { + let source_info = self.body.source_info(location); + debug!(?source_info); + for reported_span in &self.move_check.move_size_spans { + if reported_span.overlaps(span) { + return; + } + } + let lint_root = source_info.scope.lint_root(&self.body.source_scopes); + debug!(?lint_root); + let Some(lint_root) = lint_root else { + // This happens when the issue is in a function from a foreign crate that + // we monomorphized in the current crate. We can't get a `HirId` for things + // in other crates. + // FIXME: Find out where to report the lint on. Maybe simply crate-level lint root + // but correct span? This would make the lint at least accept crate-level lint attributes. + return; + }; + self.tcx.emit_node_span_lint( + LARGE_ASSIGNMENTS, + lint_root, + span, + LargeAssignmentsLint { span, size: too_large_size.bytes(), limit: limit as u64 }, + ); + self.move_check.move_size_spans.push(span); + } +} + +fn build_skip_move_check_fns(tcx: TyCtxt<'_>) -> Vec { + let fns = [ + (tcx.lang_items().owned_box(), "new"), + (tcx.get_diagnostic_item(sym::Rc), "new"), + (tcx.get_diagnostic_item(sym::Arc), "new"), + ]; + fns.into_iter() + .filter_map(|(def_id, fn_name)| { + def_id.and_then(|def_id| assoc_fn_of_type(tcx, def_id, Ident::from_str(fn_name))) + }) + .collect::>() +} From bf3deccdadffbd5903268cca74a60f7101f7e9c3 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 14 Apr 2024 15:48:05 -0400 Subject: [PATCH 17/22] Fix UB in LLVM FFI when passing zero or >1 bundle Rust passes a *const &OperandBundleDef to these APIs, usually from a Vec<&OperandBundleDef> or so. Previously we were dereferencing that pointer and passing it to the ArrayRef constructor with some length (N). This meant that if the length was 0, we were dereferencing a pointer to nowhere, and if the length was >1 then loading the *second* element somewhere in LLVM would've been reading past the end. Since Rust can't hold OperandBundleDef by-value we're forced to indirect through a vector that copies out the OperandBundleDefs from the by-reference list on the Rust side in order to match the LLVM expected API. --- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 37c2da4c23a1a..6e11fd629e4d3 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1524,13 +1524,21 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) { extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, - OperandBundleDef **OpBundles, + OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles) { Value *Callee = unwrap(Fn); FunctionType *FTy = unwrap(Ty); + + // FIXME: Is there a way around this? + SmallVector OpBundles; + OpBundles.reserve(NumOpBundles); + for (unsigned i = 0; i < NumOpBundles; ++i) { + OpBundles.push_back(*OpBundlesIndirect[i]); + } + return wrap(unwrap(B)->CreateCall( FTy, Callee, ArrayRef(unwrap(Args), NumArgs), - ArrayRef(*OpBundles, NumOpBundles))); + ArrayRef(OpBundles))); } extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) { @@ -1570,13 +1578,21 @@ extern "C" LLVMValueRef LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, - OperandBundleDef **OpBundles, unsigned NumOpBundles, + OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles, const char *Name) { Value *Callee = unwrap(Fn); FunctionType *FTy = unwrap(Ty); + + // FIXME: Is there a way around this? + SmallVector OpBundles; + OpBundles.reserve(NumOpBundles); + for (unsigned i = 0; i < NumOpBundles; ++i) { + OpBundles.push_back(*OpBundlesIndirect[i]); + } + return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch), ArrayRef(unwrap(Args), NumArgs), - ArrayRef(*OpBundles, NumOpBundles), + ArrayRef(OpBundles), Name)); } @@ -1585,7 +1601,7 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, LLVMBasicBlockRef DefaultDest, LLVMBasicBlockRef *IndirectDests, unsigned NumIndirectDests, LLVMValueRef *Args, unsigned NumArgs, - OperandBundleDef **OpBundles, unsigned NumOpBundles, + OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles, const char *Name) { Value *Callee = unwrap(Fn); FunctionType *FTy = unwrap(Ty); @@ -1597,11 +1613,18 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, IndirectDestsUnwrapped.push_back(unwrap(IndirectDests[i])); } + // FIXME: Is there a way around this? + SmallVector OpBundles; + OpBundles.reserve(NumOpBundles); + for (unsigned i = 0; i < NumOpBundles; ++i) { + OpBundles.push_back(*OpBundlesIndirect[i]); + } + return wrap(unwrap(B)->CreateCallBr( FTy, Callee, unwrap(DefaultDest), ArrayRef(IndirectDestsUnwrapped), ArrayRef(unwrap(Args), NumArgs), - ArrayRef(*OpBundles, NumOpBundles), + ArrayRef(OpBundles), Name)); } From 510720e9fcb1181cc2e634fe6edddadf2d2c4993 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Apr 2024 14:43:39 +0200 Subject: [PATCH 18/22] libtest: also measure time in Miri --- library/test/src/console.rs | 6 ++---- src/bootstrap/src/utils/render_tests.rs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/library/test/src/console.rs b/library/test/src/console.rs index f3918ba333aa0..7e224d60d9dc5 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -315,10 +315,8 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec) -> io::Resu // Prevent the usage of `Instant` in some cases: // - It's currently not supported for wasm targets. - // - We disable it for miri because it's not available when isolation is enabled. - let is_instant_unsupported = (cfg!(target_family = "wasm") && !cfg!(target_os = "wasi")) - || cfg!(target_os = "zkvm") - || cfg!(miri); + let is_instant_unsupported = + (cfg!(target_family = "wasm") && !cfg!(target_os = "wasi")) || cfg!(target_os = "zkvm"); let start_time = (!is_instant_unsupported).then(Instant::now); run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?; diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 95cd55c9a3d7c..16e0c2ac18517 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -377,7 +377,7 @@ struct SuiteOutcome { measured: usize, filtered_out: usize, /// The time it took to execute this test suite, or `None` if time measurement was not possible - /// (e.g. due to running inside Miri). + /// (e.g. due to running on wasm). exec_time: Option, } From 24dac6cd4545be87ad702b63be7532c92878eee8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Apr 2024 10:15:14 +0200 Subject: [PATCH 19/22] disable create_dir_all_bare on all(miri, windows) --- library/std/tests/create_dir_all_bare.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/tests/create_dir_all_bare.rs b/library/std/tests/create_dir_all_bare.rs index fe789323f97c0..fd2a7f906f839 100644 --- a/library/std/tests/create_dir_all_bare.rs +++ b/library/std/tests/create_dir_all_bare.rs @@ -31,6 +31,7 @@ impl Drop for CurrentDir { } #[test] +#[cfg_attr(all(miri, windows), ignore)] // File system access on Windows not supported by Miri fn create_dir_all_bare() { let tmpdir = common::tmpdir(); CurrentDir::with(tmpdir.path(), || { From 7d1ee8c0fbba7649153d084da2897b4ac7093d51 Mon Sep 17 00:00:00 2001 From: mountcount Date: Tue, 9 Apr 2024 15:29:17 +0800 Subject: [PATCH 20/22] Fix some typos in doc Signed-off-by: mountcount --- src/doc/unstable-book/src/compiler-flags/check-cfg.md | 4 ++-- src/doc/unstable-book/src/compiler-flags/shell-argfiles.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md index 90a006b0a1ee2..836929aba0bf5 100644 --- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -37,7 +37,7 @@ present in the list of expected values. If `"value"` is not in it, then `rustc` the future.* To check for the _none_ value (ie `#[cfg(foo)]`) one can use the `none()` predicate inside -`values()`: `values(none())`. It can be followed or precessed by any number of `"value"`. +`values()`: `values(none())`. It can be followed or preceded by any number of `"value"`. To enable checking of values, but to provide an *none*/empty set of expected values (ie. expect `#[cfg(name)]`), use these forms: @@ -163,7 +163,7 @@ fn poke_platypus() {} fn tame_lion() {} #[cfg(windows = "unix")] // This condition is UNEXPECTED, as while 'windows' is a well known - // condition name, it doens't expect any values + // condition name, it doesn't expect any values fn tame_windows() {} ``` diff --git a/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md b/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md index 4f3c780972de5..9e765301206ed 100644 --- a/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md +++ b/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md @@ -8,4 +8,4 @@ arguments from argfiles specified with `@shell:`. Because this feature controls the parsing of input arguments, the `-Zshell-argfiles` flag must be present before the argument specifying the -shell-style arguemnt file. +shell-style argument file. From 235d45e9c9c2c66b540cfa6601cc32315a4659c3 Mon Sep 17 00:00:00 2001 From: Kjetil Kjeka Date: Wed, 3 Apr 2024 16:25:05 +0200 Subject: [PATCH 21/22] Distribute LLVM bitcode linker as a preview component --- src/bootstrap/src/core/build_steps/dist.rs | 48 +++++++++++++++++++ src/bootstrap/src/core/build_steps/install.rs | 9 ++++ src/bootstrap/src/core/build_steps/tool.rs | 8 ++-- src/bootstrap/src/core/builder.rs | 1 + src/bootstrap/src/utils/tarball.rs | 8 ++++ .../src/compiler-flags/codegen-options.md | 4 ++ src/tools/llvm-bitcode-linker/src/linker.rs | 13 +++-- 7 files changed, 84 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index b51d3e157887b..78176665929b6 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1548,6 +1548,7 @@ impl Step for Extended { compiler: builder.compiler(stage, target), backend: "cranelift".to_string(), }); + add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {compiler, target}); let etc = builder.src.join("src/etc/installer"); @@ -2224,6 +2225,53 @@ impl Step for LlvmTools { } } +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] +pub struct LlvmBitcodeLinker { + pub compiler: Compiler, + pub target: TargetSelection, +} + +impl Step for LlvmBitcodeLinker { + type Output = Option; + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + let default = should_build_extended_tool(run.builder, "llvm-bitcode-linker"); + run.alias("llvm-bitcode-linker").default_condition(default) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(LlvmBitcodeLinker { + compiler: run.builder.compiler_for( + run.builder.top_stage, + run.builder.config.build, + run.target, + ), + target: run.target, + }); + } + + fn run(self, builder: &Builder<'_>) -> Option { + let compiler = self.compiler; + let target = self.target; + + let llbc_linker = + builder.ensure(tool::LlvmBitcodeLinker { compiler, target, extra_features: vec![] }); + + let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple); + + // Prepare the image directory + let mut tarball = Tarball::new(builder, "llvm-bitcode-linker", &target.triple); + tarball.set_overlay(OverlayKind::LlvmBitcodeLinker); + tarball.is_preview(true); + + tarball.add_file(llbc_linker, self_contained_bin_dir, 0o755); + + Some(tarball.generate()) + } +} + // Tarball intended for internal consumption to ease rustc/std development. // // Should not be considered stable by end users. diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 41920fabaa974..767c0f6936494 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -300,6 +300,15 @@ install!((self, builder, _config), ); } }; + LlvmBitcodeLinker, alias = "llvm-bitcode-linker", Self::should_build(_config), only_hosts: true, { + if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { compiler: self.compiler, target: self.target }) { + install_sh(builder, "llvm-bitcode-linker", self.compiler.stage, Some(self.target), &tarball); + } else { + builder.info( + &format!("skipping llvm-bitcode-linker stage{} ({})", self.compiler.stage, self.target), + ); + } + }; ); #[derive(Debug, Clone, Hash, PartialEq, Eq)] diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 1edf65d28b76e..8d1ff2fcb245f 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -746,9 +746,11 @@ impl Step for LlvmBitcodeLinker { .join(exe(bin_name, self.compiler.host)); if self.compiler.stage > 0 { - let bindir = builder.sysroot(self.compiler).join("bin"); - t!(fs::create_dir_all(&bindir)); - let bin_destination = bindir.join(exe(bin_name, self.compiler.host)); + let bindir_self_contained = builder + .sysroot(self.compiler) + .join(format!("lib/rustlib/{}/bin/self-contained", self.target.triple)); + t!(fs::create_dir_all(&bindir_self_contained)); + let bin_destination = bindir_self_contained.join(exe(bin_name, self.compiler.host)); builder.copy_link(&tool_out, &bin_destination); bin_destination } else { diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 224f5350e40a7..f31bc46d25fcb 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -853,6 +853,7 @@ impl<'a> Builder<'a> { dist::Clippy, dist::Miri, dist::LlvmTools, + dist::LlvmBitcodeLinker, dist::RustDev, dist::Bootstrap, dist::Extended, diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 4f99079a57f36..89fcac2a84b0a 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -20,6 +20,7 @@ pub(crate) enum OverlayKind { RLS, RustAnalyzer, RustcCodegenCranelift, + LlvmBitcodeLinker, } impl OverlayKind { @@ -64,6 +65,12 @@ impl OverlayKind { "compiler/rustc_codegen_cranelift/LICENSE-APACHE", "compiler/rustc_codegen_cranelift/LICENSE-MIT", ], + OverlayKind::LlvmBitcodeLinker => &[ + "COPYRIGHT", + "LICENSE-APACHE", + "LICENSE-MIT", + "src/tools/llvm-bitcode-linker/README.md", + ], } } @@ -87,6 +94,7 @@ impl OverlayKind { .rust_analyzer_info .version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")), OverlayKind::RustcCodegenCranelift => builder.rust_version(), + OverlayKind::LlvmBitcodeLinker => builder.rust_version(), } } } diff --git a/src/doc/unstable-book/src/compiler-flags/codegen-options.md b/src/doc/unstable-book/src/compiler-flags/codegen-options.md index 31dfcdb199ab9..cc51554706d07 100644 --- a/src/doc/unstable-book/src/compiler-flags/codegen-options.md +++ b/src/doc/unstable-book/src/compiler-flags/codegen-options.md @@ -10,6 +10,10 @@ In addition to the stable set of linker flavors, the following unstable values a - `ptx`: use [`rust-ptx-linker`](https://github.com/denzp/rust-ptx-linker) for Nvidia NVPTX GPGPU support. - `bpf`: use [`bpf-linker`](https://github.com/alessandrod/bpf-linker) for eBPF support. +- `llbc`: for linking in llvm bitcode. Install the preview rustup components`llvm-bitcode-linker` + and `llvm-tools` to use as a self-contained linker by passing + `-Zunstable-options -Clink-self-contained=+linker` together with `-Clinker-flavor=llbc`. + Can currently only be used for Nvidia NVPTX targets (`nvptx64-nvidia-cuda`). Additionally, a set of more precise linker flavors also exists, for example allowing targets to declare that they use the LLD linker by default. The following values are currently unstable, and diff --git a/src/tools/llvm-bitcode-linker/src/linker.rs b/src/tools/llvm-bitcode-linker/src/linker.rs index aa6b6443e4d90..40572f22342be 100644 --- a/src/tools/llvm-bitcode-linker/src/linker.rs +++ b/src/tools/llvm-bitcode-linker/src/linker.rs @@ -62,7 +62,7 @@ impl Session { .arg("-o") .arg(&self.link_path) .output() - .unwrap(); + .context("An error occured when calling llvm-link. Make sure the llvm-tools component is installed.")?; if !llvm_link_output.status.success() { tracing::error!( @@ -108,7 +108,9 @@ impl Session { opt_cmd.arg("--strip-debug"); } - let opt_output = opt_cmd.output().unwrap(); + let opt_output = opt_cmd.output().context( + "An error occured when calling opt. Make sure the llvm-tools component is installed.", + )?; if !opt_output.status.success() { tracing::error!( @@ -133,8 +135,11 @@ impl Session { lcc_command.arg("--mcpu").arg(mcpu); } - let lcc_output = - lcc_command.arg(&self.opt_path).arg("-o").arg(&self.out_path).output().unwrap(); + let lcc_output = lcc_command + .arg(&self.opt_path) + .arg("-o").arg(&self.out_path) + .output() + .context("An error occured when calling llc. Make sure the llvm-tools component is installed.")?; if !lcc_output.status.success() { tracing::error!( From 435db9b9bd404c1bc632fbb6ade8b4ce92c2828c Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 15 Apr 2024 13:33:08 +0000 Subject: [PATCH 22/22] Use RPITIT for `Successors` and `Predecessors` traits Now with RPITIT instead of GAT! --- compiler/rustc_borrowck/src/constraints/graph.rs | 4 +--- compiler/rustc_data_structures/src/graph/mod.rs | 12 ++---------- .../rustc_data_structures/src/graph/reference.rs | 8 ++------ compiler/rustc_data_structures/src/graph/scc/mod.rs | 4 +--- compiler/rustc_data_structures/src/graph/tests.rs | 10 ++-------- .../rustc_data_structures/src/graph/vec_graph/mod.rs | 4 +--- compiler/rustc_middle/src/mir/basic_blocks.rs | 10 +++------- compiler/rustc_mir_transform/src/coverage/graph.rs | 8 ++------ 8 files changed, 14 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs index 2dfaeb3ae7605..540b466560c5d 100644 --- a/compiler/rustc_borrowck/src/constraints/graph.rs +++ b/compiler/rustc_borrowck/src/constraints/graph.rs @@ -223,9 +223,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph } impl<'s, 'tcx, D: ConstraintGraphDirection> graph::Successors for RegionGraph<'s, 'tcx, D> { - type Successors<'g> = Successors<'s, 'tcx, D> where Self: 'g; - - fn successors(&self, node: Self::Node) -> Self::Successors<'_> { + fn successors(&self, node: Self::Node) -> impl Iterator { self.outgoing_regions(node) } } diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index 61bee2ee0bba5..3ae3023a91b34 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -25,19 +25,11 @@ pub trait StartNode: DirectedGraph { } pub trait Successors: DirectedGraph { - type Successors<'g>: Iterator - where - Self: 'g; - - fn successors(&self, node: Self::Node) -> Self::Successors<'_>; + fn successors(&self, node: Self::Node) -> impl Iterator; } pub trait Predecessors: DirectedGraph { - type Predecessors<'g>: Iterator - where - Self: 'g; - - fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_>; + fn predecessors(&self, node: Self::Node) -> impl Iterator; } /// Alias for [`DirectedGraph`] + [`StartNode`] + [`Predecessors`] + [`Successors`]. diff --git a/compiler/rustc_data_structures/src/graph/reference.rs b/compiler/rustc_data_structures/src/graph/reference.rs index 16b019374be7f..7a487552f5385 100644 --- a/compiler/rustc_data_structures/src/graph/reference.rs +++ b/compiler/rustc_data_structures/src/graph/reference.rs @@ -15,17 +15,13 @@ impl<'graph, G: StartNode> StartNode for &'graph G { } impl<'graph, G: Successors> Successors for &'graph G { - type Successors<'g> = G::Successors<'g> where 'graph: 'g; - - fn successors(&self, node: Self::Node) -> Self::Successors<'_> { + fn successors(&self, node: Self::Node) -> impl Iterator { (**self).successors(node) } } impl<'graph, G: Predecessors> Predecessors for &'graph G { - type Predecessors<'g> = G::Predecessors<'g> where 'graph: 'g; - - fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> { + fn predecessors(&self, node: Self::Node) -> impl Iterator { (**self).predecessors(node) } } diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index 1cd0edfe57fd4..5021e5e8fc090 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -104,9 +104,7 @@ impl NumEdges for Sccs { } impl Successors for Sccs { - type Successors<'g> = std::iter::Cloned>; - - fn successors(&self, node: S) -> Self::Successors<'_> { + fn successors(&self, node: S) -> impl Iterator { self.successors(node).iter().cloned() } } diff --git a/compiler/rustc_data_structures/src/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs index 118b6bd3eb687..85c2703cc2538 100644 --- a/compiler/rustc_data_structures/src/graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/tests.rs @@ -1,7 +1,5 @@ use crate::fx::FxHashMap; use std::cmp::max; -use std::iter; -use std::slice; use super::*; @@ -49,17 +47,13 @@ impl StartNode for TestGraph { } impl Predecessors for TestGraph { - type Predecessors<'g> = iter::Cloned>; - - fn predecessors(&self, node: usize) -> Self::Predecessors<'_> { + fn predecessors(&self, node: usize) -> impl Iterator { self.predecessors[&node].iter().cloned() } } impl Successors for TestGraph { - type Successors<'g> = iter::Cloned>; - - fn successors(&self, node: usize) -> Self::Successors<'_> { + fn successors(&self, node: usize) -> impl Iterator { self.successors[&node].iter().cloned() } } diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs index 3f9d8ec0acabb..26c86469fad84 100644 --- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs @@ -93,9 +93,7 @@ impl NumEdges for VecGraph { } impl Successors for VecGraph { - type Successors<'g> = std::iter::Cloned>; - - fn successors(&self, node: N) -> Self::Successors<'_> { + fn successors(&self, node: N) -> impl Iterator { self.successors(node).iter().cloned() } } diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 36e067c130641..1086d647721b7 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -1,5 +1,5 @@ use crate::mir::traversal::Postorder; -use crate::mir::{BasicBlock, BasicBlockData, Successors, Terminator, TerminatorKind, START_BLOCK}; +use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind, START_BLOCK}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph; @@ -156,19 +156,15 @@ impl<'tcx> graph::StartNode for BasicBlocks<'tcx> { } impl<'tcx> graph::Successors for BasicBlocks<'tcx> { - type Successors<'b> = Successors<'b> where 'tcx: 'b; - #[inline] - fn successors(&self, node: Self::Node) -> Self::Successors<'_> { + fn successors(&self, node: Self::Node) -> impl Iterator { self.basic_blocks[node].terminator().successors() } } impl<'tcx> graph::Predecessors for BasicBlocks<'tcx> { - type Predecessors<'b> = std::iter::Copied> where 'tcx: 'b; - #[inline] - fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> { + fn predecessors(&self, node: Self::Node) -> impl Iterator { self.predecessors()[node].iter().copied() } } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index c187466403f83..1895735ab3523 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -209,19 +209,15 @@ impl graph::StartNode for CoverageGraph { } impl graph::Successors for CoverageGraph { - type Successors<'g> = std::iter::Cloned>; - #[inline] - fn successors(&self, node: Self::Node) -> Self::Successors<'_> { + fn successors(&self, node: Self::Node) -> impl Iterator { self.successors[node].iter().cloned() } } impl graph::Predecessors for CoverageGraph { - type Predecessors<'g> = std::iter::Copied>; - #[inline] - fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> { + fn predecessors(&self, node: Self::Node) -> impl Iterator { self.predecessors[node].iter().copied() } }