diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/typeck.ftl index 272731d9914cc..e03f6efb1e2b1 100644 --- a/compiler/rustc_error_messages/locales/en-US/typeck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/typeck.ftl @@ -132,4 +132,169 @@ 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 + +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} 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}`: + .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}` + .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 + .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 + +typeck_ffi_const_and_ffi_pure_on_same_function = + `#[ffi_const]` function cannot be `#[ffi_pure]` + +typeck_cmse_nonsecure_entry_requires_c_abi = + `#[cmse_nonsecure_entry]` requires C ABI + +typeck_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` + .label = `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 + 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 = + the trait `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced, none found + .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 + } diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index ff39bf36129bb..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::{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 +141,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 +168,12 @@ 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 +217,17 @@ 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 5bb02bc246caf..84c450db3771a 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -8,8 +8,10 @@ mod generics; use crate::bounds::Bounds; use crate::collect::HirPlaceholderCollector; use crate::errors::{ - AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits, - TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified, + AmbiguousAssociatedType, AmbiguousAssociatedTypeFixSuggestion, AmbiguousLifetimeBound, + EnumVariantNotFound, EnumVariantNotFoundFixOrInfo, MultipleRelaxedDefaultBounds, + TraitObjectDeclaredWithNoTraits, TypeofReservedKeywordUsed, + ValueOfAssociatedStructAlreadySpecified, }; use crate::middle::resolve_lifetime as rl; use crate::require_c_abi_if_c_variadic; @@ -1591,29 +1593,24 @@ 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, - ); + 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 @@ -1937,17 +1934,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() @@ -1956,24 +1947,24 @@ 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", + EnumVariantNotFoundFixOrInfo::SuggestSimilarName { + span: assoc_ident.span, suggested_name, - Applicability::MaybeIncorrect, - ); + } } 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/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/coherence/unsafety.rs b/compiler/rustc_typeck/src/coherence/unsafety.rs index e45fb5fe41c02..e0510413be497 100644 --- a/compiler/rustc_typeck/src/coherence/unsafety.rs +++ b/compiler/rustc_typeck/src/coherence/unsafety.rs @@ -1,13 +1,17 @@ //! 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::{ + AttributeRequiresUnsafeKeyword, SafeTraitImplementedAsUnsafe, + UnsafeTraitImplementedWithoutUnsafeKeyword, +}; + 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 +23,21 @@ 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/collect.rs b/compiler/rustc_typeck/src/collect.rs index 970b39dc845af..6ede6eafdc64f 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}; +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}; @@ -927,16 +935,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 +1202,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 +2746,38 @@ 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; @@ -2872,25 +2859,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( @@ -2907,13 +2886,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); } @@ -3017,13 +2991,10 @@ 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 2214fc2ced883..d46dcbf6b71d9 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, DiagnosticId, ErrorGuaranteed}; use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::Ty; use rustc_session::{parse::ParseSess, SessionDiagnostic}; @@ -341,9 +341,500 @@ pub struct ExternCrateNotIdiomatic { pub suggestion_code: String, } +#[derive(SessionDiagnostic)] +#[diag(typeck::safe_trait_implemented_as_unsafe, code = "E0199")] +pub struct SafeTraitImplementedAsUnsafe { + #[primary_span] + pub span: Span, + pub trait_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::unsafe_trait_implemented_without_unsafe_keyword, code = "E0200")] +pub struct UnsafeTraitImplementedWithoutUnsafeKeyword { + #[primary_span] + pub span: Span, + pub trait_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::attribute_requires_unsafe_keyword, code = "E0569")] +pub struct AttributeRequiresUnsafeKeyword<'a> { + #[primary_span] + pub span: Span, + pub attr_name: &'a str, +} + +#[derive(Eq, PartialEq)] +pub enum UnconstrainedParameterType { + Type, + Lifetime, + Const, +} + +pub struct TypeParameterNotConstrainedForImpl { + pub span: Span, + 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)] +#[diag(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)] +#[diag(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)] +#[diag(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)] +#[diag(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)] +#[diag(typeck::ffi_const_and_ffi_pure_on_same_function, code = "E0757")] +pub struct FFIConstAndFFIPureOnSameFunction { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::cmse_nonsecure_entry_requires_c_abi, code = "E0776")] +pub struct CMSENonSecureEntryRequiresCAbi { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::cmse_nonsecure_entry_requires_trust_zone_m_ext, code = "E0775")] +pub struct CMSENonSecureEntryRequiresTrustZoneMExt { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::track_caller_requires_cabi, code = "E0737")] +pub struct TrackCallerRequiresCAbi { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::export_name_contains_null_characters, code = "E0648")] +pub struct ExportNameContainsNullCharacters { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::instruction_set_unsupported_on_target, code = "E0779")] +pub struct InstructionSetUnsupportedOnTarget { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::varargs_on_non_cabi_function, code = "E0045")] +pub struct VarargsOnNonCabiFunction { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::generic_params_on_main_function, code = "E0131")] +pub struct GenericParamsOnMainFunction { + #[primary_span] + pub span: Span, + #[label] + pub generics_param_span: Option, +} + +#[derive(SessionDiagnostic)] +#[diag(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)] +#[diag(typeck::async_main_function, code = "E0752")] +pub struct AsyncMainFunction { + #[primary_span] + pub span: Span, + #[label] + pub asyncness_span: Option, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::generic_return_type_on_main, code = "E0131")] +pub struct GenericReturnTypeOnMain { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::type_parameter_on_start_function, code = "E0132")] +pub struct TypeParameterOnStartFunction { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(typeck::where_clause_on_start_function, code = "E0647")] +pub struct WhereClauseOnStartFunction { + #[primary_span] + pub span: Span, + #[label] + pub where_clause_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(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)] +#[diag(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)] +#[diag(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, +} + #[derive(SessionDiagnostic)] #[diag(typeck::expected_used_symbol)] 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/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs index 9fee1eaaec983..11dac6e62cb01 100644 --- a/compiler/rustc_typeck/src/impl_wf_check.rs +++ b/compiler/rustc_typeck/src/impl_wf_check.rs @@ -12,13 +12,15 @@ 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; 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}; 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), "type", param_ty.name); + report_unused_parameter( + tcx, + tcx.def_span(param.def_id), + UnconstrainedParameterType::Type, + param_ty.name, + ); } } ty::GenericParamDefKind::Lifetime => { @@ -134,7 +141,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 +152,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,26 +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: &str, name: Symbol) { - let mut err = struct_span_err!( - tcx.sess, - 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(); +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. @@ -209,16 +203,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 5699f642bafa9..a39ca76d05257 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -99,7 +99,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}; @@ -116,6 +116,11 @@ 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; @@ -125,13 +130,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 }); } } } @@ -241,45 +240,31 @@ 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; } @@ -300,9 +285,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(); @@ -360,40 +344,23 @@ 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; } 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