From 0307fa347466f58ccde75ffae314abf2cc19f803 Mon Sep 17 00:00:00 2001 From: yaraksan Date: Thu, 18 Aug 2022 20:05:17 +0200 Subject: [PATCH 1/6] Add diagnostic lints to rustc_typeck --- compiler/rustc_typeck/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 8c6fb6a77181d..43077d291ec56 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -55,6 +55,8 @@ This API is completely unstable and subject to change. */ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(box_patterns)] From 9d4d7f828d5f7eda54f25b1ac040a69236e4d031 Mon Sep 17 00:00:00 2001 From: yaraksan Date: Thu, 18 Aug 2022 21:50:21 +0200 Subject: [PATCH 2/6] Ported unsafe trait diagnostics --- .../locales/en-US/typeck.ftl | 9 ++++++ .../rustc_typeck/src/coherence/unsafety.rs | 30 ++++--------------- compiler/rustc_typeck/src/errors.rs | 25 ++++++++++++++++ compiler/rustc_typeck/src/lib.rs | 2 -- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/typeck.ftl index 0014da17c88e5..11a656a318ebc 100644 --- a/compiler/rustc_error_messages/locales/en-US/typeck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/typeck.ftl @@ -131,3 +131,12 @@ typeck_unused_extern_crate = typeck_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition .suggestion = convert it to a `{$msg_code}` + +typeck_safe_trait_implemented_as_unsafe = + implementing the trait `{$trait_name}` is not unsafe + +typeck_unsafe_trait_implemented_without_unsafe_keyword = + the trait `{$trait_name}` requires an `unsafe impl` declaration + +typeck_attribute_requires_unsafe_keyword = + requires an `unsafe impl` declaration due to `#[{$attr_name}]` attribute \ No newline at end of file diff --git a/compiler/rustc_typeck/src/coherence/unsafety.rs b/compiler/rustc_typeck/src/coherence/unsafety.rs index e45fb5fe41c02..2142c8d32fbe1 100644 --- a/compiler/rustc_typeck/src/coherence/unsafety.rs +++ b/compiler/rustc_typeck/src/coherence/unsafety.rs @@ -1,13 +1,14 @@ //! Unsafety checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::Unsafety; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; +use crate::errors::{SafeTraitImplementedAsUnsafe, UnsafeTraitImplementedWithoutUnsafeKeyword, AttributeRequiresUnsafeKeyword}; + pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl)); let item = tcx.hir().expect_item(def_id); @@ -19,36 +20,15 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle"); match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) { (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => { - struct_span_err!( - tcx.sess, - item.span, - E0199, - "implementing the trait `{}` is not unsafe", - trait_ref.print_only_trait_path() - ) - .emit(); + tcx.sess.emit_err(SafeTraitImplementedAsUnsafe { span: item.span, trait_name: trait_ref.print_only_trait_path().to_string() }); } (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => { - struct_span_err!( - tcx.sess, - item.span, - E0200, - "the trait `{}` requires an `unsafe impl` declaration", - trait_ref.print_only_trait_path() - ) - .emit(); + tcx.sess.emit_err(UnsafeTraitImplementedWithoutUnsafeKeyword { span: item.span, trait_name: trait_ref.print_only_trait_path().to_string() }); } (Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => { - struct_span_err!( - tcx.sess, - item.span, - E0569, - "requires an `unsafe impl` declaration due to `#[{}]` attribute", - attr_name - ) - .emit(); + tcx.sess.emit_err(AttributeRequiresUnsafeKeyword { span: item.span, attr_name }); } (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => { diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 76599721e586f..6234daa6494af 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -340,3 +340,28 @@ pub struct ExternCrateNotIdiomatic { pub msg_code: String, pub suggestion_code: String, } + +#[derive(SessionDiagnostic)] +#[error(typeck::safe_trait_implemented_as_unsafe, code = "E0199")] +pub struct SafeTraitImplementedAsUnsafe { + #[primary_span] + #[label] + pub span: Span, + pub trait_name: String, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::unsafe_trait_implemented_without_unsafe_keyword, code = "E0200")] +pub struct UnsafeTraitImplementedWithoutUnsafeKeyword { + #[primary_span] + pub span: Span, + pub trait_name: String, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::attribute_requires_unsafe_keyword, code = "E0569")] +pub struct AttributeRequiresUnsafeKeyword<'a> { + #[primary_span] + pub span: Span, + pub attr_name: &'a str, +} \ No newline at end of file diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 43077d291ec56..8c6fb6a77181d 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -55,8 +55,6 @@ This API is completely unstable and subject to change. */ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(box_patterns)] From 6e01d8b3176a132d10e73c4ebe0dc6949e0eefab Mon Sep 17 00:00:00 2001 From: yaraksan Date: Sun, 21 Aug 2022 19:36:32 +0200 Subject: [PATCH 3/6] Add more ports of diagnostics to rustc_typeck --- .../locales/en-US/typeck.ftl | 104 ++++++- compiler/rustc_typeck/src/astconv/errors.rs | 45 ++- compiler/rustc_typeck/src/astconv/mod.rs | 65 ++-- .../rustc_typeck/src/coherence/unsafety.rs | 15 +- compiler/rustc_typeck/src/collect.rs | 94 ++---- compiler/rustc_typeck/src/errors.rs | 284 +++++++++++++++++- compiler/rustc_typeck/src/impl_wf_check.rs | 41 +-- compiler/rustc_typeck/src/lib.rs | 88 ++---- 8 files changed, 493 insertions(+), 243 deletions(-) mode change 100644 => 100755 compiler/rustc_error_messages/locales/en-US/typeck.ftl diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/typeck.ftl old mode 100644 new mode 100755 index 11a656a318ebc..7dc738fb66604 --- a/compiler/rustc_error_messages/locales/en-US/typeck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/typeck.ftl @@ -139,4 +139,106 @@ typeck_unsafe_trait_implemented_without_unsafe_keyword = the trait `{$trait_name}` requires an `unsafe impl` declaration typeck_attribute_requires_unsafe_keyword = - requires an `unsafe impl` declaration due to `#[{$attr_name}]` attribute \ No newline at end of file + requires an `unsafe impl` declaration due to `#[{$attr_name}]` attribute + +typeck_explicit_use_of_destructor = + explicit use of destructor method + .label = explicit destructor calls not allowed + .suggestion = consider using `drop` function + +typeck_unable_to_find_overloaded_call_trait = + failed to find an overloaded call trait for closure call + .help = make sure the `fn`/`fn_mut`/`fn_once` lang items are defined + and have associated `call`/`call_mut`/`call_once` functions + +typeck_type_parameter_not_constrained_for_impl = + the {$kind_name} parameter `{$name}` is not constrained by the + impl trait, self type, or predicates (SESSION DIAGNOSTIC GENERATED) + .label = unconstrained {$kind_name} parameter (SESSION DIAGNOSTIC GENERATED) + .first_note = expressions using a const parameter must map each value to a distinct output value (SESSION DIAGNOSTIC GENERATED) + .second_note = proving the result of expressions other than the parameter are unique is not supported (SESSION DIAGNOSTIC GENERATED) + +typeck_associated_items_not_distinct = + duplicate definitions with name `{$ident}`: (SESSION DIAGNOSTIC GENERATED) + .label = duplicate definition (SESSION DIAGNOSTIC GENERATED) + .prev_def_label = previous definition of `{$ident}` here (SESSION DIAGNOSTIC GENERATED) + +typeck_associated_items_not_defined_in_trait = + associated type `{$assoc_name}` not found for `{$ty_param_name}` (SESSION DIAGNOSTIC GENERATED) + .suggest_similarily_named_type = there is an associated type with a similar name (SESSION DIAGNOSTIC GENERATED) + .label_similarily_named_type = there is a similarly named associated type `{$suggested_name}` in the trait `{$trait_name}` (SESSION DIAGNOSTIC GENERATED) + .label_type_not_found = associated type `{$assoc_name}` not found (SESSION DIAGNOSTIC GENERATED) + +typeck_enum_discriminant_overflow = + enum discriminant overflowed + .label = overflowed on value after {$last_good_discriminant} + .note = explicitly set `{$overflown_discriminant} = {$wrapped_value}` if that is desired outcome + +typeck_rustc_paren_sugar_not_enabled = + the `#[rustc_paren_sugar]` attribute is a temporary means of controlling + which traits can use parenthetical notation + .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it + +typeck_attribute_on_non_foreign_function = + `#[{$attr_name}]` may only be used on foreign functions + +ffi_const_and_ffi_pure_on_same_function = + `#[ffi_const]` function cannot be `#[ffi_pure]` + +cmse_nonsecure_entry_requires_c_abi = + `#[cmse_nonsecure_entry]` requires C ABI + +cmse_nonsecure_entry_requires_trust_zone_m_ext = + `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension + +typeck_track_caller_requires_cabi = + `#[track_caller]` requires Rust ABI + +typeck_export_name_contains_null_characters = + `export_name` may not contain null characters + +typeck_instruction_set_unsupported_on_target = + target does not support `#[instruction_set]` + +typeck_varargs_on_non_cabi_function = + C-variadic function must have C or cdecl calling convention + .label = C-variadics require C or cdecl calling convention + +typeck_generic_params_on_main_function = + `main` function is not allowed to have generic + parameters + .label = `main` cannot have generic parameters + +typeck_when_clause_on_main_function = + `main` function is not allowed to have a `where` clause + .label = `main` cannot have a `where` clause + +typeck_async_main_function = + `main` function is not allowed to be `async` + .label = main` function is not allowed to be `async` + +typeck_generic_return_type_on_main = + `main` function return type is not allowed to have generic + parameters + +typeck_type_parameter_on_start_function = + start function is not allowed to have type parameters + .label = start function cannot have type parameters + +typeck_where_clause_on_start_function = + start function is not allowed to have a `where` clause + .label = start function cannot have a `where` clause + +typeck_async_start_function = + `start` is not allowed to be `async` + +typeck_ambiguous_associated_type = + ambiguous associated type + .fix_std_module_text = you are looking for the module in `std`, not the primitive type + .fix_use_fully_qualified_syntax = use fully-qualified syntax + +typeck_enum_variant_not_found = + no variant named `{$assoc_ident}` found for enum `{$self_type}` + .fix_similar_type = there is a variant with a similar name + .info_label = variant not found in `{$self_type}` + .info_label_at_enum = variant `{$assoc_ident}` not found here \ No newline at end of file diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index ff39bf36129bb..112e92efc55a7 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -1,5 +1,5 @@ use crate::astconv::AstConv; -use crate::errors::{ManualImplementation, MissingTypeParams}; +use crate::errors::{AssociatedTypeNotDefinedInTrait, AssociatedTypeNotDefinedInTraitComment, ManualImplementation, MissingTypeParams}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; @@ -138,14 +138,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a // valid span, so we point at the whole path segment instead. let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span }; - let mut err = struct_span_err!( - self.tcx().sess, + // let mut err = struct_span_err!( + // self.tcx().sess, + // span, + // E0220, + // "associated type `{}` not found for `{}`", + // assoc_name, + // ty_param_name + // ); + + let mut err = AssociatedTypeNotDefinedInTrait { span, - E0220, - "associated type `{}` not found for `{}`", assoc_name, - ty_param_name - ); + ty_param_name, + comment: AssociatedTypeNotDefinedInTraitComment::CommentNotFound { span, assoc_name } + }; let all_candidate_names: Vec<_> = all_candidates() .flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) @@ -158,13 +165,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { find_best_match_for_name(&all_candidate_names, assoc_name.name, None), assoc_name.span != DUMMY_SP, ) { - err.span_suggestion( - assoc_name.span, - "there is an associated type with a similar name", - suggested_name, - Applicability::MaybeIncorrect, - ); - return err.emit(); + err.comment = AssociatedTypeNotDefinedInTraitComment::SuggestSimilarType { span, similar: suggested_name }; + + return self.tcx().sess.emit_err(err); } // If we didn't find a good item in the supertraits (or couldn't get @@ -208,19 +211,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) .collect::>()[..] { - err.span_label( - assoc_name.span, - format!( - "there is a similarly named associated type `{suggested_name}` in the trait `{}`", - self.tcx().def_path_str(*best_trait) - ), - ); - return err.emit(); + err.comment = AssociatedTypeNotDefinedInTraitComment::LabelSimilarType { span, suggested_name, trait_name: self.tcx().def_path_str(*best_trait) }; + + return self.tcx().sess.emit_err(err); } } - err.span_label(span, format!("associated type `{}` not found", assoc_name)); - err.emit() + self.tcx().sess.emit_err(err) } /// When there are any missing associated types, emit an E0191 error and attempt to supply a diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 1e6cb53f3eeae..f4cdc18a69eb0 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -7,10 +7,7 @@ mod generics; use crate::bounds::Bounds; use crate::collect::HirPlaceholderCollector; -use crate::errors::{ - AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits, - TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified, -}; +use crate::errors::{AmbiguousAssociatedType, AmbiguousAssociatedTypeFixSuggestion, AmbiguousLifetimeBound, EnumVariantNotFound, EnumVariantNotFoundFixOrInfo, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits, TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified}; use crate::middle::resolve_lifetime as rl; use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; @@ -1576,29 +1573,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_str: &str, name: Symbol, ) -> ErrorGuaranteed { - let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type"); - if self + let fix = if self .tcx() .resolutions(()) .confused_type_with_std_module .keys() - .any(|full_span| full_span.contains(span)) - { - err.span_suggestion( - span.shrink_to_lo(), - "you are looking for the module in `std`, not the primitive type", - "std::", - Applicability::MachineApplicable, - ); + .any(|full_span| full_span.contains(span)) { + AmbiguousAssociatedTypeFixSuggestion::StdModule { span: span.shrink_to_lo() } } else { - err.span_suggestion( + AmbiguousAssociatedTypeFixSuggestion::UseFullyQualifiedSyntax { span, - "use fully-qualified syntax", - format!("<{} as {}>::{}", type_str, trait_str, name), - Applicability::HasPlaceholders, - ); - } - err.emit() + type_str, + trait_str, + name + } + }; + + self.tcx().sess.emit_err(AmbiguousAssociatedType { span, possible_fix: fix }) } // Search for a bound on a type parameter which includes the associated item @@ -1922,17 +1913,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let msg = format!("expected type, found variant `{}`", assoc_ident); tcx.sess.span_err(span, &msg) } else if qself_ty.is_enum() { - let mut err = struct_span_err!( - tcx.sess, - assoc_ident.span, - E0599, - "no variant named `{}` found for enum `{}`", - assoc_ident, - qself_ty, - ); + let self_type = qself_ty.to_string(); let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT"); - if let Some(suggested_name) = find_best_match_for_name( + + let fix_or_info = if let Some(suggested_name) = find_best_match_for_name( &adt_def .variants() .iter() @@ -1941,24 +1926,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_ident.name, None, ) { - err.span_suggestion( - assoc_ident.span, - "there is a variant with a similar name", - suggested_name, - Applicability::MaybeIncorrect, - ); + EnumVariantNotFoundFixOrInfo::SuggestSimilarName { span: assoc_ident.span, suggested_name } } else { - err.span_label( - assoc_ident.span, - format!("variant not found in `{}`", qself_ty), - ); - } - - if let Some(sp) = tcx.hir().span_if_local(adt_def.did()) { - err.span_label(sp, format!("variant `{}` not found here", assoc_ident)); - } + EnumVariantNotFoundFixOrInfo::InfoLabel { span: assoc_ident.span, self_type: &self_type } + }; - err.emit() + tcx.sess.emit_err(EnumVariantNotFound { span: assoc_ident.span, info_label_at_enum: tcx.hir().span_if_local(adt_def.did()), fix_or_info, assoc_ident, self_type: &self_type }) } else if let Some(reported) = qself_ty.error_reported() { reported } else { diff --git a/compiler/rustc_typeck/src/coherence/unsafety.rs b/compiler/rustc_typeck/src/coherence/unsafety.rs index 2142c8d32fbe1..e0510413be497 100644 --- a/compiler/rustc_typeck/src/coherence/unsafety.rs +++ b/compiler/rustc_typeck/src/coherence/unsafety.rs @@ -7,7 +7,10 @@ use rustc_hir::Unsafety; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; -use crate::errors::{SafeTraitImplementedAsUnsafe, UnsafeTraitImplementedWithoutUnsafeKeyword, AttributeRequiresUnsafeKeyword}; +use crate::errors::{ + AttributeRequiresUnsafeKeyword, SafeTraitImplementedAsUnsafe, + UnsafeTraitImplementedWithoutUnsafeKeyword, +}; pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl)); @@ -20,11 +23,17 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle"); match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) { (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => { - tcx.sess.emit_err(SafeTraitImplementedAsUnsafe { span: item.span, trait_name: trait_ref.print_only_trait_path().to_string() }); + tcx.sess.emit_err(SafeTraitImplementedAsUnsafe { + span: item.span, + trait_name: trait_ref.print_only_trait_path().to_string(), + }); } (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => { - tcx.sess.emit_err(UnsafeTraitImplementedWithoutUnsafeKeyword { span: item.span, trait_name: trait_ref.print_only_trait_path().to_string() }); + tcx.sess.emit_err(UnsafeTraitImplementedWithoutUnsafeKeyword { + span: item.span, + trait_name: trait_ref.print_only_trait_path().to_string(), + }); } (Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index e7c5ecc60ec78..a464dd1b957c1 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -25,7 +25,7 @@ use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, error_code}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; @@ -48,6 +48,7 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::{abi, SanitizerSet}; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; use std::iter; +use crate::errors::{AttributeOnNonForeignFunction, CMSENonSecureEntryRequiresCAbi, CMSENonSecureEntryRequiresTrustZoneMExt, EnumDiscriminantOverflow, ExportNameContainsNullCharacters, FFIConstAndFFIPureOnSameFunction, InstructionSetUnsupportedOnTarget, RustcParenSugarNotEnabled, TrackCallerRequiresCAbi}; mod item_bounds; mod type_of; @@ -927,16 +928,14 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::V } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) { Some(discr) } else { - struct_span_err!(tcx.sess, variant.span, E0370, "enum discriminant overflowed") - .span_label( - variant.span, - format!("overflowed on value after {}", prev_discr.unwrap()), - ) - .note(&format!( - "explicitly set `{} = {}` if that is desired outcome", - variant.ident, wrapped_discr - )) - .emit(); + tcx.sess.emit_err(EnumDiscriminantOverflow { + span: variant.span, + last_good_discriminant: prev_discr.unwrap().to_string(), + _note: (), + overflown_discriminant: variant.ident, + wrapped_value: wrapped_discr.to_string() + }); + None } .unwrap_or(wrapped_discr), @@ -1196,14 +1195,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar); if paren_sugar && !tcx.features().unboxed_closures { - tcx.sess - .struct_span_err( - item.span, - "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ - which traits can use parenthetical notation", - ) - .help("add `#![feature(unboxed_closures)]` to the crate attributes to use it") - .emit(); + tcx.sess.emit_err(RustcParenSugarNotEnabled { span: item.span, _help: () }); } let is_marker = tcx.has_attr(def_id, sym::marker); @@ -2747,50 +2739,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE; } else { // `#[ffi_returns_twice]` is only allowed `extern fn`s. - struct_span_err!( - tcx.sess, - attr.span, - E0724, - "`#[ffi_returns_twice]` may only be used on foreign functions" - ) - .emit(); + tcx.sess.emit_err(AttributeOnNonForeignFunction { span: attr.span, error_code: error_code!(E0724), attr_name: "ffi_returns_twice" }); } } else if attr.has_name(sym::ffi_pure) { if tcx.is_foreign_item(did) { if attrs.iter().any(|a| a.has_name(sym::ffi_const)) { // `#[ffi_const]` functions cannot be `#[ffi_pure]` - struct_span_err!( - tcx.sess, - attr.span, - E0757, - "`#[ffi_const]` function cannot be `#[ffi_pure]`" - ) - .emit(); + tcx.sess.emit_err(FFIConstAndFFIPureOnSameFunction { span: attr.span }); } else { codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE; } } else { // `#[ffi_pure]` is only allowed on foreign functions - struct_span_err!( - tcx.sess, - attr.span, - E0755, - "`#[ffi_pure]` may only be used on foreign functions" - ) - .emit(); + tcx.sess.emit_err(AttributeOnNonForeignFunction { span: attr.span, error_code: error_code!(E0755), attr_name: "ffi_pure" }); } } else if attr.has_name(sym::ffi_const) { if tcx.is_foreign_item(did) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST; } else { // `#[ffi_const]` is only allowed on foreign functions - struct_span_err!( - tcx.sess, - attr.span, - E0756, - "`#[ffi_const]` may only be used on foreign functions" - ) - .emit(); + tcx.sess.emit_err(AttributeOnNonForeignFunction { span: attr.span, error_code: error_code!(E0756), attr_name: "ffi_const" }); } } else if attr.has_name(sym::rustc_allocator_nounwind) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; @@ -2877,25 +2845,17 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { } } else if attr.has_name(sym::cmse_nonsecure_entry) { if !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) { - struct_span_err!( - tcx.sess, - attr.span, - E0776, - "`#[cmse_nonsecure_entry]` requires C ABI" - ) - .emit(); + tcx.sess.emit_err(CMSENonSecureEntryRequiresCAbi { span: attr.span }); } if !tcx.sess.target.llvm_target.contains("thumbv8m") { - struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") - .emit(); + tcx.sess.emit_err(CMSENonSecureEntryRequiresTrustZoneMExt { span: attr.span }); } codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY; } else if attr.has_name(sym::thread_local) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; } else if attr.has_name(sym::track_caller) { if !tcx.is_closure(did.to_def_id()) && tcx.fn_sig(did).abi() != abi::Abi::Rust { - struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") - .emit(); + tcx.sess.emit_err(TrackCallerRequiresCAbi { span: attr.span }); } if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller { feature_err( @@ -2912,13 +2872,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { if s.as_str().contains('\0') { // `#[export_name = ...]` will be converted to a null-terminated string, // so it may not contain any null characters. - struct_span_err!( - tcx.sess, - attr.span, - E0648, - "`export_name` may not contain null characters" - ) - .emit(); + + tcx.sess.emit_err(ExportNameContainsNullCharacters { span: attr.span }); } codegen_fn_attrs.export_name = Some(s); } @@ -3022,13 +2977,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { match segments.as_slice() { [sym::arm, sym::a32] | [sym::arm, sym::t32] => { if !tcx.sess.target.has_thumb_interworking { - struct_span_err!( - tcx.sess.diagnostic(), - attr.span, - E0779, - "target does not support `#[instruction_set]`" - ) - .emit(); + tcx.sess.emit_err(InstructionSetUnsupportedOnTarget { span: attr.span }); + None } else if segments[1] == sym::a32 { Some(InstructionSetAttr::ArmA32) diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 6234daa6494af..44d5612c24dba 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -1,5 +1,5 @@ //! Errors emitted by typeck. -use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, DiagnosticId}; use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::Ty; use rustc_session::{parse::ParseSess, SessionDiagnostic}; @@ -364,4 +364,284 @@ pub struct AttributeRequiresUnsafeKeyword<'a> { #[primary_span] pub span: Span, pub attr_name: &'a str, -} \ No newline at end of file +} + +#[derive(SessionDiagnostic)] +#[error(typeck::type_parameter_not_constrained_for_impl, code = "E0207")] +pub struct TypeParameterNotConstrainedForImpl<'a> { + #[primary_span] + pub span: Span, + pub kind_name: &'a str, + pub name: String, + #[note(typeck::first_note)] + pub first_note: Option<()>, + #[note(typeck::second_note)] + pub second_note: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::associated_items_not_distinct, code = "E0201")] +pub struct AssociatedItemsNotDistinct { + #[primary_span] + #[label] + pub span: Span, + pub ident: String, + #[label(typeck::prev_def_label)] + pub prev_definition_span: Span, +} + +#[derive(SessionSubdiagnostic)] +pub enum AssociatedTypeNotDefinedInTraitComment { + #[suggestion( + typeck::suggest_similarily_named_type, + code = "{similar}", + applicability = "maybe-incorrect" + )] + SuggestSimilarType { + #[primary_span] + span: Span, + similar: Symbol, + }, + #[label(typeck::label_similarily_named_type)] + LabelSimilarType { + #[primary_span] + span: Span, + suggested_name: Symbol, + trait_name: String + }, + #[label(typeck::label_type_not_found)] + CommentNotFound { + #[primary_span] + span: Span, + assoc_name: Ident, + } +} + + +#[derive(SessionDiagnostic)] +#[error(typeck::associated_items_not_defined_in_trait, code = "E0220")] +pub struct AssociatedTypeNotDefinedInTrait<'a> { + #[primary_span] + pub span: Span, + pub assoc_name: Ident, + pub ty_param_name: &'a str, + #[subdiagnostic] + pub comment: AssociatedTypeNotDefinedInTraitComment +} + +#[derive(SessionDiagnostic)] +#[error(typeck::enum_discriminant_overflow, code = "E0370")] +pub struct EnumDiscriminantOverflow { + #[primary_span] + #[label] + pub span: Span, + pub last_good_discriminant: String, + pub overflown_discriminant: Ident, + pub wrapped_value: String, + #[note] + pub _note: (), +} + +#[derive(SessionDiagnostic)] +#[error(typeck::rustc_paren_sugar_not_enabled)] +pub struct RustcParenSugarNotEnabled { + #[primary_span] + pub span: Span, + #[help] + pub _help: (), +} + +pub struct AttributeOnNonForeignFunction<'a> { + pub span: Span, + pub error_code: DiagnosticId, + pub attr_name: &'a str, +} + +// Manual implementation of `SessionDiagnostic` to be able to call `span_to_snippet`. +impl<'a, 'b> SessionDiagnostic<'a> for AttributeOnNonForeignFunction<'b> { + fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let mut err = sess.span_diagnostic.struct_span_err_with_code( + self.span, + rustc_errors::fluent::typeck::attribute_on_non_foreign_function, + self.error_code, + ); + err.set_arg("attr_name", self.attr_name); + + err + } +} + +#[derive(SessionDiagnostic)] +#[error(typeck::ffi_const_and_ffi_pure_on_same_function, code = "E0724")] +pub struct FFIConstAndFFIPureOnSameFunction { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::cmse_nonsecure_entry_requires_c_abi, code = "E0776")] +pub struct CMSENonSecureEntryRequiresCAbi { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::cmse_nonsecure_entry_requires_trust_zone_m_ext, code = "E0775")] +pub struct CMSENonSecureEntryRequiresTrustZoneMExt { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::track_caller_requires_cabi, code = "E0737")] +pub struct TrackCallerRequiresCAbi { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::export_name_contains_null_characters, code = "E0648")] +pub struct ExportNameContainsNullCharacters { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::instruction_set_unsupported_on_target, code = "E0779")] +pub struct InstructionSetUnsupportedOnTarget { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::varargs_on_non_cabi_function, code = "E0045")] +pub struct VarargsOnNonCabiFunction { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::generic_params_on_main_function, code = "E0131")] +pub struct GenericParamsOnMainFunction { + #[primary_span] + pub span: Span, + #[label] + pub generics_param_span: Option +} + +#[derive(SessionDiagnostic)] +#[error(typeck::when_clause_on_main_function, code = "E0646")] +pub struct WhenClauseOnMainFunction { + #[primary_span] + pub span: Span, + #[label] + pub generics_where_clauses_span: Option +} + +#[derive(SessionDiagnostic)] +#[error(typeck::async_main_function, code = "E0752")] +pub struct AsyncMainFunction { + #[primary_span] + pub span: Span, + #[label] + pub asyncness_span: Option +} + +#[derive(SessionDiagnostic)] +#[error(typeck::generic_return_type_on_main, code = "E0131")] +pub struct GenericReturnTypeOnMain { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::type_parameter_on_start_function, code = "E0132")] +pub struct TypeParameterOnStartFunction { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::where_clause_on_start_function, code = "E0647")] +pub struct WhereClauseOnStartFunction { + #[primary_span] + pub span: Span, + #[label] + pub where_clause_span: Span +} + +#[derive(SessionDiagnostic)] +#[error(typeck::async_start_function, code = "E0752")] +pub struct AsyncStartFunction { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionSubdiagnostic)] +pub enum AmbiguousAssociatedTypeFixSuggestion<'a> { + #[suggestion( + typeck::fix_std_module_text, + code = "std::", + applicability = "machine-applicable" + )] + StdModule { + #[primary_span] + span: Span, + }, + #[suggestion( + typeck::fix_use_fully_qualified_syntax, + code = "<{type_str} as {trait_str}>::{name}", + applicability = "has-placeholders" + )] + UseFullyQualifiedSyntax { + #[primary_span] + span: Span, + type_str: &'a str, + trait_str: &'a str, + name: Symbol, + }, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::ambiguous_associated_type, code = "E0223")] +pub struct AmbiguousAssociatedType<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub possible_fix: AmbiguousAssociatedTypeFixSuggestion<'a> +} + + +#[derive(SessionSubdiagnostic)] +pub enum EnumVariantNotFoundFixOrInfo<'a> { + #[suggestion( + typeck::fix_similar_type, + code = "{suggested_name}", + applicability = "maybe-incorrect" + )] + SuggestSimilarName { + #[primary_span] + span: Span, + suggested_name: Symbol + }, + #[label(typeck::info_label)] + InfoLabel { + #[primary_span] + span: Span, + self_type: &'a str + }, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::enum_variant_not_found, code = "E0599")] +pub struct EnumVariantNotFound<'a> { + #[primary_span] + pub span: Span, + #[label(typeck::info_label_at_enum)] + pub info_label_at_enum: Option, + #[subdiagnostic] + pub fix_or_info: EnumVariantNotFoundFixOrInfo<'a>, + pub assoc_ident: Ident, + pub self_type: &'a str +} diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs index 9fee1eaaec983..3b709949daebf 100644 --- a/compiler/rustc_typeck/src/impl_wf_check.rs +++ b/compiler/rustc_typeck/src/impl_wf_check.rs @@ -12,7 +12,6 @@ use crate::constrained_generic_params as cgp; use min_specialization::check_min_specialization; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::struct_span_err; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::query::Providers; @@ -20,6 +19,7 @@ use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; use rustc_span::{Span, Symbol}; use std::collections::hash_map::Entry::{Occupied, Vacant}; +use crate::errors::{AssociatedItemsNotDistinct, TypeParameterNotConstrainedForImpl}; mod min_specialization; @@ -174,25 +174,15 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) } fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol) { - let mut err = struct_span_err!( - tcx.sess, + let note = if kind == "const" { Some(()) } else { None }; + + tcx.sess.emit_err(TypeParameterNotConstrainedForImpl { span, - E0207, - "the {} parameter `{}` is not constrained by the \ - impl trait, self type, or predicates", - kind, - name - ); - err.span_label(span, format!("unconstrained {} parameter", kind)); - if kind == "const" { - err.note( - "expressions using a const parameter must map each value to a distinct output value", - ); - err.note( - "proving the result of expressions other than the parameter are unique is not supported", - ); - } - err.emit(); + kind_name: kind, + name: name.to_string(), + first_note: note, + second_note: note + }); } /// Enforce that we do not have two items in an impl with the same name. @@ -209,16 +199,11 @@ fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { let ident = impl_item.ident(tcx); match seen_items.entry(ident.normalize_to_macros_2_0()) { Occupied(entry) => { - let mut err = struct_span_err!( - tcx.sess, + tcx.sess.emit_err(AssociatedItemsNotDistinct { span, - E0201, - "duplicate definitions with name `{}`:", - ident - ); - err.span_label(*entry.get(), format!("previous definition of `{}` here", ident)); - err.span_label(span, "duplicate definition"); - err.emit(); + ident: ident.to_string(), + prev_definition_span: *entry.get() + }); } Vacant(entry) => { entry.insert(span); diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 8c6fb6a77181d..aa57a0eeab84e 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -98,7 +98,7 @@ mod outlives; mod structured_errors; mod variance; -use rustc_errors::{struct_span_err, ErrorGuaranteed}; +use rustc_errors::{ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{Node, CRATE_HIR_ID}; @@ -117,6 +117,7 @@ use std::iter; use astconv::AstConv; use bounds::Bounds; +use crate::errors::{AsyncMainFunction, AsyncStartFunction, GenericParamsOnMainFunction, GenericReturnTypeOnMain, TypeParameterOnStartFunction, VarargsOnNonCabiFunction, WhenClauseOnMainFunction, WhereClauseOnStartFunction}; fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) { match (decl.c_variadic, abi) { @@ -124,13 +125,7 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl { .. }) => {} // The function is a "C-variadic" function with an incorrect calling convention. (true, _) => { - let mut err = struct_span_err!( - tcx.sess, - span, - E0045, - "C-variadic function must have C or cdecl calling convention" - ); - err.span_label(span, "C-variadics require C or cdecl calling convention").emit(); + tcx.sess.emit_err(VarargsOnNonCabiFunction { span }); } } } @@ -240,45 +235,25 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { let main_fn_predicates = tcx.predicates_of(main_def_id); if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() { let generics_param_span = main_fn_generics_params_span(tcx, main_def_id); - let msg = "`main` function is not allowed to have generic \ - parameters"; - let mut diag = - struct_span_err!(tcx.sess, generics_param_span.unwrap_or(main_span), E0131, "{}", msg); - if let Some(generics_param_span) = generics_param_span { - let label = "`main` cannot have generic parameters"; - diag.span_label(generics_param_span, label); - } - diag.emit(); + + tcx.sess.emit_err(GenericParamsOnMainFunction { span: generics_param_span.unwrap_or(main_span), generics_param_span }); + error = true; } else if !main_fn_predicates.predicates.is_empty() { // generics may bring in implicit predicates, so we skip this check if generics is present. let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id); - let mut diag = struct_span_err!( - tcx.sess, - generics_where_clauses_span.unwrap_or(main_span), - E0646, - "`main` function is not allowed to have a `where` clause" - ); - if let Some(generics_where_clauses_span) = generics_where_clauses_span { - diag.span_label(generics_where_clauses_span, "`main` cannot have a `where` clause"); - } - diag.emit(); + + tcx.sess.emit_err(WhenClauseOnMainFunction { span: generics_where_clauses_span.unwrap_or(main_span), generics_where_clauses_span }); + error = true; } let main_asyncness = tcx.asyncness(main_def_id); if let hir::IsAsync::Async = main_asyncness { - let mut diag = struct_span_err!( - tcx.sess, - main_span, - E0752, - "`main` function is not allowed to be `async`" - ); let asyncness_span = main_fn_asyncness_span(tcx, main_def_id); - if let Some(asyncness_span) = asyncness_span { - diag.span_label(asyncness_span, "`main` function is not allowed to be `async`"); - } - diag.emit(); + + tcx.sess.emit_err(AsyncMainFunction { span: main_span, asyncness_span }); + error = true; } @@ -299,9 +274,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { let return_ty = main_fnsig.output(); let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span); if !return_ty.bound_vars().is_empty() { - let msg = "`main` function return type is not allowed to have generic \ - parameters"; - struct_span_err!(tcx.sess, return_ty_span, E0131, "{}", msg).emit(); + tcx.sess.emit_err(GenericReturnTypeOnMain { span: return_ty_span }); + error = true; } let return_ty = return_ty.skip_binder(); @@ -359,40 +333,20 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind { let mut error = false; if !generics.params.is_empty() { - struct_span_err!( - tcx.sess, - generics.span, - E0132, - "start function is not allowed to have type parameters" - ) - .span_label(generics.span, "start function cannot have type parameters") - .emit(); + tcx.sess.emit_err(TypeParameterOnStartFunction { span: generics.span }); + error = true; } if generics.has_where_clause_predicates { - struct_span_err!( - tcx.sess, - generics.where_clause_span, - E0647, - "start function is not allowed to have a `where` clause" - ) - .span_label( - generics.where_clause_span, - "start function cannot have a `where` clause", - ) - .emit(); + tcx.sess.emit_err(WhereClauseOnStartFunction { span: generics.where_clause_span, where_clause_span: generics.where_clause_span }); + error = true; } if let hir::IsAsync::Async = sig.header.asyncness { let span = tcx.def_span(it.def_id); - struct_span_err!( - tcx.sess, - span, - E0752, - "`start` is not allowed to be `async`" - ) - .span_label(span, "`start` is not allowed to be `async`") - .emit(); + + tcx.sess.emit_err(AsyncStartFunction { span }); + error = true; } From 26a163497606eef591aef5ee5716f97f06f9869a Mon Sep 17 00:00:00 2001 From: yaraksan Date: Sun, 21 Aug 2022 22:47:18 +0200 Subject: [PATCH 4/6] Fixed broken tests --- .../locales/en-US/typeck.ftl | 35 +++--- compiler/rustc_typeck/src/astconv/errors.rs | 18 ++- compiler/rustc_typeck/src/astconv/mod.rs | 30 ++++- compiler/rustc_typeck/src/collect.rs | 47 +++++--- compiler/rustc_typeck/src/errors.rs | 103 +++++++++++------- compiler/rustc_typeck/src/impl_wf_check.rs | 20 ++-- compiler/rustc_typeck/src/lib.rs | 23 +++- 7 files changed, 179 insertions(+), 97 deletions(-) mode change 100755 => 100644 compiler/rustc_error_messages/locales/en-US/typeck.ftl diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/typeck.ftl old mode 100755 new mode 100644 index 7dc738fb66604..a7d7068fcc477 --- a/compiler/rustc_error_messages/locales/en-US/typeck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/typeck.ftl @@ -152,22 +152,21 @@ typeck_unable_to_find_overloaded_call_trait = and have associated `call`/`call_mut`/`call_once` functions typeck_type_parameter_not_constrained_for_impl = - the {$kind_name} parameter `{$name}` is not constrained by the - impl trait, self type, or predicates (SESSION DIAGNOSTIC GENERATED) - .label = unconstrained {$kind_name} parameter (SESSION DIAGNOSTIC GENERATED) - .first_note = expressions using a const parameter must map each value to a distinct output value (SESSION DIAGNOSTIC GENERATED) - .second_note = proving the result of expressions other than the parameter are unique is not supported (SESSION DIAGNOSTIC GENERATED) + the {$kind} parameter `{$name}` is not constrained by the impl trait, self type, or predicates + .label = unconstrained {$kind} parameter + .first_note = expressions using a const parameter must map each value to a distinct output value + .second_note = proving the result of expressions other than the parameter are unique is not supported typeck_associated_items_not_distinct = - duplicate definitions with name `{$ident}`: (SESSION DIAGNOSTIC GENERATED) - .label = duplicate definition (SESSION DIAGNOSTIC GENERATED) - .prev_def_label = previous definition of `{$ident}` here (SESSION DIAGNOSTIC GENERATED) + duplicate definitions with name `{$ident}`: + .label = duplicate definition + .prev_def_label = previous definition of `{$ident}` here typeck_associated_items_not_defined_in_trait = - associated type `{$assoc_name}` not found for `{$ty_param_name}` (SESSION DIAGNOSTIC GENERATED) - .suggest_similarily_named_type = there is an associated type with a similar name (SESSION DIAGNOSTIC GENERATED) - .label_similarily_named_type = there is a similarly named associated type `{$suggested_name}` in the trait `{$trait_name}` (SESSION DIAGNOSTIC GENERATED) - .label_type_not_found = associated type `{$assoc_name}` not found (SESSION DIAGNOSTIC GENERATED) + associated type `{$assoc_name}` not found for `{$ty_param_name}` + .suggest_similarily_named_type = there is an associated type with a similar name + .label_similarily_named_type = there is a similarly named associated type `{$suggested_name}` in the trait `{$trait_name}` + .label_type_not_found = associated type `{$assoc_name}` not found typeck_enum_discriminant_overflow = enum discriminant overflowed @@ -175,8 +174,7 @@ typeck_enum_discriminant_overflow = .note = explicitly set `{$overflown_discriminant} = {$wrapped_value}` if that is desired outcome typeck_rustc_paren_sugar_not_enabled = - the `#[rustc_paren_sugar]` attribute is a temporary means of controlling - which traits can use parenthetical notation + the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it typeck_attribute_on_non_foreign_function = @@ -205,8 +203,7 @@ typeck_varargs_on_non_cabi_function = .label = C-variadics require C or cdecl calling convention typeck_generic_params_on_main_function = - `main` function is not allowed to have generic - parameters + `main` function is not allowed to have generic parameters .label = `main` cannot have generic parameters typeck_when_clause_on_main_function = @@ -215,11 +212,10 @@ typeck_when_clause_on_main_function = typeck_async_main_function = `main` function is not allowed to be `async` - .label = main` function is not allowed to be `async` + .label = `main` function is not allowed to be `async` typeck_generic_return_type_on_main = - `main` function return type is not allowed to have generic - parameters + `main` function return type is not allowed to have generic parameters typeck_type_parameter_on_start_function = start function is not allowed to have type parameters @@ -231,6 +227,7 @@ typeck_where_clause_on_start_function = typeck_async_start_function = `start` is not allowed to be `async` + .label = `start` is not allowed to be `async` typeck_ambiguous_associated_type = ambiguous associated type diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index 112e92efc55a7..d90b701330e51 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -1,5 +1,8 @@ use crate::astconv::AstConv; -use crate::errors::{AssociatedTypeNotDefinedInTrait, AssociatedTypeNotDefinedInTraitComment, ManualImplementation, MissingTypeParams}; +use crate::errors::{ + AssociatedTypeNotDefinedInTrait, AssociatedTypeNotDefinedInTraitComment, ManualImplementation, + MissingTypeParams, +}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; @@ -151,7 +154,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span, assoc_name, ty_param_name, - comment: AssociatedTypeNotDefinedInTraitComment::CommentNotFound { span, assoc_name } + comment: AssociatedTypeNotDefinedInTraitComment::CommentNotFound { span, assoc_name }, }; let all_candidate_names: Vec<_> = all_candidates() @@ -165,7 +168,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { find_best_match_for_name(&all_candidate_names, assoc_name.name, None), assoc_name.span != DUMMY_SP, ) { - err.comment = AssociatedTypeNotDefinedInTraitComment::SuggestSimilarType { span, similar: suggested_name }; + err.comment = AssociatedTypeNotDefinedInTraitComment::SuggestSimilarType { + span, + similar: suggested_name, + }; return self.tcx().sess.emit_err(err); } @@ -211,7 +217,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) .collect::>()[..] { - err.comment = AssociatedTypeNotDefinedInTraitComment::LabelSimilarType { span, suggested_name, trait_name: self.tcx().def_path_str(*best_trait) }; + err.comment = AssociatedTypeNotDefinedInTraitComment::LabelSimilarType { + span, + suggested_name, + trait_name: self.tcx().def_path_str(*best_trait), + }; return self.tcx().sess.emit_err(err); } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index f4cdc18a69eb0..97be481b54f9c 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -7,7 +7,12 @@ mod generics; use crate::bounds::Bounds; use crate::collect::HirPlaceholderCollector; -use crate::errors::{AmbiguousAssociatedType, AmbiguousAssociatedTypeFixSuggestion, AmbiguousLifetimeBound, EnumVariantNotFound, EnumVariantNotFoundFixOrInfo, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits, TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified}; +use crate::errors::{ + AmbiguousAssociatedType, AmbiguousAssociatedTypeFixSuggestion, AmbiguousLifetimeBound, + EnumVariantNotFound, EnumVariantNotFoundFixOrInfo, MultipleRelaxedDefaultBounds, + TraitObjectDeclaredWithNoTraits, TypeofReservedKeywordUsed, + ValueOfAssociatedStructAlreadySpecified, +}; use crate::middle::resolve_lifetime as rl; use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; @@ -1578,14 +1583,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .resolutions(()) .confused_type_with_std_module .keys() - .any(|full_span| full_span.contains(span)) { + .any(|full_span| full_span.contains(span)) + { AmbiguousAssociatedTypeFixSuggestion::StdModule { span: span.shrink_to_lo() } } else { AmbiguousAssociatedTypeFixSuggestion::UseFullyQualifiedSyntax { span, type_str, trait_str, - name + name, } }; @@ -1926,12 +1932,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_ident.name, None, ) { - EnumVariantNotFoundFixOrInfo::SuggestSimilarName { span: assoc_ident.span, suggested_name } + EnumVariantNotFoundFixOrInfo::SuggestSimilarName { + span: assoc_ident.span, + suggested_name, + } } else { - EnumVariantNotFoundFixOrInfo::InfoLabel { span: assoc_ident.span, self_type: &self_type } + EnumVariantNotFoundFixOrInfo::InfoLabel { + span: assoc_ident.span, + self_type: &self_type, + } }; - tcx.sess.emit_err(EnumVariantNotFound { span: assoc_ident.span, info_label_at_enum: tcx.hir().span_if_local(adt_def.did()), fix_or_info, assoc_ident, self_type: &self_type }) + tcx.sess.emit_err(EnumVariantNotFound { + span: assoc_ident.span, + info_label_at_enum: tcx.hir().span_if_local(adt_def.did()), + fix_or_info, + assoc_ident, + self_type: &self_type, + }) } else if let Some(reported) = qself_ty.error_reported() { reported } else { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index a464dd1b957c1..b97bd46a82571 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -19,13 +19,21 @@ use crate::bounds::Bounds; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::constrained_generic_params as cgp; use crate::errors; +use crate::errors::{ + AttributeOnNonForeignFunction, CMSENonSecureEntryRequiresCAbi, + CMSENonSecureEntryRequiresTrustZoneMExt, EnumDiscriminantOverflow, + ExportNameContainsNullCharacters, FFIConstAndFFIPureOnSameFunction, + InstructionSetUnsupportedOnTarget, RustcParenSugarNotEnabled, TrackCallerRequiresCAbi, +}; use crate::middle::resolve_lifetime as rl; use rustc_ast as ast; use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, error_code}; +use rustc_errors::{ + error_code, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, +}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; @@ -48,7 +56,6 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::{abi, SanitizerSet}; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; use std::iter; -use crate::errors::{AttributeOnNonForeignFunction, CMSENonSecureEntryRequiresCAbi, CMSENonSecureEntryRequiresTrustZoneMExt, EnumDiscriminantOverflow, ExportNameContainsNullCharacters, FFIConstAndFFIPureOnSameFunction, InstructionSetUnsupportedOnTarget, RustcParenSugarNotEnabled, TrackCallerRequiresCAbi}; mod item_bounds; mod type_of; @@ -928,13 +935,13 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::V } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) { Some(discr) } else { - tcx.sess.emit_err(EnumDiscriminantOverflow { - span: variant.span, - last_good_discriminant: prev_discr.unwrap().to_string(), - _note: (), - overflown_discriminant: variant.ident, - wrapped_value: wrapped_discr.to_string() - }); + tcx.sess.emit_err(EnumDiscriminantOverflow { + span: variant.span, + last_good_discriminant: prev_discr.unwrap().to_string(), + _note: (), + overflown_discriminant: variant.ident, + wrapped_value: wrapped_discr.to_string(), + }); None } @@ -2739,7 +2746,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE; } else { // `#[ffi_returns_twice]` is only allowed `extern fn`s. - tcx.sess.emit_err(AttributeOnNonForeignFunction { span: attr.span, error_code: error_code!(E0724), attr_name: "ffi_returns_twice" }); + tcx.sess.emit_err(AttributeOnNonForeignFunction { + span: attr.span, + error_code: error_code!(E0724), + attr_name: "ffi_returns_twice", + }); } } else if attr.has_name(sym::ffi_pure) { if tcx.is_foreign_item(did) { @@ -2751,14 +2762,22 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { } } else { // `#[ffi_pure]` is only allowed on foreign functions - tcx.sess.emit_err(AttributeOnNonForeignFunction { span: attr.span, error_code: error_code!(E0755), attr_name: "ffi_pure" }); + tcx.sess.emit_err(AttributeOnNonForeignFunction { + span: attr.span, + error_code: error_code!(E0755), + attr_name: "ffi_pure", + }); } } else if attr.has_name(sym::ffi_const) { if tcx.is_foreign_item(did) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST; } else { // `#[ffi_const]` is only allowed on foreign functions - tcx.sess.emit_err(AttributeOnNonForeignFunction { span: attr.span, error_code: error_code!(E0756), attr_name: "ffi_const" }); + tcx.sess.emit_err(AttributeOnNonForeignFunction { + span: attr.span, + error_code: error_code!(E0756), + attr_name: "ffi_const", + }); } } else if attr.has_name(sym::rustc_allocator_nounwind) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; @@ -2977,7 +2996,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { match segments.as_slice() { [sym::arm, sym::a32] | [sym::arm, sym::t32] => { if !tcx.sess.target.has_thumb_interworking { - tcx.sess.emit_err(InstructionSetUnsupportedOnTarget { span: attr.span }); + tcx.sess.emit_err(InstructionSetUnsupportedOnTarget { + span: attr.span, + }); None } else if segments[1] == sym::a32 { diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 44d5612c24dba..440da1935ab88 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -1,5 +1,5 @@ //! Errors emitted by typeck. -use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, DiagnosticId}; +use rustc_errors::{error_code, Applicability, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed}; use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::Ty; use rustc_session::{parse::ParseSess, SessionDiagnostic}; @@ -345,7 +345,6 @@ pub struct ExternCrateNotIdiomatic { #[error(typeck::safe_trait_implemented_as_unsafe, code = "E0199")] pub struct SafeTraitImplementedAsUnsafe { #[primary_span] - #[label] pub span: Span, pub trait_name: String, } @@ -366,17 +365,45 @@ pub struct AttributeRequiresUnsafeKeyword<'a> { pub attr_name: &'a str, } -#[derive(SessionDiagnostic)] -#[error(typeck::type_parameter_not_constrained_for_impl, code = "E0207")] -pub struct TypeParameterNotConstrainedForImpl<'a> { - #[primary_span] +#[derive(Eq, PartialEq)] +pub enum UnconstrainedParameterType { + Type, + Lifetime, + Const +} + +pub struct TypeParameterNotConstrainedForImpl { pub span: Span, - pub kind_name: &'a str, - pub name: String, - #[note(typeck::first_note)] - pub first_note: Option<()>, - #[note(typeck::second_note)] - pub second_note: Option<()>, + pub kind: UnconstrainedParameterType, + pub name: Symbol, +} + +impl<'a> SessionDiagnostic<'a> for TypeParameterNotConstrainedForImpl { + fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let kind_msg = match self.kind { + UnconstrainedParameterType::Type => "type", + UnconstrainedParameterType::Lifetime => "lifetime", + UnconstrainedParameterType::Const => "const", + }; + + let mut err = sess.span_diagnostic.struct_span_err_with_code( + self.span, + rustc_errors::fluent::typeck::type_parameter_not_constrained_for_impl, + error_code!(E0207), + ); + + err.set_arg("name", self.name); + err.set_arg("kind", kind_msg); + + err.span_label(self.span, rustc_errors::fluent::typeck::label); + + if self.kind == UnconstrainedParameterType::Const { + err.note(rustc_errors::fluent::typeck::first_note); + err.note(rustc_errors::fluent::typeck::second_note); + } + + err + } } #[derive(SessionDiagnostic)] @@ -393,9 +420,9 @@ pub struct AssociatedItemsNotDistinct { #[derive(SessionSubdiagnostic)] pub enum AssociatedTypeNotDefinedInTraitComment { #[suggestion( - typeck::suggest_similarily_named_type, - code = "{similar}", - applicability = "maybe-incorrect" + typeck::suggest_similarily_named_type, + code = "{similar}", + applicability = "maybe-incorrect" )] SuggestSimilarType { #[primary_span] @@ -407,17 +434,16 @@ pub enum AssociatedTypeNotDefinedInTraitComment { #[primary_span] span: Span, suggested_name: Symbol, - trait_name: String + trait_name: String, }, #[label(typeck::label_type_not_found)] CommentNotFound { #[primary_span] span: Span, assoc_name: Ident, - } + }, } - #[derive(SessionDiagnostic)] #[error(typeck::associated_items_not_defined_in_trait, code = "E0220")] pub struct AssociatedTypeNotDefinedInTrait<'a> { @@ -426,7 +452,7 @@ pub struct AssociatedTypeNotDefinedInTrait<'a> { pub assoc_name: Ident, pub ty_param_name: &'a str, #[subdiagnostic] - pub comment: AssociatedTypeNotDefinedInTraitComment + pub comment: AssociatedTypeNotDefinedInTraitComment, } #[derive(SessionDiagnostic)] @@ -472,7 +498,7 @@ impl<'a, 'b> SessionDiagnostic<'a> for AttributeOnNonForeignFunction<'b> { } #[derive(SessionDiagnostic)] -#[error(typeck::ffi_const_and_ffi_pure_on_same_function, code = "E0724")] +#[error(typeck::ffi_const_and_ffi_pure_on_same_function, code = "E0757")] pub struct FFIConstAndFFIPureOnSameFunction { #[primary_span] pub span: Span, @@ -517,6 +543,7 @@ pub struct InstructionSetUnsupportedOnTarget { #[error(typeck::varargs_on_non_cabi_function, code = "E0045")] pub struct VarargsOnNonCabiFunction { #[primary_span] + #[label] pub span: Span, } @@ -526,7 +553,7 @@ pub struct GenericParamsOnMainFunction { #[primary_span] pub span: Span, #[label] - pub generics_param_span: Option + pub generics_param_span: Option, } #[derive(SessionDiagnostic)] @@ -535,7 +562,7 @@ pub struct WhenClauseOnMainFunction { #[primary_span] pub span: Span, #[label] - pub generics_where_clauses_span: Option + pub generics_where_clauses_span: Option, } #[derive(SessionDiagnostic)] @@ -544,7 +571,7 @@ pub struct AsyncMainFunction { #[primary_span] pub span: Span, #[label] - pub asyncness_span: Option + pub asyncness_span: Option, } #[derive(SessionDiagnostic)] @@ -558,6 +585,7 @@ pub struct GenericReturnTypeOnMain { #[error(typeck::type_parameter_on_start_function, code = "E0132")] pub struct TypeParameterOnStartFunction { #[primary_span] + #[label] pub span: Span, } @@ -567,7 +595,7 @@ pub struct WhereClauseOnStartFunction { #[primary_span] pub span: Span, #[label] - pub where_clause_span: Span + pub where_clause_span: Span, } #[derive(SessionDiagnostic)] @@ -581,18 +609,18 @@ pub struct AsyncStartFunction { #[derive(SessionSubdiagnostic)] pub enum AmbiguousAssociatedTypeFixSuggestion<'a> { #[suggestion( - typeck::fix_std_module_text, - code = "std::", - applicability = "machine-applicable" + typeck::fix_std_module_text, + code = "std::", + applicability = "machine-applicable" )] StdModule { #[primary_span] span: Span, }, #[suggestion( - typeck::fix_use_fully_qualified_syntax, - code = "<{type_str} as {trait_str}>::{name}", - applicability = "has-placeholders" + typeck::fix_use_fully_qualified_syntax, + code = "<{type_str} as {trait_str}>::{name}", + applicability = "has-placeholders" )] UseFullyQualifiedSyntax { #[primary_span] @@ -609,27 +637,26 @@ pub struct AmbiguousAssociatedType<'a> { #[primary_span] pub span: Span, #[subdiagnostic] - pub possible_fix: AmbiguousAssociatedTypeFixSuggestion<'a> + pub possible_fix: AmbiguousAssociatedTypeFixSuggestion<'a>, } - #[derive(SessionSubdiagnostic)] pub enum EnumVariantNotFoundFixOrInfo<'a> { #[suggestion( - typeck::fix_similar_type, - code = "{suggested_name}", - applicability = "maybe-incorrect" + typeck::fix_similar_type, + code = "{suggested_name}", + applicability = "maybe-incorrect" )] SuggestSimilarName { #[primary_span] span: Span, - suggested_name: Symbol + suggested_name: Symbol, }, #[label(typeck::info_label)] InfoLabel { #[primary_span] span: Span, - self_type: &'a str + self_type: &'a str, }, } @@ -643,5 +670,5 @@ pub struct EnumVariantNotFound<'a> { #[subdiagnostic] pub fix_or_info: EnumVariantNotFoundFixOrInfo<'a>, pub assoc_ident: Ident, - pub self_type: &'a str + pub self_type: &'a str, } diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs index 3b709949daebf..523a9bfbdbbcc 100644 --- a/compiler/rustc_typeck/src/impl_wf_check.rs +++ b/compiler/rustc_typeck/src/impl_wf_check.rs @@ -18,8 +18,8 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; use rustc_span::{Span, Symbol}; +use crate::errors::{AssociatedItemsNotDistinct, TypeParameterNotConstrainedForImpl, UnconstrainedParameterType}; use std::collections::hash_map::Entry::{Occupied, Vacant}; -use crate::errors::{AssociatedItemsNotDistinct, TypeParameterNotConstrainedForImpl}; mod min_specialization; @@ -123,7 +123,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) ty::GenericParamDefKind::Type { .. } => { let param_ty = ty::ParamTy::for_def(param); if !input_parameters.contains(&cgp::Parameter::from(param_ty)) { - report_unused_parameter(tcx, tcx.def_span(param.def_id), "type", param_ty.name); + report_unused_parameter(tcx, tcx.def_span(param.def_id), UnconstrainedParameterType::Type, param_ty.name); } } ty::GenericParamDefKind::Lifetime => { @@ -134,7 +134,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) report_unused_parameter( tcx, tcx.def_span(param.def_id), - "lifetime", + UnconstrainedParameterType::Lifetime, param.name, ); } @@ -145,7 +145,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) report_unused_parameter( tcx, tcx.def_span(param.def_id), - "const", + UnconstrainedParameterType::Const, param_ct.name, ); } @@ -173,15 +173,11 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) // used elsewhere are not projected back out. } -fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol) { - let note = if kind == "const" { Some(()) } else { None }; - +fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: UnconstrainedParameterType, name: Symbol) { tcx.sess.emit_err(TypeParameterNotConstrainedForImpl { span, - kind_name: kind, - name: name.to_string(), - first_note: note, - second_note: note + kind, + name, }); } @@ -202,7 +198,7 @@ fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { tcx.sess.emit_err(AssociatedItemsNotDistinct { span, ident: ident.to_string(), - prev_definition_span: *entry.get() + prev_definition_span: *entry.get(), }); } Vacant(entry) => { diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index aa57a0eeab84e..3a1dfed1ef5c9 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -98,7 +98,7 @@ mod outlives; mod structured_errors; mod variance; -use rustc_errors::{ErrorGuaranteed}; +use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{Node, CRATE_HIR_ID}; @@ -115,9 +115,13 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use std::iter; +use crate::errors::{ + AsyncMainFunction, AsyncStartFunction, GenericParamsOnMainFunction, GenericReturnTypeOnMain, + TypeParameterOnStartFunction, VarargsOnNonCabiFunction, WhenClauseOnMainFunction, + WhereClauseOnStartFunction, +}; use astconv::AstConv; use bounds::Bounds; -use crate::errors::{AsyncMainFunction, AsyncStartFunction, GenericParamsOnMainFunction, GenericReturnTypeOnMain, TypeParameterOnStartFunction, VarargsOnNonCabiFunction, WhenClauseOnMainFunction, WhereClauseOnStartFunction}; fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) { match (decl.c_variadic, abi) { @@ -236,14 +240,20 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() { let generics_param_span = main_fn_generics_params_span(tcx, main_def_id); - tcx.sess.emit_err(GenericParamsOnMainFunction { span: generics_param_span.unwrap_or(main_span), generics_param_span }); + tcx.sess.emit_err(GenericParamsOnMainFunction { + span: generics_param_span.unwrap_or(main_span), + generics_param_span, + }); error = true; } else if !main_fn_predicates.predicates.is_empty() { // generics may bring in implicit predicates, so we skip this check if generics is present. let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id); - tcx.sess.emit_err(WhenClauseOnMainFunction { span: generics_where_clauses_span.unwrap_or(main_span), generics_where_clauses_span }); + tcx.sess.emit_err(WhenClauseOnMainFunction { + span: generics_where_clauses_span.unwrap_or(main_span), + generics_where_clauses_span, + }); error = true; } @@ -338,7 +348,10 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { error = true; } if generics.has_where_clause_predicates { - tcx.sess.emit_err(WhereClauseOnStartFunction { span: generics.where_clause_span, where_clause_span: generics.where_clause_span }); + tcx.sess.emit_err(WhereClauseOnStartFunction { + span: generics.where_clause_span, + where_clause_span: generics.where_clause_span, + }); error = true; } From f9fb2712f7e43c89f173de7611f6875fc0f1b7e5 Mon Sep 17 00:00:00 2001 From: yaraksan Date: Sun, 21 Aug 2022 23:06:58 +0200 Subject: [PATCH 5/6] Removed merge misstakes --- .../locales/en-US/typeck.ftl | 1 - compiler/rustc_typeck/src/errors.rs | 50 +++++++++---------- compiler/rustc_typeck/src/impl_wf_check.rs | 24 ++++++--- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/typeck.ftl index 31de2b3ada24d..9745569870d0e 100644 --- a/compiler/rustc_error_messages/locales/en-US/typeck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/typeck.ftl @@ -132,7 +132,6 @@ typeck_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition .suggestion = convert it to a `{$msg_code}` -<<<<<<< HEAD typeck_safe_trait_implemented_as_unsafe = implementing the trait `{$trait_name}` is not unsafe diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index fa7888b14ef74..127b0ad6e0af1 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -342,8 +342,7 @@ pub struct ExternCrateNotIdiomatic { } #[derive(SessionDiagnostic)] -<<<<<<< HEAD -#[error(typeck::safe_trait_implemented_as_unsafe, code = "E0199")] +#[diag(typeck::safe_trait_implemented_as_unsafe, code = "E0199")] pub struct SafeTraitImplementedAsUnsafe { #[primary_span] pub span: Span, @@ -351,7 +350,7 @@ pub struct SafeTraitImplementedAsUnsafe { } #[derive(SessionDiagnostic)] -#[error(typeck::unsafe_trait_implemented_without_unsafe_keyword, code = "E0200")] +#[diag(typeck::unsafe_trait_implemented_without_unsafe_keyword, code = "E0200")] pub struct UnsafeTraitImplementedWithoutUnsafeKeyword { #[primary_span] pub span: Span, @@ -359,7 +358,7 @@ pub struct UnsafeTraitImplementedWithoutUnsafeKeyword { } #[derive(SessionDiagnostic)] -#[error(typeck::attribute_requires_unsafe_keyword, code = "E0569")] +#[diag(typeck::attribute_requires_unsafe_keyword, code = "E0569")] pub struct AttributeRequiresUnsafeKeyword<'a> { #[primary_span] pub span: Span, @@ -370,7 +369,7 @@ pub struct AttributeRequiresUnsafeKeyword<'a> { pub enum UnconstrainedParameterType { Type, Lifetime, - Const + Const, } pub struct TypeParameterNotConstrainedForImpl { @@ -408,7 +407,7 @@ impl<'a> SessionDiagnostic<'a> for TypeParameterNotConstrainedForImpl { } #[derive(SessionDiagnostic)] -#[error(typeck::associated_items_not_distinct, code = "E0201")] +#[diag(typeck::associated_items_not_distinct, code = "E0201")] pub struct AssociatedItemsNotDistinct { #[primary_span] #[label] @@ -446,7 +445,7 @@ pub enum AssociatedTypeNotDefinedInTraitComment { } #[derive(SessionDiagnostic)] -#[error(typeck::associated_items_not_defined_in_trait, code = "E0220")] +#[diag(typeck::associated_items_not_defined_in_trait, code = "E0220")] pub struct AssociatedTypeNotDefinedInTrait<'a> { #[primary_span] pub span: Span, @@ -457,7 +456,7 @@ pub struct AssociatedTypeNotDefinedInTrait<'a> { } #[derive(SessionDiagnostic)] -#[error(typeck::enum_discriminant_overflow, code = "E0370")] +#[diag(typeck::enum_discriminant_overflow, code = "E0370")] pub struct EnumDiscriminantOverflow { #[primary_span] #[label] @@ -470,7 +469,7 @@ pub struct EnumDiscriminantOverflow { } #[derive(SessionDiagnostic)] -#[error(typeck::rustc_paren_sugar_not_enabled)] +#[diag(typeck::rustc_paren_sugar_not_enabled)] pub struct RustcParenSugarNotEnabled { #[primary_span] pub span: Span, @@ -499,49 +498,49 @@ impl<'a, 'b> SessionDiagnostic<'a> for AttributeOnNonForeignFunction<'b> { } #[derive(SessionDiagnostic)] -#[error(typeck::ffi_const_and_ffi_pure_on_same_function, code = "E0757")] +#[diag(typeck::ffi_const_and_ffi_pure_on_same_function, code = "E0757")] pub struct FFIConstAndFFIPureOnSameFunction { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(typeck::cmse_nonsecure_entry_requires_c_abi, code = "E0776")] +#[diag(typeck::cmse_nonsecure_entry_requires_c_abi, code = "E0776")] pub struct CMSENonSecureEntryRequiresCAbi { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(typeck::cmse_nonsecure_entry_requires_trust_zone_m_ext, code = "E0775")] +#[diag(typeck::cmse_nonsecure_entry_requires_trust_zone_m_ext, code = "E0775")] pub struct CMSENonSecureEntryRequiresTrustZoneMExt { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(typeck::track_caller_requires_cabi, code = "E0737")] +#[diag(typeck::track_caller_requires_cabi, code = "E0737")] pub struct TrackCallerRequiresCAbi { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(typeck::export_name_contains_null_characters, code = "E0648")] +#[diag(typeck::export_name_contains_null_characters, code = "E0648")] pub struct ExportNameContainsNullCharacters { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(typeck::instruction_set_unsupported_on_target, code = "E0779")] +#[diag(typeck::instruction_set_unsupported_on_target, code = "E0779")] pub struct InstructionSetUnsupportedOnTarget { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(typeck::varargs_on_non_cabi_function, code = "E0045")] +#[diag(typeck::varargs_on_non_cabi_function, code = "E0045")] pub struct VarargsOnNonCabiFunction { #[primary_span] #[label] @@ -549,7 +548,7 @@ pub struct VarargsOnNonCabiFunction { } #[derive(SessionDiagnostic)] -#[error(typeck::generic_params_on_main_function, code = "E0131")] +#[diag(typeck::generic_params_on_main_function, code = "E0131")] pub struct GenericParamsOnMainFunction { #[primary_span] pub span: Span, @@ -558,7 +557,7 @@ pub struct GenericParamsOnMainFunction { } #[derive(SessionDiagnostic)] -#[error(typeck::when_clause_on_main_function, code = "E0646")] +#[diag(typeck::when_clause_on_main_function, code = "E0646")] pub struct WhenClauseOnMainFunction { #[primary_span] pub span: Span, @@ -567,7 +566,7 @@ pub struct WhenClauseOnMainFunction { } #[derive(SessionDiagnostic)] -#[error(typeck::async_main_function, code = "E0752")] +#[diag(typeck::async_main_function, code = "E0752")] pub struct AsyncMainFunction { #[primary_span] pub span: Span, @@ -576,14 +575,14 @@ pub struct AsyncMainFunction { } #[derive(SessionDiagnostic)] -#[error(typeck::generic_return_type_on_main, code = "E0131")] +#[diag(typeck::generic_return_type_on_main, code = "E0131")] pub struct GenericReturnTypeOnMain { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(typeck::type_parameter_on_start_function, code = "E0132")] +#[diag(typeck::type_parameter_on_start_function, code = "E0132")] pub struct TypeParameterOnStartFunction { #[primary_span] #[label] @@ -591,7 +590,7 @@ pub struct TypeParameterOnStartFunction { } #[derive(SessionDiagnostic)] -#[error(typeck::where_clause_on_start_function, code = "E0647")] +#[diag(typeck::where_clause_on_start_function, code = "E0647")] pub struct WhereClauseOnStartFunction { #[primary_span] pub span: Span, @@ -600,7 +599,7 @@ pub struct WhereClauseOnStartFunction { } #[derive(SessionDiagnostic)] -#[error(typeck::async_start_function, code = "E0752")] +#[diag(typeck::async_start_function, code = "E0752")] pub struct AsyncStartFunction { #[primary_span] #[label] @@ -633,7 +632,7 @@ pub enum AmbiguousAssociatedTypeFixSuggestion<'a> { } #[derive(SessionDiagnostic)] -#[error(typeck::ambiguous_associated_type, code = "E0223")] +#[diag(typeck::ambiguous_associated_type, code = "E0223")] pub struct AmbiguousAssociatedType<'a> { #[primary_span] pub span: Span, @@ -662,7 +661,7 @@ pub enum EnumVariantNotFoundFixOrInfo<'a> { } #[derive(SessionDiagnostic)] -#[error(typeck::enum_variant_not_found, code = "E0599")] +#[diag(typeck::enum_variant_not_found, code = "E0599")] pub struct EnumVariantNotFound<'a> { #[primary_span] pub span: Span, @@ -674,6 +673,7 @@ pub struct EnumVariantNotFound<'a> { pub self_type: &'a str, } +#[derive(SessionDiagnostic)] #[diag(typeck::expected_used_symbol)] pub struct ExpectedUsedSymbol { #[primary_span] diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs index 523a9bfbdbbcc..11dac6e62cb01 100644 --- a/compiler/rustc_typeck/src/impl_wf_check.rs +++ b/compiler/rustc_typeck/src/impl_wf_check.rs @@ -18,7 +18,9 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; use rustc_span::{Span, Symbol}; -use crate::errors::{AssociatedItemsNotDistinct, TypeParameterNotConstrainedForImpl, UnconstrainedParameterType}; +use crate::errors::{ + AssociatedItemsNotDistinct, TypeParameterNotConstrainedForImpl, UnconstrainedParameterType, +}; use std::collections::hash_map::Entry::{Occupied, Vacant}; mod min_specialization; @@ -123,7 +125,12 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) ty::GenericParamDefKind::Type { .. } => { let param_ty = ty::ParamTy::for_def(param); if !input_parameters.contains(&cgp::Parameter::from(param_ty)) { - report_unused_parameter(tcx, tcx.def_span(param.def_id), UnconstrainedParameterType::Type, param_ty.name); + report_unused_parameter( + tcx, + tcx.def_span(param.def_id), + UnconstrainedParameterType::Type, + param_ty.name, + ); } } ty::GenericParamDefKind::Lifetime => { @@ -173,12 +180,13 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) // used elsewhere are not projected back out. } -fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: UnconstrainedParameterType, name: Symbol) { - tcx.sess.emit_err(TypeParameterNotConstrainedForImpl { - span, - kind, - name, - }); +fn report_unused_parameter( + tcx: TyCtxt<'_>, + span: Span, + kind: UnconstrainedParameterType, + name: Symbol, +) { + tcx.sess.emit_err(TypeParameterNotConstrainedForImpl { span, kind, name }); } /// Enforce that we do not have two items in an impl with the same name. From b0cf801e116452d9d9912ccd7eecd98917a72951 Mon Sep 17 00:00:00 2001 From: yaraksan Date: Tue, 23 Aug 2022 20:23:59 +0200 Subject: [PATCH 6/6] Finished easy struct_span_err-macro ports --- .../locales/en-US/typeck.ftl | 57 ++++++ .../rustc_typeck/src/coherence/builtin.rs | 177 +++++++----------- compiler/rustc_typeck/src/coherence/mod.rs | 86 +++------ compiler/rustc_typeck/src/coherence/orphan.rs | 33 ++-- compiler/rustc_typeck/src/errors.rs | 159 ++++++++++++++++ src/test/ui/error-codes/E0375.stderr | 2 +- .../ui/invalid_dispatch_from_dyn_impls.stderr | 2 +- src/test/ui/issues/issue-26905.stderr | 2 +- 8 files changed, 329 insertions(+), 189 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/typeck.ftl index 9745569870d0e..e29e82e3d306a 100644 --- a/compiler/rustc_error_messages/locales/en-US/typeck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/typeck.ftl @@ -241,3 +241,60 @@ typeck_enum_variant_not_found = .info_label_at_enum = variant `{$assoc_ident}` not found here typeck_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)` + +typeck_invalid_dispatch_from_dyn_types_differ_too_much = + the trait `DispatchFromDyn` may only be implemented for a coercion between structures with the same definition; expected `{$source_path}`, found `{$target_path}` + +typeck_invalid_dispatch_from_dyn_invalid_repr = + structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]` + +typeck_invalid_dispatch_from_dyn_invalid_fields = + the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else + .note = extra field `{$field_name}` of type `{$ty_a}` is not allowed + +typeck_invalid_dispatch_from_dyn_no_coerced_fields = + the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced, none found + +typeck_invalid_dispatch_from_dyn_too_many_coerced_fields = + implementing the `DispatchFromDyn` trait requires multiple coercions + .note = the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced + .fields_that_need_coercions_fields = currently, {$coerced_fields_len} fields need coercions: {$coerced_fields} + +typeck_invalid_dispatch_from_dyn_not_a_struct = + the trait `DispatchFromDyn` may only be implemented for a coercion between structures + +typeck_coerce_unsized_invalid_definition = + the trait `CoerceUnsized` may only be implemented for a coercion between structures with the same definition; expected `{$source_path}`, found `{$target_path} + +typeck_coerce_unsized_no_coerced_field = + implementing the trait `CoerceUnsized` requires multiple coercions + .note = `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced + .fields_that_need_coercions_fields = currently, {$coerced_fields_len} fields need coercions: {$coerced_fields} + .label = requires multiple coercions + +typeck_coerce_unsized_not_a_struct = + the trait `CoerceUnsized` may only be implemented for a coercion between structures + +typeck_cannot_implement_primitives = + cannot define inherent `impl` for a type outside of the crate where the type is defined + +typeck_explicit_impl_of_internal_structs = + explicit impls for the `{$trait_name}` trait are not permitted + .label = impl of `{$trait_name}` not allowed + +typeck_marker_trait_impl_contains_items = + impls for marker traits cannot contain items + +typeck_type_automatically_implements_trait = + the object type `{$object_type}` automatically implements the trait `{$trait_path}` + .label = `{$object_type}` automatically implements trait `{$trait_path}` + +typeck_cross_crate_opt_out_trait_impl_on_invalid_target = + { $error_type -> + [cross_crate] cross-crate traits with a default impl, like `{$trait_path}`, can only be implemented for a struct/enum type defined in the current crate + *[invalid_type] cross-crate traits with a default impl, like `{$trait_path}`, can only be implemented for a struct/enum type, not `{$self_type}` + } + .label = { $error_type -> + [cross_crate] can't implement cross-crate trait for type in another crate + *[invalid_type] can't implement cross-crate trait with a default impl for non-struct/enum type + } \ No newline at end of file diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index 2467a81638f75..ab5a450de5f3b 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -1,7 +1,11 @@ //! Check properties that are required by built-in traits and set //! up data structures required by type-checking/codegen. -use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem}; +use crate::errors::{ + CoerceUnsizedInvalidDefinition, CoerceUnsizedNoCoercedField, CoerceUnsizedNotAStruct, + CoerceUnsizedTooManyCoercedFields, CopyImplOnNonAdt, CopyImplOnTypeWithDtor, + DropImplOnWrongItem, InvalidDispatchFromDynDeclaration, InvalidDispatchFromDynDeclarationType, +}; use rustc_errors::{struct_span_err, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -209,7 +213,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: let param_env = tcx.param_env(impl_did); - let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg); + // let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg); tcx.infer_ctxt().enter(|infcx| { let cause = ObligationCause::misc(span, impl_hir_id); @@ -226,23 +230,22 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: let source_path = tcx.def_path_str(def_a.did()); let target_path = tcx.def_path_str(def_b.did()); - create_err(&format!( - "the trait `DispatchFromDyn` may only be implemented \ - for a coercion between structures with the same \ - definition; expected `{}`, found `{}`", - source_path, target_path, - )) - .emit(); + tcx.sess.emit_err(InvalidDispatchFromDynDeclaration { + span, + err_type: InvalidDispatchFromDynDeclarationType::TypesDifferTooMuch { + source_path, + target_path, + }, + }); return; } if def_a.repr().c() || def_a.repr().packed() { - create_err( - "structs implementing `DispatchFromDyn` may not have \ - `#[repr(packed)]` or `#[repr(C)]`", - ) - .emit(); + tcx.sess.emit_err(InvalidDispatchFromDynDeclaration { + span, + err_type: InvalidDispatchFromDynDeclarationType::InvalidRepr, + }); } let fields = &def_a.non_enum_variant().fields; @@ -262,16 +265,14 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) { if ok.obligations.is_empty() { - create_err( - "the trait `DispatchFromDyn` may only be implemented \ - for structs containing the field being coerced, \ - ZST fields with 1 byte alignment, and nothing else", - ) - .note(&format!( - "extra field `{}` of type `{}` is not allowed", - field.name, ty_a, - )) - .emit(); + tcx.sess.emit_err(InvalidDispatchFromDynDeclaration { + span, + err_type: + InvalidDispatchFromDynDeclarationType::InvalidFields { + field_name: field.name, + ty_a: ty_a.to_string(), + }, + }); return false; } @@ -282,38 +283,29 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: .collect::>(); if coerced_fields.is_empty() { - create_err( - "the trait `DispatchFromDyn` may only be implemented \ - for a coercion between structures with a single field \ - being coerced, none found", - ) - .emit(); + tcx.sess.emit_err(InvalidDispatchFromDynDeclaration { + span, + err_type: InvalidDispatchFromDynDeclarationType::NoCoercedFields, + }); } else if coerced_fields.len() > 1 { - create_err( - "implementing the `DispatchFromDyn` trait requires multiple coercions", - ) - .note( - "the trait `DispatchFromDyn` may only be implemented \ - for a coercion between structures with a single field \ - being coerced", - ) - .note(&format!( - "currently, {} fields need coercions: {}", - coerced_fields.len(), - coerced_fields - .iter() - .map(|field| { - format!( - "`{}` (`{}` to `{}`)", - field.name, - field.ty(tcx, substs_a), - field.ty(tcx, substs_b), - ) - }) - .collect::>() - .join(", ") - )) - .emit(); + tcx.sess.emit_err(InvalidDispatchFromDynDeclaration { + span, + err_type: InvalidDispatchFromDynDeclarationType::TooManyCoercedFields { + coerced_fields_len: coerced_fields.len(), + coerced_fields: coerced_fields + .iter() + .map(|field| { + format!( + "`{}` (`{}` -> `{}`)", + field.name, + field.ty(tcx, substs_a), + field.ty(tcx, substs_b), + ) + }) + .collect::>() + .join(", "), + }, + }); } else { let errors = traits::fully_solve_obligations( &infcx, @@ -339,11 +331,10 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: } } _ => { - create_err( - "the trait `DispatchFromDyn` may only be implemented \ - for a coercion between structures", - ) - .emit(); + tcx.sess.emit_err(InvalidDispatchFromDynDeclaration { + span, + err_type: InvalidDispatchFromDynDeclarationType::NotAStruct, + }); } } }) @@ -416,17 +407,13 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn if def_a != def_b { let source_path = tcx.def_path_str(def_a.did()); let target_path = tcx.def_path_str(def_b.did()); - struct_span_err!( - tcx.sess, + + tcx.sess.emit_err(CoerceUnsizedInvalidDefinition { span, - E0377, - "the trait `CoerceUnsized` may only be implemented \ - for a coercion between structures with the same \ - definition; expected `{}`, found `{}`", source_path, - target_path - ) - .emit(); + target_path, + }); + return err_info; } @@ -503,15 +490,8 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn .collect::>(); if diff_fields.is_empty() { - struct_span_err!( - tcx.sess, - span, - E0374, - "the trait `CoerceUnsized` may only be implemented \ - for a coercion between structures with one field \ - being coerced, none found" - ) - .emit(); + tcx.sess.emit_err(CoerceUnsizedNoCoercedField { span }); + return err_info; } else if diff_fields.len() > 1 { let item = tcx.hir().expect_item(impl_did); @@ -523,31 +503,18 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn tcx.def_span(impl_did) }; - struct_span_err!( - tcx.sess, + tcx.sess.emit_err(CoerceUnsizedTooManyCoercedFields { span, - E0375, - "implementing the trait \ - `CoerceUnsized` requires multiple \ - coercions" - ) - .note( - "`CoerceUnsized` may only be implemented for \ - a coercion between structures with one field being coerced", - ) - .note(&format!( - "currently, {} fields need coercions: {}", - diff_fields.len(), - diff_fields + _note: (), + _fields_note: (), + coerced_fields_len: diff_fields.len(), + coerced_fields: diff_fields .iter() - .map(|&(i, a, b)| { - format!("`{}` (`{}` to `{}`)", fields[i].name, a, b) - }) + .map(|&(i, a, b)| format!("`{}` (`{}` -> `{}`)", fields[i].name, a, b)) .collect::>() - .join(", ") - )) - .span_label(span, "requires multiple coercions") - .emit(); + .join(", "), + }); + return err_info; } @@ -557,14 +524,8 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn } _ => { - struct_span_err!( - tcx.sess, - span, - E0376, - "the trait `CoerceUnsized` may only be implemented \ - for a coercion between structures" - ) - .emit(); + tcx.sess.emit_err(CoerceUnsizedNotAStruct { span }); + return err_info; } }; diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs index ae9ebe5909144..2df938ca70cd9 100644 --- a/compiler/rustc_typeck/src/coherence/mod.rs +++ b/compiler/rustc_typeck/src/coherence/mod.rs @@ -5,7 +5,10 @@ // done by the orphan and overlap modules. Then we build up various // mappings. That mapping code resides here. -use rustc_errors::struct_span_err; +use crate::errors::{ + ExplicitImplOfInternalStructs, MarkerTraitImplContainsItems, TypeAutomaticallyImplementsTrait, +}; +use rustc_errors::error_code; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; @@ -45,50 +48,38 @@ fn enforce_trait_manually_implementable( // Disallow *all* explicit impls of `Pointee`, `DiscriminantKind`, `Sized` and `Unsize` for now. if did == li.pointee_trait() { - struct_span_err!( - tcx.sess, - impl_header_span, - E0322, - "explicit impls for the `Pointee` trait are not permitted" - ) - .span_label(impl_header_span, "impl of `Pointee` not allowed") - .emit(); + tcx.sess.emit_err(ExplicitImplOfInternalStructs { + span: impl_header_span, + error_code: error_code!(E0322), + trait_name: "Pointee", + }); return; } if did == li.discriminant_kind_trait() { - struct_span_err!( - tcx.sess, - impl_header_span, - E0322, - "explicit impls for the `DiscriminantKind` trait are not permitted" - ) - .span_label(impl_header_span, "impl of `DiscriminantKind` not allowed") - .emit(); + tcx.sess.emit_err(ExplicitImplOfInternalStructs { + span: impl_header_span, + error_code: error_code!(E0322), + trait_name: "DiscriminantKind", + }); return; } if did == li.sized_trait() { - struct_span_err!( - tcx.sess, - impl_header_span, - E0322, - "explicit impls for the `Sized` trait are not permitted" - ) - .span_label(impl_header_span, "impl of `Sized` not allowed") - .emit(); + tcx.sess.emit_err(ExplicitImplOfInternalStructs { + span: impl_header_span, + error_code: error_code!(E0322), + trait_name: "Sized", + }); return; } if did == li.unsize_trait() { - struct_span_err!( - tcx.sess, - impl_header_span, - E0328, - "explicit impls for the `Unsize` trait are not permitted" - ) - .span_label(impl_header_span, "impl of `Unsize` not allowed") - .emit(); + tcx.sess.emit_err(ExplicitImplOfInternalStructs { + span: impl_header_span, + error_code: error_code!(E0328), + trait_name: "Unsize", + }); return; } @@ -128,13 +119,7 @@ fn enforce_empty_impls_for_marker_traits( return; } - struct_span_err!( - tcx.sess, - tcx.def_span(impl_def_id), - E0715, - "impls for marker traits cannot contain items" - ) - .emit(); + tcx.sess.emit_err(MarkerTraitImplContainsItems { span: tcx.def_span(impl_def_id) }); } pub fn provide(providers: &mut Providers) { @@ -213,23 +198,12 @@ fn check_object_overlap<'tcx>( let mut supertrait_def_ids = traits::supertrait_def_ids(tcx, component_def_id); if supertrait_def_ids.any(|d| d == trait_def_id) { let span = tcx.def_span(impl_def_id); - struct_span_err!( - tcx.sess, - span, - E0371, - "the object type `{}` automatically implements the trait `{}`", - trait_ref.self_ty(), - tcx.def_path_str(trait_def_id) - ) - .span_label( + + tcx.sess.emit_err(TypeAutomaticallyImplementsTrait { span, - format!( - "`{}` automatically implements trait `{}`", - trait_ref.self_ty(), - tcx.def_path_str(trait_def_id) - ), - ) - .emit(); + object_type: trait_ref.self_ty().to_string(), + trait_path: tcx.def_path_str(trait_def_id), + }); } } } diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index 1608550aa6ae4..936a52ed95c76 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -1,6 +1,7 @@ //! Orphan checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. +use crate::errors::CrossCrateOptOutTraitImplOnInvalidTarget; use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_errors::{Diagnostic, ErrorGuaranteed}; @@ -172,32 +173,20 @@ fn do_orphan_check_impl<'tcx>( if self_def_id.is_local() { None } else { - Some(( - format!( - "cross-crate traits with a default impl, like `{}`, \ - can only be implemented for a struct/enum type \ - defined in the current crate", - tcx.def_path_str(trait_def_id) - ), - "can't implement cross-crate trait for type in another crate", - )) + Some((tcx.def_path_str(trait_def_id), "".to_string(), "cross_crate")) } } - _ => Some(( - format!( - "cross-crate traits with a default impl, like `{}`, can \ - only be implemented for a struct/enum type, not `{}`", - tcx.def_path_str(trait_def_id), - self_ty - ), - "can't implement cross-crate trait with a default impl for \ - non-struct/enum type", - )), + _ => Some((tcx.def_path_str(trait_def_id), self_ty.to_string(), "invalid_type")), }; - if let Some((msg, label)) = msg { - let reported = - struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit(); + if let Some((trait_path, self_type, error_type)) = msg { + let reported = tcx.sess.emit_err(CrossCrateOptOutTraitImplOnInvalidTarget { + span: sp, + trait_path, + error_type, + self_type, + }); + return Err(reported); } } diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 127b0ad6e0af1..d46dcbf6b71d9 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -679,3 +679,162 @@ pub struct ExpectedUsedSymbol { #[primary_span] pub span: Span, } + +pub enum InvalidDispatchFromDynDeclarationType { + TypesDifferTooMuch { source_path: String, target_path: String }, + InvalidRepr, + InvalidFields { field_name: Symbol, ty_a: String }, + NoCoercedFields, + TooManyCoercedFields { coerced_fields_len: usize, coerced_fields: String }, + NotAStruct, +} + +pub struct InvalidDispatchFromDynDeclaration { + pub(crate) span: Span, + pub(crate) err_type: InvalidDispatchFromDynDeclarationType, +} + +// Manual implementation of `SessionDiagnostic` to be able to call `span_to_snippet`. +impl<'a> SessionDiagnostic<'a> for InvalidDispatchFromDynDeclaration { + fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let msg = match &self.err_type { + InvalidDispatchFromDynDeclarationType::TypesDifferTooMuch { .. } => { + rustc_errors::fluent::typeck::invalid_dispatch_from_dyn_types_differ_too_much + } + InvalidDispatchFromDynDeclarationType::InvalidRepr => { + rustc_errors::fluent::typeck::invalid_dispatch_from_dyn_invalid_repr + } + InvalidDispatchFromDynDeclarationType::InvalidFields { .. } => { + rustc_errors::fluent::typeck::invalid_dispatch_from_dyn_invalid_fields + } + InvalidDispatchFromDynDeclarationType::NoCoercedFields => { + rustc_errors::fluent::typeck::invalid_dispatch_from_dyn_no_coerced_fields + } + InvalidDispatchFromDynDeclarationType::TooManyCoercedFields { .. } => { + rustc_errors::fluent::typeck::invalid_dispatch_from_dyn_too_many_coerced_fields + } + InvalidDispatchFromDynDeclarationType::NotAStruct => { + rustc_errors::fluent::typeck::invalid_dispatch_from_dyn_not_a_struct + } + }; + + let mut err = + sess.span_diagnostic.struct_span_err_with_code(self.span, msg, error_code!(E0378)); + + match self.err_type { + InvalidDispatchFromDynDeclarationType::TypesDifferTooMuch { + source_path, + target_path, + } => { + err.set_arg("source_path", source_path); + err.set_arg("target_path", target_path); + } + InvalidDispatchFromDynDeclarationType::InvalidFields { field_name, ty_a } => { + err.set_arg("field_name", field_name); + err.set_arg("ty_a", ty_a); + + err.note(rustc_errors::fluent::typeck::note); + } + InvalidDispatchFromDynDeclarationType::TooManyCoercedFields { + coerced_fields_len, + coerced_fields, + } => { + err.set_arg("coerced_fields_len", coerced_fields_len); + err.set_arg("coerced_fields", coerced_fields); + + err.note(rustc_errors::fluent::typeck::note); + err.note(rustc_errors::fluent::typeck::fields_that_need_coercions_fields); + } + _ => {} + } + + err + } +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::coerce_unsized_invalid_definition, code = "E0377")] +pub struct CoerceUnsizedInvalidDefinition { + #[primary_span] + pub span: Span, + pub source_path: String, + pub target_path: String, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::coerce_unsized_no_coerced_field, code = "E0374")] +pub struct CoerceUnsizedNoCoercedField { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::coerce_unsized_no_coerced_field, code = "E0375")] +pub struct CoerceUnsizedTooManyCoercedFields { + #[primary_span] + #[label] + pub span: Span, + #[note] + pub _note: (), + #[note(typeck::fields_that_need_coercions_fields)] + pub _fields_note: (), + pub coerced_fields_len: usize, + pub coerced_fields: String, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::coerce_unsized_not_a_struct, code = "E0376")] +pub struct CoerceUnsizedNotAStruct { + #[primary_span] + pub span: Span, +} + +pub struct ExplicitImplOfInternalStructs { + pub span: Span, + pub error_code: DiagnosticId, + pub trait_name: &'static str, +} + +impl<'a> SessionDiagnostic<'a> for ExplicitImplOfInternalStructs { + fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let mut err = sess.span_diagnostic.struct_span_err_with_code( + self.span, + rustc_errors::fluent::typeck::explicit_impl_of_internal_structs, + self.error_code, + ); + + err.set_arg("trait_name", self.trait_name); + + err.span_label(self.span, rustc_errors::fluent::typeck::label); + + err + } +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::marker_trait_impl_contains_items, code = "E0715")] +pub struct MarkerTraitImplContainsItems { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::type_automatically_implements_trait, code = "E0371")] +pub struct TypeAutomaticallyImplementsTrait { + #[primary_span] + #[label] + pub span: Span, + pub object_type: String, + pub trait_path: String, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::cross_crate_opt_out_trait_impl_on_invalid_target, code = "E0321")] +pub struct CrossCrateOptOutTraitImplOnInvalidTarget { + #[primary_span] + #[label] + pub span: Span, + pub trait_path: String, + pub error_type: &'static str, + pub self_type: String, +} diff --git a/src/test/ui/error-codes/E0375.stderr b/src/test/ui/error-codes/E0375.stderr index a68b3af5aaf76..59b16c89a89d0 100644 --- a/src/test/ui/error-codes/E0375.stderr +++ b/src/test/ui/error-codes/E0375.stderr @@ -5,7 +5,7 @@ LL | impl CoerceUnsized> for Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions | = note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced - = note: currently, 2 fields need coercions: `b` (`T` to `U`), `c` (`U` to `T`) + = note: currently, 2 fields need coercions: `b` (`T` -> `U`), `c` (`U` -> `T`) error: aborting due to previous error diff --git a/src/test/ui/invalid_dispatch_from_dyn_impls.stderr b/src/test/ui/invalid_dispatch_from_dyn_impls.stderr index b5b32d2f0bd36..20f676fe15804 100644 --- a/src/test/ui/invalid_dispatch_from_dyn_impls.stderr +++ b/src/test/ui/invalid_dispatch_from_dyn_impls.stderr @@ -13,7 +13,7 @@ LL | impl DispatchFromDyn> for Multipl | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced - = note: currently, 2 fields need coercions: `ptr1` (`*const T` to `*const U`), `ptr2` (`*const T` to `*const U`) + = note: currently, 2 fields need coercions: `ptr1` (`*const T` -> `*const U`), `ptr2` (`*const T` -> `*const U`) error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced, none found --> $DIR/invalid_dispatch_from_dyn_impls.rs:31:1 diff --git a/src/test/ui/issues/issue-26905.stderr b/src/test/ui/issues/issue-26905.stderr index 10dbb73258599..5cf1389ddec23 100644 --- a/src/test/ui/issues/issue-26905.stderr +++ b/src/test/ui/issues/issue-26905.stderr @@ -5,7 +5,7 @@ LL | impl, U: ?Sized> CoerceUnsized> for MyRc{ | ^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions | = note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced - = note: currently, 2 fields need coercions: `_ptr` (`*const T` to `*const U`), `_boo` (`NotPhantomData` to `NotPhantomData`) + = note: currently, 2 fields need coercions: `_ptr` (`*const T` -> `*const U`), `_boo` (`NotPhantomData` -> `NotPhantomData`) error: aborting due to previous error