Rollup merge of #102110 - CleanCut:migrate_rustc_passes_diagnostics, r=davidtwco

Migrate rustc_passes diagnostics

Picks up abandoned work from https://github.com/rust-lang/rust/pull/100870

I would like to do this collaboratively, as there is a lot of work! Here's the process:

- Comment below that you are willing to help and I will add you as a collaborator to my `rust` fork (that gives you write access)
- Indicate which file/task you would like to work on (so we don't duplicate work) from the list below
- Do the work, push up a commit, comment that you're done with that file/task
- Repeat until done 😄

### Files to Migrate (in `compiler/rustc_passes/src/`)

- [x] check_attr.rs ``@CleanCut``
- [x] check_const.rs ``@CleanCut``
- [x] dead.rs ``@CleanCut``
- [x] debugger_visualizer.rs ``@CleanCut``
- [x] diagnostic_items.rs ``@CleanCut``
- [x] entry.rs ``@CleanCut``
- [x] lang_items.rs ``@CleanCut``
- [x] layout_test.rs ``@CleanCut``
- [x] lib_features.rs ``@CleanCut``
- [x] ~liveness.rs~ ``@CleanCut`` Nothing to do
- [x] loops.rs ``@CleanCut``
- [x] naked_functions.rs ``@CleanCut``
- [x] stability.rs ``@CleanCut``
- [x] weak_lang_items.rs ``@CleanCut``

### Tasks

- [x] Rebase on current `master` ``@CleanCut``
- [x] Review work from [the earlier PR](https://github.com/rust-lang/rust/pull/100870) and make sure it all looks good
  - [x] compiler/rustc_error_messages/locales/en-US/passes.ftl ``@CleanCut``
  - [x] compiler/rustc_passes/src/check_attr.rs ``@CleanCut``
  - [x] compiler/rustc_passes/src/errors.rs ``@CleanCut``
  - [x] compiler/rustc_passes/src/lang_items.rs ``@CleanCut``
  - [x] compiler/rustc_passes/src/lib.rs ``@CleanCut``
  - [x] compiler/rustc_passes/src/weak_lang_items.rs ``@CleanCut``
This commit is contained in:
Dylan DPC 2022-10-12 11:11:23 +05:30 committed by GitHub
commit 32471a7035
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1793 additions and 756 deletions

View file

@ -18,3 +18,12 @@ middle_limit_invalid =
middle_const_eval_non_int =
constant evaluation of enum discriminant resulted in non-integer
middle_unknown_layout =
the type `{$ty}` has an unknown layout
middle_values_too_big =
values of the type `{$ty}` are too big for the current architecture
middle_cannot_be_normalized =
unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized

View file

@ -10,88 +10,119 @@ passes_outer_crate_level_attr =
passes_inner_crate_level_attr =
crate-level attribute should be in the root module
passes_ignored_attr_with_macro = `#[{$sym}]` is ignored on struct fields, match arms and macro defs
passes_ignored_attr_with_macro =
`#[{$sym}]` is ignored on struct fields, match arms and macro defs
.warn = {-passes_previously_accepted}
.note = {-passes_see_issue(issue: "80564")}
passes_ignored_attr = `#[{$sym}]` is ignored on struct fields and match arms
passes_ignored_attr =
`#[{$sym}]` is ignored on struct fields and match arms
.warn = {-passes_previously_accepted}
.note = {-passes_see_issue(issue: "80564")}
passes_inline_ignored_function_prototype = `#[inline]` is ignored on function prototypes
passes_inline_ignored_function_prototype =
`#[inline]` is ignored on function prototypes
passes_inline_ignored_constants = `#[inline]` is ignored on constants
passes_inline_ignored_constants =
`#[inline]` is ignored on constants
.warn = {-passes_previously_accepted}
.note = {-passes_see_issue(issue: "65833")}
passes_inline_not_fn_or_closure = attribute should be applied to function or closure
passes_inline_not_fn_or_closure =
attribute should be applied to function or closure
.label = not a function or closure
passes_no_coverage_ignored_function_prototype = `#[no_coverage]` is ignored on function prototypes
passes_no_coverage_ignored_function_prototype =
`#[no_coverage]` is ignored on function prototypes
passes_no_coverage_propagate =
`#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
passes_no_coverage_fn_defn = `#[no_coverage]` may only be applied to function definitions
passes_no_coverage_fn_defn =
`#[no_coverage]` may only be applied to function definitions
passes_no_coverage_not_coverable = `#[no_coverage]` must be applied to coverable code
passes_no_coverage_not_coverable =
`#[no_coverage]` must be applied to coverable code
.label = not coverable code
passes_should_be_applied_to_fn = attribute should be applied to a function definition
passes_should_be_applied_to_fn =
attribute should be applied to a function definition
.label = not a function definition
passes_naked_tracked_caller = cannot use `#[track_caller]` with `#[naked]`
passes_naked_tracked_caller =
cannot use `#[track_caller]` with `#[naked]`
passes_should_be_applied_to_struct_enum = attribute should be applied to a struct or enum
passes_should_be_applied_to_struct_enum =
attribute should be applied to a struct or enum
.label = not a struct or enum
passes_should_be_applied_to_trait = attribute should be applied to a trait
passes_should_be_applied_to_trait =
attribute should be applied to a trait
.label = not a trait
passes_target_feature_on_statement = {passes_should_be_applied_to_fn}
passes_target_feature_on_statement =
{passes_should_be_applied_to_fn}
.warn = {-passes_previously_accepted}
.label = {passes_should_be_applied_to_fn.label}
passes_should_be_applied_to_static = attribute should be applied to a static
passes_should_be_applied_to_static =
attribute should be applied to a static
.label = not a static
passes_doc_expect_str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
passes_doc_expect_str =
doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
passes_doc_alias_empty = {$attr_str} attribute cannot have empty value
passes_doc_alias_empty =
{$attr_str} attribute cannot have empty value
passes_doc_alias_bad_char = {$char_} character isn't allowed in {$attr_str}
passes_doc_alias_bad_char =
{$char_} character isn't allowed in {$attr_str}
passes_doc_alias_start_end = {$attr_str} cannot start or end with ' '
passes_doc_alias_start_end =
{$attr_str} cannot start or end with ' '
passes_doc_alias_bad_location = {$attr_str} isn't allowed on {$location}
passes_doc_alias_bad_location =
{$attr_str} isn't allowed on {$location}
passes_doc_alias_not_an_alias = {$attr_str} is the same as the item's name
passes_doc_alias_not_an_alias =
{$attr_str} is the same as the item's name
passes_doc_alias_duplicated = doc alias is duplicated
.label = first defined here
passes_doc_alias_not_string_literal = `#[doc(alias("a"))]` expects string literals
passes_doc_alias_not_string_literal =
`#[doc(alias("a"))]` expects string literals
passes_doc_alias_malformed =
doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
passes_doc_keyword_empty_mod = `#[doc(keyword = "...")]` should be used on empty modules
passes_doc_keyword_empty_mod =
`#[doc(keyword = "...")]` should be used on empty modules
passes_doc_keyword_not_mod = `#[doc(keyword = "...")]` should be used on modules
passes_doc_keyword_not_mod =
`#[doc(keyword = "...")]` should be used on modules
passes_doc_keyword_invalid_ident = `{$doc_keyword}` is not a valid identifier
passes_doc_keyword_invalid_ident =
`{$doc_keyword}` is not a valid identifier
passes_doc_fake_variadic_not_valid =
`#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity
passes_doc_keyword_only_impl = `#[doc(keyword = "...")]` should be used on impl blocks
passes_doc_keyword_only_impl =
`#[doc(keyword = "...")]` should be used on impl blocks
passes_doc_inline_conflict_first = this attribute...
passes_doc_inline_conflict_second = ...conflicts with this attribute
passes_doc_inline_conflict = conflicting doc inlining attributes
passes_doc_inline_conflict_first =
this attribute...
passes_doc_inline_conflict_second =
{"."}..conflicts with this attribute
passes_doc_inline_conflict =
conflicting doc inlining attributes
.help = remove one of the conflicting attributes
passes_doc_inline_only_use = this attribute can only be applied to a `use` item
passes_doc_inline_only_use =
this attribute can only be applied to a `use` item
.label = only applicable on `use` items
.not_a_use_item_label = not a `use` item
.note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
@ -99,30 +130,39 @@ passes_doc_inline_only_use = this attribute can only be applied to a `use` item
passes_doc_attr_not_crate_level =
`#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
passes_attr_crate_level = this attribute can only be applied at the crate level
passes_attr_crate_level =
this attribute can only be applied at the crate level
.suggestion = to apply to the crate, use an inner attribute
.help = to apply to the crate, use an inner attribute
.note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
passes_doc_test_unknown = unknown `doc(test)` attribute `{$path}`
passes_doc_test_unknown =
unknown `doc(test)` attribute `{$path}`
passes_doc_test_takes_list = `#[doc(test(...)]` takes a list of attributes
passes_doc_test_takes_list =
`#[doc(test(...)]` takes a list of attributes
passes_doc_primitive = `doc(primitive)` should never have been stable
passes_doc_primitive =
`doc(primitive)` should never have been stable
passes_doc_test_unknown_any = unknown `doc` attribute `{$path}`
passes_doc_test_unknown_any =
unknown `doc` attribute `{$path}`
passes_doc_test_unknown_spotlight = unknown `doc` attribute `{$path}`
passes_doc_test_unknown_spotlight =
unknown `doc` attribute `{$path}`
.note = `doc(spotlight)` was renamed to `doc(notable_trait)`
.suggestion = use `notable_trait` instead
.no_op_note = `doc(spotlight)` is now a no-op
passes_doc_test_unknown_include = unknown `doc` attribute `{$path}`
passes_doc_test_unknown_include =
unknown `doc` attribute `{$path}`
.suggestion = use `doc = include_str!` instead
passes_doc_invalid = invalid `doc` attribute
passes_doc_invalid =
invalid `doc` attribute
passes_pass_by_value = `pass_by_value` attribute should be applied to a struct, enum or type alias
passes_pass_by_value =
`pass_by_value` attribute should be applied to a struct, enum or type alias
.label = is not a struct, enum or type alias
passes_allow_incoherent_impl =
@ -137,42 +177,54 @@ passes_must_use_async =
`must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within
.label = this attribute does nothing, the `Future`s returned by async functions are already `must_use`
passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target}
passes_must_use_no_effect =
`#[must_use]` has no effect when applied to {$article} {$target}
passes_must_not_suspend = `must_not_suspend` attribute should be applied to a struct, enum, or trait
passes_must_not_suspend =
`must_not_suspend` attribute should be applied to a struct, enum, or trait
.label = is not a struct, enum, or trait
passes_cold = {passes_should_be_applied_to_fn}
passes_cold =
{passes_should_be_applied_to_fn}
.warn = {-passes_previously_accepted}
.label = {passes_should_be_applied_to_fn.label}
passes_link = attribute should be applied to an `extern` block with non-Rust ABI
passes_link =
attribute should be applied to an `extern` block with non-Rust ABI
.warn = {-passes_previously_accepted}
.label = not an `extern` block
passes_link_name = attribute should be applied to a foreign function or static
passes_link_name =
attribute should be applied to a foreign function or static
.warn = {-passes_previously_accepted}
.label = not a foreign function or static
.help = try `#[link(name = "{$value}")]` instead
passes_no_link = attribute should be applied to an `extern crate` item
passes_no_link =
attribute should be applied to an `extern crate` item
.label = not an `extern crate` item
passes_export_name = attribute should be applied to a free function, impl method or static
passes_export_name =
attribute should be applied to a free function, impl method or static
.label = not a free function, impl method or static
passes_rustc_layout_scalar_valid_range_not_struct = attribute should be applied to a struct
passes_rustc_layout_scalar_valid_range_not_struct =
attribute should be applied to a struct
.label = not a struct
passes_rustc_layout_scalar_valid_range_arg = expected exactly one integer literal argument
passes_rustc_layout_scalar_valid_range_arg =
expected exactly one integer literal argument
passes_rustc_legacy_const_generics_only = #[rustc_legacy_const_generics] functions must only have const generics
passes_rustc_legacy_const_generics_only =
#[rustc_legacy_const_generics] functions must only have const generics
.label = non-const generic parameter
passes_rustc_legacy_const_generics_index = #[rustc_legacy_const_generics] must have one index for each generic parameter
passes_rustc_legacy_const_generics_index =
#[rustc_legacy_const_generics] must have one index for each generic parameter
.label = generic parameters
passes_rustc_legacy_const_generics_index_exceed = index exceeds number of arguments
passes_rustc_legacy_const_generics_index_exceed =
index exceeds number of arguments
.label = there {$arg_count ->
[one] is
*[other] are
@ -181,93 +233,438 @@ passes_rustc_legacy_const_generics_index_exceed = index exceeds number of argume
*[other] arguments
}
passes_rustc_legacy_const_generics_index_negative = arguments should be non-negative integers
passes_rustc_legacy_const_generics_index_negative =
arguments should be non-negative integers
passes_rustc_dirty_clean = attribute requires -Z query-dep-graph to be enabled
passes_rustc_dirty_clean =
attribute requires -Z query-dep-graph to be enabled
passes_link_section = attribute should be applied to a function or static
passes_link_section =
attribute should be applied to a function or static
.warn = {-passes_previously_accepted}
.label = not a function or static
passes_no_mangle_foreign = `#[no_mangle]` has no effect on a foreign {$foreign_item_kind}
passes_no_mangle_foreign =
`#[no_mangle]` has no effect on a foreign {$foreign_item_kind}
.warn = {-passes_previously_accepted}
.label = foreign {$foreign_item_kind}
.note = symbol names in extern blocks are not mangled
.suggestion = remove this attribute
passes_no_mangle = attribute should be applied to a free function, impl method or static
passes_no_mangle =
attribute should be applied to a free function, impl method or static
.warn = {-passes_previously_accepted}
.label = not a free function, impl method or static
passes_repr_ident = meta item in `repr` must be an identifier
passes_repr_ident =
meta item in `repr` must be an identifier
passes_repr_conflicting = conflicting representation hints
passes_repr_conflicting =
conflicting representation hints
passes_used_static = attribute must be applied to a `static` variable
passes_used_static =
attribute must be applied to a `static` variable
passes_used_compiler_linker = `used(compiler)` and `used(linker)` can't be used together
passes_used_compiler_linker =
`used(compiler)` and `used(linker)` can't be used together
passes_allow_internal_unstable = attribute should be applied to a macro
passes_allow_internal_unstable =
attribute should be applied to a macro
.label = not a macro
passes_debug_visualizer_placement = attribute should be applied to a module
passes_debug_visualizer_placement =
attribute should be applied to a module
passes_debug_visualizer_invalid = invalid argument
passes_debug_visualizer_invalid =
invalid argument
.note_1 = expected: `natvis_file = "..."`
.note_2 = OR
.note_3 = expected: `gdb_script_file = "..."`
passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn`
passes_debug_visualizer_unreadable =
couldn't read {$file}: {$error}
passes_rustc_allow_const_fn_unstable =
attribute should be applied to `const fn`
.label = not a `const fn`
passes_rustc_std_internal_symbol = attribute should be applied to functions or statics
passes_rustc_std_internal_symbol =
attribute should be applied to functions or statics
.label = not a function or static
passes_const_trait = attribute should be applied to a trait
passes_const_trait =
attribute should be applied to a trait
passes_stability_promotable = attribute cannot be applied to an expression
passes_stability_promotable =
attribute cannot be applied to an expression
passes_deprecated = attribute is ignored here
passes_deprecated =
attribute is ignored here
passes_macro_use = `#[{$name}]` only has an effect on `extern crate` and modules
passes_macro_use =
`#[{$name}]` only has an effect on `extern crate` and modules
passes_macro_export = `#[macro_export]` only has an effect on macro definitions
passes_macro_export =
`#[macro_export]` only has an effect on macro definitions
passes_plugin_registrar = `#[plugin_registrar]` only has an effect on functions
passes_plugin_registrar =
`#[plugin_registrar]` only has an effect on functions
passes_unused_empty_lints_note = attribute `{$name}` with an empty list has no effect
passes_unused_empty_lints_note =
attribute `{$name}` with an empty list has no effect
passes_unused_no_lints_note = attribute `{$name}` without any lints has no effect
passes_unused_no_lints_note =
attribute `{$name}` without any lints has no effect
passes_unused_default_method_body_const_note =
`default_method_body_is_const` has been replaced with `#[const_trait]` on traits
passes_unused = unused attribute
passes_unused =
unused attribute
.suggestion = remove this attribute
passes_non_exported_macro_invalid_attrs = attribute should be applied to function or closure
passes_non_exported_macro_invalid_attrs =
attribute should be applied to function or closure
.label = not a function or closure
passes_unused_duplicate = unused attribute
passes_unused_duplicate =
unused attribute
.suggestion = remove this attribute
.note = attribute also specified here
.warn = {-passes_previously_accepted}
passes_unused_multiple = multiple `{$name}` attributes
passes_unused_multiple =
multiple `{$name}` attributes
.suggestion = remove this attribute
.note = attribute also specified here
passes_rustc_lint_opt_ty = `#[rustc_lint_opt_ty]` should be applied to a struct
passes_rustc_lint_opt_ty =
`#[rustc_lint_opt_ty]` should be applied to a struct
.label = not a struct
passes_rustc_lint_opt_deny_field_access = `#[rustc_lint_opt_deny_field_access]` should be applied to a field
passes_rustc_lint_opt_deny_field_access =
`#[rustc_lint_opt_deny_field_access]` should be applied to a field
.label = not a field
passes_link_ordinal = attribute should be applied to a foreign function or static
passes_link_ordinal =
attribute should be applied to a foreign function or static
.label = not a foreign function or static
passes_collapse_debuginfo = `collapse_debuginfo` attribute should be applied to macro definitions
passes_collapse_debuginfo =
`collapse_debuginfo` attribute should be applied to macro definitions
.label = not a macro definition
passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect
passes_deprecated_annotation_has_no_effect =
this `#[deprecated]` annotation has no effect
.suggestion = remove the unnecessary deprecation attribute
passes_unknown_external_lang_item =
unknown external lang item: `{$lang_item}`
passes_missing_panic_handler =
`#[panic_handler]` function required, but not found
passes_alloc_func_required =
`#[alloc_error_handler]` function required, but not found
passes_missing_alloc_error_handler =
use `#![feature(default_alloc_error_handler)]` for a default error handler
passes_missing_lang_item =
language item required, but not found: `{$name}`
.note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library
.help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config`
passes_lang_item_on_incorrect_target =
`{$name}` language item must be applied to a {$expected_target}
.label = attribute should be applied to a {$expected_target}, not a {$actual_target}
passes_unknown_lang_item =
definition of an unknown language item: `{$name}`
.label = definition of unknown language item `{$name}`
passes_invalid_attr_at_crate_level =
`{$name}` attribute cannot be used at crate level
.suggestion = perhaps you meant to use an outer attribute
passes_duplicate_diagnostic_item =
duplicate diagnostic item found: `{$name}`.
passes_duplicate_diagnostic_item_in_crate =
duplicate diagnostic item in crate `{$crate_name}`: `{$name}`.
passes_diagnostic_item_first_defined =
the diagnostic item is first defined here
.note = the diagnostic item is first defined in crate `{$orig_crate_name}`.
passes_abi =
abi: {$abi}
passes_align =
align: {$align}
passes_size =
size: {$size}
passes_homogeneous_aggregate =
homogeneous_aggregate: {$homogeneous_aggregate}
passes_layout_of =
layout_of({$normalized_ty}) = {$ty_layout}
passes_unrecognized_field =
unrecognized field name `{$name}`
passes_layout =
layout error: {$layout_error}
passes_feature_stable_twice =
feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since}
passes_feature_previously_declared =
feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared}
passes_expr_not_allowed_in_context =
{$expr} is not allowed in a `{$context}`
passes_const_impl_const_trait =
const `impl`s must be for traits marked with `#[const_trait]`
.note = this trait must be annotated with `#[const_trait]`
passes_break_non_loop =
`break` with value from a `{$kind}` loop
.label = can only break with a value inside `loop` or breakable block
.label2 = you can't `break` with a value in a `{$kind}` loop
.suggestion = use `break` on its own without a value inside this `{$kind}` loop
.break_expr_suggestion = alternatively, you might have meant to use the available loop label
passes_continue_labeled_block =
`continue` pointing to a labeled block
.label = labeled blocks cannot be `continue`'d
.block_label = labeled block the `continue` points to
passes_break_inside_closure =
`{$name}` inside of a closure
.label = cannot `{$name}` inside of a closure
.closure_label = enclosing closure
passes_break_inside_async_block =
`{$name}` inside of an `async` block
.label = cannot `{$name}` inside of an `async` block
.async_block_label = enclosing `async` block
passes_outside_loop =
`{$name}` outside of a loop
.label = cannot `{$name}` outside of a loop
passes_unlabeled_in_labeled_block =
unlabeled `{$cf_type}` inside of a labeled block
.label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label
passes_unlabeled_cf_in_while_condition =
`break` or `continue` with no label in the condition of a `while` loop
.label = unlabeled `{$cf_type}` in the condition of a `while` loop
passes_cannot_inline_naked_function =
naked functions cannot be inlined
passes_undefined_naked_function_abi =
Rust ABI is unsupported in naked functions
passes_no_patterns =
patterns not allowed in naked function parameters
passes_params_not_allowed =
referencing function parameters is not allowed in naked functions
.help = follow the calling convention in asm block to use parameters
passes_naked_functions_asm_block =
naked functions must contain a single asm block
.label_multiple_asm = multiple asm blocks are unsupported in naked functions
.label_non_asm = non-asm is unsupported in naked functions
passes_naked_functions_operands =
only `const` and `sym` operands are supported in naked functions
passes_naked_functions_asm_options =
asm options unsupported in naked functions: {$unsupported_options}
passes_naked_functions_must_use_noreturn =
asm in naked functions must use `noreturn` option
.suggestion = consider specifying that the asm block is responsible for returning from the function
passes_attr_only_on_main =
`{$attr}` attribute can only be used on `fn main()`
passes_attr_only_on_root_main =
`{$attr}` attribute can only be used on root `fn main()`
passes_attr_only_in_functions =
`{$attr}` attribute can only be used on functions
passes_multiple_rustc_main =
multiple functions with a `#[rustc_main]` attribute
.first = first `#[rustc_main]` function
.additional = additional `#[rustc_main]` function
passes_multiple_start_functions =
multiple `start` functions
.label = multiple `start` functions
.previous = previous `#[start]` function here
passes_extern_main =
the `main` function cannot be declared in an `extern` block
passes_unix_sigpipe_values =
valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
passes_no_main_function =
`main` function not found in crate `{$crate_name}`
.here_is_main = here is a function named `main`
.one_or_more_possible_main = you have one or more functions named `main` not defined at the crate level
.consider_moving_main = consider moving the `main` function definitions
.main_must_be_defined_at_crate = the main function must be defined at the crate level{$has_filename ->
[true] {" "}(in `{$filename}`)
*[false] {""}
}
.consider_adding_main_to_file = consider adding a `main` function to `{$filename}`
.consider_adding_main_at_crate = consider adding a `main` function at the crate level
.teach_note = If you don't know the basics of Rust, you can go look to the Rust Book to get started: https://doc.rust-lang.org/book/
.non_function_main = non-function item at `crate::main` is found
passes_duplicate_lang_item =
found duplicate lang item `{$lang_item_name}`
.first_defined_span = the lang item is first defined here
.first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on)
.first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`.
.first_definition_local = first definition in the local crate (`{$orig_crate_name}`)
.second_definition_local = second definition in the local crate (`{$crate_name}`)
.first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
.second_definition_path = second definition in `{$crate_name}` loaded from {$path}
passes_duplicate_lang_item_crate =
duplicate lang item in crate `{$crate_name}`: `{$lang_item_name}`.
.first_defined_span = the lang item is first defined here
.first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on)
.first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`.
.first_definition_local = first definition in the local crate (`{$orig_crate_name}`)
.second_definition_local = second definition in the local crate (`{$crate_name}`)
.first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
.second_definition_path = second definition in `{$crate_name}` loaded from {$path}
passes_duplicate_lang_item_crate_depends =
duplicate lang item in crate `{$crate_name}` (which `{$dependency_of}` depends on): `{$lang_item_name}`.
.first_defined_span = the lang item is first defined here
.first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on)
.first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`.
.first_definition_local = first definition in the local crate (`{$orig_crate_name}`)
.second_definition_local = second definition in the local crate (`{$crate_name}`)
.first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
.second_definition_path = second definition in `{$crate_name}` loaded from {$path}
passes_incorrect_target =
`{$name}` language item must be applied to a {$kind} with {$at_least ->
[true] at least {$num}
*[false] {$num}
} generic {$num ->
[one] argument
*[other] arguments
}
.label = this {$kind} has {$actual_num} generic {$actual_num ->
[one] argument
*[other] arguments
}
passes_useless_assignment =
useless assignment of {$is_field_assign ->
[true] field
*[false] variable
} of type `{$ty}` to itself
passes_only_has_effect_on =
`#[{$attr_name}]` only has an effect on {$target_name ->
[function] functions
[module] modules
[implementation_block] implementation blocks
*[unspecified] (unspecified--this is a compiler bug)
}
passes_object_lifetime_err =
{$repr}
passes_unrecognized_repr_hint =
unrecognized representation hint
.help = valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
passes_attr_application_enum =
attribute should be applied to an enum
.label = not an enum
passes_attr_application_struct =
attribute should be applied to a struct
.label = not a struct
passes_attr_application_struct_union =
attribute should be applied to a struct or union
.label = not a struct or union
passes_attr_application_struct_enum_union =
attribute should be applied to a struct, enum, or union
.label = not a struct, enum, or union
passes_attr_application_struct_enum_function_union =
attribute should be applied to a struct, enum, function, or union
.label = not a struct, enum, function, or union
passes_transparent_incompatible =
transparent {$target} cannot have other repr hints
passes_deprecated_attribute =
deprecated attribute must be paired with either stable or unstable attribute
passes_useless_stability =
this stability annotation is useless
.label = useless stability annotation
.item = the stability attribute annotates this item
passes_invalid_stability =
invalid stability version found
.label = invalid stability version
.item = the stability attribute annotates this item
passes_cannot_stabilize_deprecated =
an API can't be stabilized after it is deprecated
.label = invalid version
.item = the stability attribute annotates this item
passes_invalid_deprecation_version =
invalid deprecation version found
.label = invalid deprecation version
.item = the stability attribute annotates this item
passes_missing_stability_attr =
{$descr} has missing stability attribute
passes_missing_const_stab_attr =
{$descr} has missing const stability attribute
passes_trait_impl_const_stable =
trait implementations cannot be const stable yet
.note = see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
passes_feature_only_on_nightly =
`#![feature]` may not be used on the {$release_channel} release channel
passes_unknown_feature =
unknown feature `{$feature}`
passes_implied_feature_not_exist =
feature `{$implied_by}` implying `{$feature}` does not exist
passes_duplicate_feature_err =
the feature `{$feature}` has already been declared
passes_missing_const_err =
attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
.help = make the function or method const
.label = attribute specified here

View file

@ -255,6 +255,56 @@ impl EmissionGuarantee for () {
}
}
/// Marker type which enables implementation of `create_note` and `emit_note` functions for
/// note-without-error struct diagnostics.
#[derive(Copy, Clone)]
pub struct Noted;
impl<'a> DiagnosticBuilder<'a, Noted> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
pub(crate) fn new_note(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
let diagnostic = Diagnostic::new_with_code(Level::Note, None, message);
Self::new_diagnostic_note(handler, diagnostic)
}
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
pub(crate) fn new_diagnostic_note(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
debug!("Created new diagnostic");
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(diagnostic),
},
_marker: PhantomData,
}
}
}
impl EmissionGuarantee for Noted {
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
match db.inner.state {
// First `.emit()` call, the `&Handler` is still available.
DiagnosticBuilderState::Emittable(handler) => {
db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
handler.emit_diagnostic(&mut db.inner.diagnostic);
}
// `.emit()` was previously called, disallowed from repeating it.
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
}
Noted
}
fn make_diagnostic_builder(
handler: &Handler,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new_note(handler, msg)
}
}
impl<'a> DiagnosticBuilder<'a, !> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].

View file

@ -374,7 +374,7 @@ pub use diagnostic::{
AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay,
DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
};
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee};
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
use std::backtrace::Backtrace;
/// A handler deals with errors and other compiler output.

View file

@ -191,10 +191,29 @@ pub enum LayoutError<'tcx> {
impl<'a> IntoDiagnostic<'a, !> for LayoutError<'a> {
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, !> {
handler.struct_fatal(self.to_string())
let mut diag = handler.struct_fatal("");
match self {
LayoutError::Unknown(ty) => {
diag.set_arg("ty", ty);
diag.set_primary_message(rustc_errors::fluent::middle::unknown_layout);
}
LayoutError::SizeOverflow(ty) => {
diag.set_arg("ty", ty);
diag.set_primary_message(rustc_errors::fluent::middle::values_too_big);
}
LayoutError::NormalizationFailure(ty, e) => {
diag.set_arg("ty", ty);
diag.set_arg("failure_ty", e.get_type_for_failure());
diag.set_primary_message(rustc_errors::fluent::middle::cannot_be_normalized);
}
}
diag
}
}
// FIXME: Once the other errors that embed this error have been converted to translateable
// diagnostics, this Display impl should be removed.
impl<'tcx> fmt::Display for LayoutError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {

View file

@ -4,10 +4,13 @@
//! conflicts between multiple such attributes attached to the same
//! item.
use crate::errors;
use crate::errors::{
self, AttrApplication, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel, ObjectLifetimeErr,
OnlyHasEffectOn, TransparentIncompatible, UnrecognizedReprHint,
};
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan};
use rustc_errors::{fluent, Applicability, MultiSpan};
use rustc_expand::base::resolve_path;
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir;
@ -164,17 +167,17 @@ impl CheckAttrVisitor<'_> {
sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
sym::deprecated => self.check_deprecated(hir_id, attr, span, target),
sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target),
sym::path => self.check_generic_attr(hir_id, attr, target, &[Target::Mod]),
sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod),
sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
sym::macro_export => self.check_macro_export(hir_id, attr, target),
sym::ignore | sym::should_panic | sym::proc_macro_derive => {
self.check_generic_attr(hir_id, attr, target, &[Target::Fn])
self.check_generic_attr(hir_id, attr, target, Target::Fn)
}
sym::automatically_derived => {
self.check_generic_attr(hir_id, attr, target, &[Target::Impl])
self.check_generic_attr(hir_id, attr, target, Target::Impl)
}
sym::no_implicit_prelude => {
self.check_generic_attr(hir_id, attr, target, &[Target::Mod])
self.check_generic_attr(hir_id, attr, target, Target::Mod)
}
sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id),
_ => {}
@ -351,31 +354,17 @@ impl CheckAttrVisitor<'_> {
hir_id: HirId,
attr: &Attribute,
target: Target,
allowed_targets: &[Target],
allowed_target: Target,
) {
if !allowed_targets.iter().any(|t| t == &target) {
let name = attr.name_or_empty();
let mut i = allowed_targets.iter();
// Pluralize
let b = i.next().map_or_else(String::new, |t| t.to_string() + "s");
let supported_names = i.enumerate().fold(b, |mut b, (i, allowed_target)| {
if allowed_targets.len() > 2 && i == allowed_targets.len() - 2 {
b.push_str(", and ");
} else if allowed_targets.len() == 2 && i == allowed_targets.len() - 2 {
b.push_str(" and ");
} else {
b.push_str(", ");
}
// Pluralize
b.push_str(&(allowed_target.to_string() + "s"));
b
});
self.tcx.struct_span_lint_hir(
if target != allowed_target {
self.tcx.emit_spanned_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span,
&format!("`#[{name}]` only has an effect on {}", supported_names),
|lint| lint,
OnlyHasEffectOn {
attr_name: attr.name_or_empty(),
target_name: allowed_target.name().replace(" ", "_"),
},
);
}
}
@ -432,7 +421,7 @@ impl CheckAttrVisitor<'_> {
ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
};
tcx.sess.span_err(p.span, &repr);
tcx.sess.emit_err(ObjectLifetimeErr { span: p.span, repr });
}
}
}
@ -1605,12 +1594,17 @@ impl CheckAttrVisitor<'_> {
continue;
}
let (article, allowed_targets) = match hint.name_or_empty() {
match hint.name_or_empty() {
sym::C => {
is_c = true;
match target {
Target::Struct | Target::Union | Target::Enum => continue,
_ => ("a", "struct, enum, or union"),
_ => {
self.tcx.sess.emit_err(AttrApplication::StructEnumUnion {
hint_span: hint.span(),
span,
});
}
}
}
sym::align => {
@ -1626,12 +1620,20 @@ impl CheckAttrVisitor<'_> {
match target {
Target::Struct | Target::Union | Target::Enum | Target::Fn => continue,
_ => ("a", "struct, enum, function, or union"),
_ => {
self.tcx.sess.emit_err(AttrApplication::StructEnumFunctionUnion {
hint_span: hint.span(),
span,
});
}
}
}
sym::packed => {
if target != Target::Struct && target != Target::Union {
("a", "struct or union")
self.tcx.sess.emit_err(AttrApplication::StructUnion {
hint_span: hint.span(),
span,
});
} else {
continue;
}
@ -1639,7 +1641,9 @@ impl CheckAttrVisitor<'_> {
sym::simd => {
is_simd = true;
if target != Target::Struct {
("a", "struct")
self.tcx
.sess
.emit_err(AttrApplication::Struct { hint_span: hint.span(), span });
} else {
continue;
}
@ -1648,7 +1652,12 @@ impl CheckAttrVisitor<'_> {
is_transparent = true;
match target {
Target::Struct | Target::Union | Target::Enum => continue,
_ => ("a", "struct, enum, or union"),
_ => {
self.tcx.sess.emit_err(AttrApplication::StructEnumUnion {
hint_span: hint.span(),
span,
});
}
}
}
sym::i8
@ -1665,35 +1674,18 @@ impl CheckAttrVisitor<'_> {
| sym::usize => {
int_reprs += 1;
if target != Target::Enum {
("an", "enum")
self.tcx
.sess
.emit_err(AttrApplication::Enum { hint_span: hint.span(), span });
} else {
continue;
}
}
_ => {
struct_span_err!(
self.tcx.sess,
hint.span(),
E0552,
"unrecognized representation hint"
)
.help("valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, \
`i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`")
.emit();
self.tcx.sess.emit_err(UnrecognizedReprHint { span: hint.span() });
continue;
}
};
struct_span_err!(
self.tcx.sess,
hint.span(),
E0517,
"{}",
&format!("attribute should be applied to {article} {allowed_targets}")
)
.span_label(span, &format!("not {article} {allowed_targets}"))
.emit();
}
// Just point at all repr hints if there are any incompatibilities.
@ -1703,14 +1695,9 @@ impl CheckAttrVisitor<'_> {
// Error on repr(transparent, <anything else>).
if is_transparent && hints.len() > 1 {
let hint_spans: Vec<_> = hint_spans.clone().collect();
struct_span_err!(
self.tcx.sess,
hint_spans,
E0692,
"transparent {} cannot have other repr hints",
target
)
.emit();
self.tcx
.sess
.emit_err(TransparentIncompatible { hint_spans, target: target.to_string() });
}
// Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
if (int_reprs > 1)
@ -1862,14 +1849,12 @@ impl CheckAttrVisitor<'_> {
match std::fs::File::open(&file) {
Ok(_) => true,
Err(err) => {
self.tcx
.sess
.struct_span_err(
meta_item.span,
&format!("couldn't read {}: {}", file.display(), err),
)
.emit();
Err(error) => {
self.tcx.sess.emit_err(DebugVisualizerUnreadable {
span: meta_item.span,
file: &file,
error,
});
false
}
}
@ -2180,25 +2165,11 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
if attr.style == AttrStyle::Inner {
for attr_to_check in ATTRS_TO_CHECK {
if attr.has_name(*attr_to_check) {
let mut err = tcx.sess.struct_span_err(
attr.span,
&format!(
"`{}` attribute cannot be used at crate level",
attr_to_check.to_ident_string()
),
);
// Only emit an error with a suggestion if we can create a
// string out of the attribute span
if let Ok(src) = tcx.sess.source_map().span_to_snippet(attr.span) {
let replacement = src.replace("#!", "#");
err.span_suggestion_verbose(
attr.span,
"perhaps you meant to use an outer attribute",
replacement,
rustc_errors::Applicability::MachineApplicable,
);
}
err.emit();
tcx.sess.emit_err(InvalidAttrAtCrateLevel {
span: attr.span,
snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(),
name: *attr_to_check,
});
}
}
}

View file

@ -8,7 +8,6 @@
//! through, but errors for structured control flow in a `const` should be emitted here.
use rustc_attr as attr;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
@ -18,6 +17,8 @@ use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
use rustc_span::{sym, Span, Symbol};
use crate::errors::ExprNotAllowedInContext;
/// An expression that is not *always* legal in a const context.
#[derive(Clone, Copy)]
enum NonConstExpr {
@ -133,18 +134,22 @@ impl<'tcx> CheckConstVisitor<'tcx> {
let const_kind =
const_kind.expect("`const_check_violated` may only be called inside a const context");
let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());
let required_gates = required_gates.unwrap_or(&[]);
let missing_gates: Vec<_> =
required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
match missing_gates.as_slice() {
[] => {
struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit();
tcx.sess.emit_err(ExprNotAllowedInContext {
span,
expr: expr.name(),
context: const_kind.keyword_name(),
});
}
[missing_primary, ref missing_secondary @ ..] => {
let msg =
format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());
let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, &msg);
// If multiple feature gates would be required to enable this expression, include

View file

@ -4,7 +4,7 @@
use itertools::Itertools;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, Applicability, DelayDm, MultiSpan};
use rustc_errors::{pluralize, Applicability, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
@ -18,6 +18,8 @@ use rustc_session::lint;
use rustc_span::symbol::{sym, Symbol};
use std::mem;
use crate::errors::UselessAssignment;
// Any local node that may call something in its body block should be
// explored. For example, if it's a live Node::Item that is a
// function, then we should explore its block to check for codes that
@ -180,19 +182,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
&& !assign.span.from_expansion()
{
let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..));
self.tcx.struct_span_lint_hir(
self.tcx.emit_spanned_lint(
lint::builtin::DEAD_CODE,
assign.hir_id,
assign.span,
DelayDm(|| format!(
"useless assignment of {} of type `{}` to itself",
if is_field_assign { "field" } else { "variable" },
self.typeck_results().expr_ty(lhs),
)),
|lint| {
lint
},
UselessAssignment { is_field_assign, ty: self.typeck_results().expr_ty(lhs) }
)
}
}

View file

@ -13,6 +13,8 @@ use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
use std::sync::Arc;
use crate::errors::DebugVisualizerUnreadable;
fn check_for_debugger_visualizer<'tcx>(
tcx: TyCtxt<'tcx>,
hir_id: HirId,
@ -54,13 +56,12 @@ fn check_for_debugger_visualizer<'tcx>(
debugger_visualizers
.insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type));
}
Err(err) => {
tcx.sess
.struct_span_err(
meta_item.span,
&format!("couldn't read {}: {}", file.display(), err),
)
.emit();
Err(error) => {
tcx.sess.emit_err(DebugVisualizerUnreadable {
span: meta_item.span,
file: &file,
error,
});
}
}
}

View file

@ -14,7 +14,9 @@ use rustc_hir::diagnostic_items::DiagnosticItems;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::symbol::{kw::Empty, sym, Symbol};
use crate::errors::{DuplicateDiagnosticItem, DuplicateDiagnosticItemInCrate};
fn observe_item<'tcx>(
tcx: TyCtxt<'tcx>,
@ -33,25 +35,22 @@ fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item
items.id_to_name.insert(item_def_id, name);
if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) {
if original_def_id != item_def_id {
let mut err = match tcx.hir().span_if_local(item_def_id) {
Some(span) => tcx
.sess
.struct_span_err(span, &format!("duplicate diagnostic item found: `{name}`.")),
None => tcx.sess.struct_err(&format!(
"duplicate diagnostic item in crate `{}`: `{}`.",
tcx.crate_name(item_def_id.krate),
name
)),
};
if let Some(span) = tcx.hir().span_if_local(original_def_id) {
err.span_note(span, "the diagnostic item is first defined here");
let orig_span = tcx.hir().span_if_local(original_def_id);
let orig_crate_name = if orig_span.is_some() {
None
} else {
err.note(&format!(
"the diagnostic item is first defined in crate `{}`.",
tcx.crate_name(original_def_id.krate)
));
}
err.emit();
Some(tcx.crate_name(original_def_id.krate))
};
match tcx.hir().span_if_local(item_def_id) {
Some(span) => tcx.sess.emit_err(DuplicateDiagnosticItem { span, name }),
None => tcx.sess.emit_err(DuplicateDiagnosticItemInCrate {
span: orig_span,
orig_crate_name: orig_crate_name.unwrap_or(Empty),
have_orig_crate_name: orig_crate_name.map(|_| ()),
crate_name: tcx.crate_name(item_def_id.krate),
name,
}),
};
}
}
}

View file

@ -1,5 +1,5 @@
use rustc_ast::entry::EntryPointType;
use rustc_errors::struct_span_err;
use rustc_errors::error_code;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
@ -8,7 +8,12 @@ use rustc_middle::ty::{DefIdTree, TyCtxt};
use rustc_session::config::{sigpipe, CrateType, EntryFnType};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_span::{Span, Symbol};
use crate::errors::{
AttrOnlyInFunctions, AttrOnlyOnMain, AttrOnlyOnRootMain, ExternMain, MultipleRustcMain,
MultipleStartFunctions, NoMainErr, UnixSigpipeValues,
};
struct EntryContext<'tcx> {
tcx: TyCtxt<'tcx>,
@ -71,14 +76,9 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry
}
}
fn err_if_attr_found(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol, details: &str) {
fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> {
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym) {
ctxt.tcx
.sess
.struct_span_err(attr.span, &format!("`{}` attribute {}", sym, details))
.emit();
}
ctxt.tcx.sess.find_by_name(attrs, sym).map(|attr| attr.span)
}
fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
@ -86,49 +86,47 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
match entry_point_type(ctxt, id, at_root) {
EntryPointType::None => {
err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on `fn main()`");
if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
}
}
_ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => {
err_if_attr_found(ctxt, id, sym::start, "can only be used on functions");
err_if_attr_found(ctxt, id, sym::rustc_main, "can only be used on functions");
for attr in [sym::start, sym::rustc_main] {
if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
ctxt.tcx.sess.emit_err(AttrOnlyInFunctions { span, attr });
}
}
}
EntryPointType::MainNamed => (),
EntryPointType::OtherMain => {
err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on root `fn main()`");
if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
ctxt.tcx.sess.emit_err(AttrOnlyOnRootMain { span, attr: sym::unix_sigpipe });
}
ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
}
EntryPointType::RustcMainAttr => {
if ctxt.attr_main_fn.is_none() {
ctxt.attr_main_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
} else {
struct_span_err!(
ctxt.tcx.sess,
ctxt.tcx.def_span(id.def_id.to_def_id()),
E0137,
"multiple functions with a `#[rustc_main]` attribute"
)
.span_label(
ctxt.tcx.def_span(id.def_id.to_def_id()),
"additional `#[rustc_main]` function",
)
.span_label(ctxt.attr_main_fn.unwrap().1, "first `#[rustc_main]` function")
.emit();
ctxt.tcx.sess.emit_err(MultipleRustcMain {
span: ctxt.tcx.def_span(id.def_id.to_def_id()),
first: ctxt.attr_main_fn.unwrap().1,
additional: ctxt.tcx.def_span(id.def_id.to_def_id()),
});
}
}
EntryPointType::Start => {
err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on `fn main()`");
if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
}
if ctxt.start_fn.is_none() {
ctxt.start_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
} else {
struct_span_err!(
ctxt.tcx.sess,
ctxt.tcx.def_span(id.def_id),
E0138,
"multiple `start` functions"
)
.span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
.span_label(ctxt.tcx.def_span(id.def_id.to_def_id()), "multiple `start` functions")
.emit();
ctxt.tcx.sess.emit_err(MultipleStartFunctions {
span: ctxt.tcx.def_span(id.def_id),
labeled: ctxt.tcx.def_span(id.def_id.to_def_id()),
previous: ctxt.start_fn.unwrap().1,
});
}
}
}
@ -144,12 +142,7 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
if let Some(main_def) = tcx.resolutions(()).main_def && let Some(def_id) = main_def.opt_fn_def_id() {
// non-local main imports are handled below
if let Some(def_id) = def_id.as_local() && matches!(tcx.hir().find_by_def_id(def_id), Some(Node::ForeignItem(_))) {
tcx.sess
.struct_span_err(
tcx.def_span(def_id),
"the `main` function cannot be declared in an `extern` block",
)
.emit();
tcx.sess.emit_err(ExternMain { span: tcx.def_span(def_id) });
return None;
}
@ -182,12 +175,7 @@ fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 {
sigpipe::DEFAULT
}
_ => {
tcx.sess
.struct_span_err(
attr.span,
"valid values for `#[unix_sigpipe = \"...\"]` are `inherit`, `sig_ign`, or `sig_dfl`",
)
.emit();
tcx.sess.emit_err(UnixSigpipeValues { span: attr.span });
sigpipe::DEFAULT
}
}
@ -206,52 +194,29 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
}
// There is no main function.
let mut err = struct_span_err!(
tcx.sess,
DUMMY_SP,
E0601,
"`main` function not found in crate `{}`",
tcx.crate_name(LOCAL_CRATE)
);
let filename = &tcx.sess.local_crate_source_file;
let note = if !visitor.non_main_fns.is_empty() {
for &span in &visitor.non_main_fns {
err.span_note(span, "here is a function named `main`");
}
err.note("you have one or more functions named `main` not defined at the crate level");
err.help("consider moving the `main` function definitions");
// There were some functions named `main` though. Try to give the user a hint.
format!(
"the main function must be defined at the crate level{}",
filename.as_ref().map(|f| format!(" (in `{}`)", f.display())).unwrap_or_default()
)
} else if let Some(filename) = filename {
format!("consider adding a `main` function to `{}`", filename.display())
} else {
String::from("consider adding a `main` function at the crate level")
};
let mut has_filename = true;
let filename = tcx.sess.local_crate_source_file.clone().unwrap_or_else(|| {
has_filename = false;
Default::default()
});
let main_def_opt = tcx.resolutions(()).main_def;
let diagnostic_id = error_code!(E0601);
let add_teach_note = tcx.sess.teach(&diagnostic_id);
// The file may be empty, which leads to the diagnostic machinery not emitting this
// note. This is a relatively simple way to detect that case and emit a span-less
// note instead.
if tcx.sess.source_map().lookup_line(sp.hi()).is_ok() {
err.set_span(sp.shrink_to_hi());
err.span_label(sp.shrink_to_hi(), &note);
} else {
err.note(&note);
}
let file_empty = !tcx.sess.source_map().lookup_line(sp.hi()).is_ok();
if let Some(main_def) = tcx.resolutions(()).main_def && main_def.opt_fn_def_id().is_none(){
// There is something at `crate::main`, but it is not a function definition.
err.span_label(main_def.span, "non-function item at `crate::main` is found");
}
if tcx.sess.teach(&err.get_code().unwrap()) {
err.note(
"If you don't know the basics of Rust, you can go look to the Rust Book \
to get started: https://doc.rust-lang.org/book/",
);
}
err.emit();
tcx.sess.emit_err(NoMainErr {
sp,
crate_name: tcx.crate_name(LOCAL_CRATE),
has_filename,
filename,
file_empty,
non_main_fns: visitor.non_main_fns.clone(),
main_def_opt,
add_teach_note,
});
}
pub fn provide(providers: &mut Providers) {

View file

@ -1,6 +1,16 @@
use rustc_errors::{Applicability, MultiSpan};
use std::{
io::Error,
path::{Path, PathBuf},
};
use rustc_ast::Label;
use rustc_errors::{error_code, Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan};
use rustc_hir::{self as hir, ExprKind, Target};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_span::{Span, Symbol};
use rustc_middle::ty::{MainDefinition, Ty};
use rustc_span::{Span, Symbol, DUMMY_SP};
use crate::lang_items::Duplicate;
#[derive(LintDiagnostic)]
#[diag(passes::outer_crate_level_attr)]
@ -526,6 +536,15 @@ pub struct DebugVisualizerInvalid {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes::debug_visualizer_unreadable)]
pub struct DebugVisualizerUnreadable<'a> {
#[primary_span]
pub span: Span,
pub file: &'a Path,
pub error: Error,
}
#[derive(Diagnostic)]
#[diag(passes::rustc_allow_const_fn_unstable)]
pub struct RustcAllowConstFnUnstable {
@ -665,3 +684,765 @@ pub struct DeprecatedAnnotationHasNoEffect {
#[suggestion(applicability = "machine-applicable", code = "")]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes::unknown_external_lang_item, code = "E0264")]
pub struct UnknownExternLangItem {
#[primary_span]
pub span: Span,
pub lang_item: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes::missing_panic_handler)]
pub struct MissingPanicHandler;
#[derive(Diagnostic)]
#[diag(passes::alloc_func_required)]
pub struct AllocFuncRequired;
#[derive(Diagnostic)]
#[diag(passes::missing_alloc_error_handler)]
pub struct MissingAllocErrorHandler;
#[derive(Diagnostic)]
#[diag(passes::missing_lang_item)]
#[note]
#[help]
pub struct MissingLangItem {
pub name: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes::lang_item_on_incorrect_target, code = "E0718")]
pub struct LangItemOnIncorrectTarget {
#[primary_span]
#[label]
pub span: Span,
pub name: Symbol,
pub expected_target: Target,
pub actual_target: Target,
}
#[derive(Diagnostic)]
#[diag(passes::unknown_lang_item, code = "E0522")]
pub struct UnknownLangItem {
#[primary_span]
#[label]
pub span: Span,
pub name: Symbol,
}
pub struct InvalidAttrAtCrateLevel {
pub span: Span,
pub snippet: Option<String>,
pub name: Symbol,
}
impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
fn into_diagnostic(
self,
handler: &'_ rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag =
handler.struct_err(rustc_errors::fluent::passes::invalid_attr_at_crate_level);
diag.set_span(self.span);
diag.set_arg("name", self.name);
// Only emit an error with a suggestion if we can create a string out
// of the attribute span
if let Some(src) = self.snippet {
let replacement = src.replace("#!", "#");
diag.span_suggestion_verbose(
self.span,
rustc_errors::fluent::passes::suggestion,
replacement,
rustc_errors::Applicability::MachineApplicable,
);
}
diag
}
}
#[derive(Diagnostic)]
#[diag(passes::duplicate_diagnostic_item)]
pub struct DuplicateDiagnosticItem {
#[primary_span]
pub span: Span,
pub name: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes::duplicate_diagnostic_item_in_crate)]
pub struct DuplicateDiagnosticItemInCrate {
#[note(passes::diagnostic_item_first_defined)]
pub span: Option<Span>,
pub orig_crate_name: Symbol,
#[note]
pub have_orig_crate_name: Option<()>,
pub crate_name: Symbol,
pub name: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes::abi)]
pub struct Abi {
#[primary_span]
pub span: Span,
pub abi: String,
}
#[derive(Diagnostic)]
#[diag(passes::align)]
pub struct Align {
#[primary_span]
pub span: Span,
pub align: String,
}
#[derive(Diagnostic)]
#[diag(passes::size)]
pub struct Size {
#[primary_span]
pub span: Span,
pub size: String,
}
#[derive(Diagnostic)]
#[diag(passes::homogeneous_aggregate)]
pub struct HomogeneousAggregate {
#[primary_span]
pub span: Span,
pub homogeneous_aggregate: String,
}
#[derive(Diagnostic)]
#[diag(passes::layout_of)]
pub struct LayoutOf {
#[primary_span]
pub span: Span,
pub normalized_ty: String,
pub ty_layout: String,
}
#[derive(Diagnostic)]
#[diag(passes::unrecognized_field)]
pub struct UnrecognizedField {
#[primary_span]
pub span: Span,
pub name: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes::feature_stable_twice, code = "E0711")]
pub struct FeatureStableTwice {
#[primary_span]
pub span: Span,
pub feature: Symbol,
pub since: Symbol,
pub prev_since: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes::feature_previously_declared, code = "E0711")]
pub struct FeaturePreviouslyDeclared<'a, 'b> {
#[primary_span]
pub span: Span,
pub feature: Symbol,
pub declared: &'a str,
pub prev_declared: &'b str,
}
#[derive(Diagnostic)]
#[diag(passes::expr_not_allowed_in_context, code = "E0744")]
pub struct ExprNotAllowedInContext<'a> {
#[primary_span]
pub span: Span,
pub expr: String,
pub context: &'a str,
}
pub struct BreakNonLoop<'a> {
pub span: Span,
pub head: Option<Span>,
pub kind: &'a str,
pub suggestion: String,
pub loop_label: Option<Label>,
pub break_label: Option<Label>,
pub break_expr_kind: &'a ExprKind<'a>,
pub break_expr_span: Span,
}
impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> {
fn into_diagnostic(
self,
handler: &rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = handler.struct_span_err_with_code(
self.span,
rustc_errors::fluent::passes::break_non_loop,
error_code!(E0571),
);
diag.set_arg("kind", self.kind);
diag.span_label(self.span, rustc_errors::fluent::passes::label);
if let Some(head) = self.head {
diag.span_label(head, rustc_errors::fluent::passes::label2);
}
diag.span_suggestion(
self.span,
rustc_errors::fluent::passes::suggestion,
self.suggestion,
Applicability::MaybeIncorrect,
);
if let (Some(label), None) = (self.loop_label, self.break_label) {
match self.break_expr_kind {
ExprKind::Path(hir::QPath::Resolved(
None,
hir::Path { segments: [segment], res: hir::def::Res::Err, .. },
)) if label.ident.to_string() == format!("'{}", segment.ident) => {
// This error is redundant, we will have already emitted a
// suggestion to use the label when `segment` wasn't found
// (hence the `Res::Err` check).
diag.delay_as_bug();
}
_ => {
diag.span_suggestion(
self.break_expr_span,
rustc_errors::fluent::passes::break_expr_suggestion,
label.ident,
Applicability::MaybeIncorrect,
);
}
}
}
diag
}
}
#[derive(Diagnostic)]
#[diag(passes::continue_labeled_block, code = "E0696")]
pub struct ContinueLabeledBlock {
#[primary_span]
#[label]
pub span: Span,
#[label(passes::block_label)]
pub block_span: Span,
}
#[derive(Diagnostic)]
#[diag(passes::break_inside_closure, code = "E0267")]
pub struct BreakInsideClosure<'a> {
#[primary_span]
#[label]
pub span: Span,
#[label(passes::closure_label)]
pub closure_span: Span,
pub name: &'a str,
}
#[derive(Diagnostic)]
#[diag(passes::break_inside_async_block, code = "E0267")]
pub struct BreakInsideAsyncBlock<'a> {
#[primary_span]
#[label]
pub span: Span,
#[label(passes::async_block_label)]
pub closure_span: Span,
pub name: &'a str,
}
#[derive(Diagnostic)]
#[diag(passes::outside_loop, code = "E0268")]
pub struct OutsideLoop<'a> {
#[primary_span]
#[label]
pub span: Span,
pub name: &'a str,
}
#[derive(Diagnostic)]
#[diag(passes::unlabeled_in_labeled_block, code = "E0695")]
pub struct UnlabeledInLabeledBlock<'a> {
#[primary_span]
#[label]
pub span: Span,
pub cf_type: &'a str,
}
#[derive(Diagnostic)]
#[diag(passes::unlabeled_cf_in_while_condition, code = "E0590")]
pub struct UnlabeledCfInWhileCondition<'a> {
#[primary_span]
#[label]
pub span: Span,
pub cf_type: &'a str,
}
#[derive(Diagnostic)]
#[diag(passes::cannot_inline_naked_function)]
pub struct CannotInlineNakedFunction {
#[primary_span]
pub span: Span,
}
#[derive(LintDiagnostic)]
#[diag(passes::undefined_naked_function_abi)]
pub struct UndefinedNakedFunctionAbi;
#[derive(Diagnostic)]
#[diag(passes::no_patterns)]
pub struct NoPatterns {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes::params_not_allowed)]
#[help]
pub struct ParamsNotAllowed {
#[primary_span]
pub span: Span,
}
pub struct NakedFunctionsAsmBlock {
pub span: Span,
pub multiple_asms: Vec<Span>,
pub non_asms: Vec<Span>,
}
impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock {
fn into_diagnostic(
self,
handler: &rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = handler.struct_span_err_with_code(
self.span,
rustc_errors::fluent::passes::naked_functions_asm_block,
error_code!(E0787),
);
for span in self.multiple_asms.iter() {
diag.span_label(*span, rustc_errors::fluent::passes::label_multiple_asm);
}
for span in self.non_asms.iter() {
diag.span_label(*span, rustc_errors::fluent::passes::label_non_asm);
}
diag
}
}
#[derive(Diagnostic)]
#[diag(passes::naked_functions_operands, code = "E0787")]
pub struct NakedFunctionsOperands {
#[primary_span]
pub unsupported_operands: Vec<Span>,
}
#[derive(Diagnostic)]
#[diag(passes::naked_functions_asm_options, code = "E0787")]
pub struct NakedFunctionsAsmOptions {
#[primary_span]
pub span: Span,
pub unsupported_options: String,
}
#[derive(Diagnostic)]
#[diag(passes::naked_functions_must_use_noreturn, code = "E0787")]
pub struct NakedFunctionsMustUseNoreturn {
#[primary_span]
pub span: Span,
#[suggestion(code = ", options(noreturn)", applicability = "machine-applicable")]
pub last_span: Span,
}
#[derive(Diagnostic)]
#[diag(passes::attr_only_on_main)]
pub struct AttrOnlyOnMain {
#[primary_span]
pub span: Span,
pub attr: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes::attr_only_on_root_main)]
pub struct AttrOnlyOnRootMain {
#[primary_span]
pub span: Span,
pub attr: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes::attr_only_in_functions)]
pub struct AttrOnlyInFunctions {
#[primary_span]
pub span: Span,
pub attr: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes::multiple_rustc_main, code = "E0137")]
pub struct MultipleRustcMain {
#[primary_span]
pub span: Span,
#[label(passes::first)]
pub first: Span,
#[label(passes::additional)]
pub additional: Span,
}
#[derive(Diagnostic)]
#[diag(passes::multiple_start_functions, code = "E0138")]
pub struct MultipleStartFunctions {
#[primary_span]
pub span: Span,
#[label]
pub labeled: Span,
#[label(passes::previous)]
pub previous: Span,
}
#[derive(Diagnostic)]
#[diag(passes::extern_main)]
pub struct ExternMain {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes::unix_sigpipe_values)]
pub struct UnixSigpipeValues {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes::no_main_function, code = "E0601")]
pub struct NoMainFunction {
#[primary_span]
pub span: Span,
pub crate_name: String,
}
pub struct NoMainErr {
pub sp: Span,
pub crate_name: Symbol,
pub has_filename: bool,
pub filename: PathBuf,
pub file_empty: bool,
pub non_main_fns: Vec<Span>,
pub main_def_opt: Option<MainDefinition>,
pub add_teach_note: bool,
}
impl<'a> IntoDiagnostic<'a> for NoMainErr {
fn into_diagnostic(
self,
handler: &'a rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut diag = handler.struct_span_err_with_code(
DUMMY_SP,
rustc_errors::fluent::passes::no_main_function,
error_code!(E0601),
);
diag.set_arg("crate_name", self.crate_name);
diag.set_arg("filename", self.filename);
diag.set_arg("has_filename", self.has_filename);
let note = if !self.non_main_fns.is_empty() {
for &span in &self.non_main_fns {
diag.span_note(span, rustc_errors::fluent::passes::here_is_main);
}
diag.note(rustc_errors::fluent::passes::one_or_more_possible_main);
diag.help(rustc_errors::fluent::passes::consider_moving_main);
// There were some functions named `main` though. Try to give the user a hint.
rustc_errors::fluent::passes::main_must_be_defined_at_crate
} else if self.has_filename {
rustc_errors::fluent::passes::consider_adding_main_to_file
} else {
rustc_errors::fluent::passes::consider_adding_main_at_crate
};
if self.file_empty {
diag.note(note);
} else {
diag.set_span(self.sp.shrink_to_hi());
diag.span_label(self.sp.shrink_to_hi(), note);
}
if let Some(main_def) = self.main_def_opt && main_def.opt_fn_def_id().is_none(){
// There is something at `crate::main`, but it is not a function definition.
diag.span_label(main_def.span, rustc_errors::fluent::passes::non_function_main);
}
if self.add_teach_note {
diag.note(rustc_errors::fluent::passes::teach_note);
}
diag
}
}
pub struct DuplicateLangItem {
pub local_span: Option<Span>,
pub lang_item_name: Symbol,
pub crate_name: Symbol,
pub dependency_of: Symbol,
pub is_local: bool,
pub path: String,
pub first_defined_span: Option<Span>,
pub orig_crate_name: Symbol,
pub orig_dependency_of: Symbol,
pub orig_is_local: bool,
pub orig_path: String,
pub(crate) duplicate: Duplicate,
}
impl IntoDiagnostic<'_> for DuplicateLangItem {
fn into_diagnostic(
self,
handler: &rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = handler.struct_err_with_code(
match self.duplicate {
Duplicate::Plain => rustc_errors::fluent::passes::duplicate_lang_item,
Duplicate::Crate => rustc_errors::fluent::passes::duplicate_lang_item_crate,
Duplicate::CrateDepends => {
rustc_errors::fluent::passes::duplicate_lang_item_crate_depends
}
},
error_code!(E0152),
);
diag.set_arg("lang_item_name", self.lang_item_name);
diag.set_arg("crate_name", self.crate_name);
diag.set_arg("dependency_of", self.dependency_of);
diag.set_arg("path", self.path);
diag.set_arg("orig_crate_name", self.orig_crate_name);
diag.set_arg("orig_dependency_of", self.orig_dependency_of);
diag.set_arg("orig_path", self.orig_path);
if let Some(span) = self.local_span {
diag.set_span(span);
}
if let Some(span) = self.first_defined_span {
diag.span_note(span, rustc_errors::fluent::passes::first_defined_span);
} else {
if self.orig_dependency_of.is_empty() {
diag.note(rustc_errors::fluent::passes::first_defined_crate);
} else {
diag.note(rustc_errors::fluent::passes::first_defined_crate_depends);
}
if self.orig_is_local {
diag.note(rustc_errors::fluent::passes::first_definition_local);
} else {
diag.note(rustc_errors::fluent::passes::first_definition_path);
}
if self.is_local {
diag.note(rustc_errors::fluent::passes::second_definition_local);
} else {
diag.note(rustc_errors::fluent::passes::second_definition_path);
}
}
diag
}
}
#[derive(Diagnostic)]
#[diag(passes::incorrect_target, code = "E0718")]
pub struct IncorrectTarget<'a> {
#[primary_span]
pub span: Span,
#[label]
pub generics_span: Span,
pub name: &'a str, // cannot be symbol because it renders e.g. `r#fn` instead of `fn`
pub kind: &'static str,
pub num: usize,
pub actual_num: usize,
pub at_least: bool,
}
#[derive(LintDiagnostic)]
#[diag(passes::useless_assignment)]
pub struct UselessAssignment<'a> {
pub is_field_assign: bool,
pub ty: Ty<'a>,
}
#[derive(LintDiagnostic)]
#[diag(passes::only_has_effect_on)]
pub struct OnlyHasEffectOn {
pub attr_name: Symbol,
pub target_name: String,
}
#[derive(Diagnostic)]
#[diag(passes::object_lifetime_err)]
pub struct ObjectLifetimeErr {
#[primary_span]
pub span: Span,
pub repr: String,
}
#[derive(Diagnostic)]
#[diag(passes::unrecognized_repr_hint, code = "E0552")]
#[help]
pub struct UnrecognizedReprHint {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
pub enum AttrApplication {
#[diag(passes::attr_application_enum, code = "E0517")]
Enum {
#[primary_span]
hint_span: Span,
#[label]
span: Span,
},
#[diag(passes::attr_application_struct, code = "E0517")]
Struct {
#[primary_span]
hint_span: Span,
#[label]
span: Span,
},
#[diag(passes::attr_application_struct_union, code = "E0517")]
StructUnion {
#[primary_span]
hint_span: Span,
#[label]
span: Span,
},
#[diag(passes::attr_application_struct_enum_union, code = "E0517")]
StructEnumUnion {
#[primary_span]
hint_span: Span,
#[label]
span: Span,
},
#[diag(passes::attr_application_struct_enum_function_union, code = "E0517")]
StructEnumFunctionUnion {
#[primary_span]
hint_span: Span,
#[label]
span: Span,
},
}
#[derive(Diagnostic)]
#[diag(passes::transparent_incompatible, code = "E0692")]
pub struct TransparentIncompatible {
#[primary_span]
pub hint_spans: Vec<Span>,
pub target: String,
}
#[derive(Diagnostic)]
#[diag(passes::deprecated_attribute, code = "E0549")]
pub struct DeprecatedAttribute {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes::useless_stability)]
pub struct UselessStability {
#[primary_span]
#[label]
pub span: Span,
#[label(passes::item)]
pub item_sp: Span,
}
#[derive(Diagnostic)]
#[diag(passes::invalid_stability)]
pub struct InvalidStability {
#[primary_span]
#[label]
pub span: Span,
#[label(passes::item)]
pub item_sp: Span,
}
#[derive(Diagnostic)]
#[diag(passes::cannot_stabilize_deprecated)]
pub struct CannotStabilizeDeprecated {
#[primary_span]
#[label]
pub span: Span,
#[label(passes::item)]
pub item_sp: Span,
}
#[derive(Diagnostic)]
#[diag(passes::invalid_deprecation_version)]
pub struct InvalidDeprecationVersion {
#[primary_span]
#[label]
pub span: Span,
#[label(passes::item)]
pub item_sp: Span,
}
#[derive(Diagnostic)]
#[diag(passes::missing_stability_attr)]
pub struct MissingStabilityAttr<'a> {
#[primary_span]
pub span: Span,
pub descr: &'a str,
}
#[derive(Diagnostic)]
#[diag(passes::missing_const_stab_attr)]
pub struct MissingConstStabAttr<'a> {
#[primary_span]
pub span: Span,
pub descr: &'a str,
}
#[derive(Diagnostic)]
#[diag(passes::trait_impl_const_stable)]
#[note]
pub struct TraitImplConstStable {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes::feature_only_on_nightly, code = "E0554")]
pub struct FeatureOnlyOnNightly {
#[primary_span]
pub span: Span,
pub release_channel: &'static str,
}
#[derive(Diagnostic)]
#[diag(passes::unknown_feature, code = "E0635")]
pub struct UnknownFeature {
#[primary_span]
pub span: Span,
pub feature: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes::implied_feature_not_exist)]
pub struct ImpliedFeatureNotExist {
#[primary_span]
pub span: Span,
pub feature: Symbol,
pub implied_by: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes::duplicate_feature_err, code = "E0636")]
pub struct DuplicateFeatureErr {
#[primary_span]
pub span: Span,
pub feature: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes::missing_const_err)]
pub struct MissingConstErr {
#[primary_span]
#[help]
pub fn_sig_span: Span,
#[label]
pub const_span: Span,
}

View file

@ -8,9 +8,11 @@
//! * Functions called by the compiler itself.
use crate::check_attr::target_from_impl_item;
use crate::errors::{
DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem,
};
use crate::weak_lang_items;
use rustc_errors::{pluralize, struct_span_err};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
@ -18,10 +20,16 @@ use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS};
use rustc_hir::{HirId, LangItem, LanguageItems, Target};
use rustc_middle::ty::TyCtxt;
use rustc_session::cstore::ExternCrate;
use rustc_span::Span;
use rustc_span::{symbol::kw::Empty, Span};
use rustc_middle::ty::query::Providers;
pub(crate) enum Duplicate {
Plain,
Crate,
CrateDepends,
}
struct LanguageItemCollector<'tcx> {
items: LanguageItems,
tcx: TyCtxt<'tcx>,
@ -34,42 +42,24 @@ impl<'tcx> LanguageItemCollector<'tcx> {
fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
let attrs = self.tcx.hir().attrs(hir_id);
if let Some((value, span)) = extract(&attrs) {
match ITEM_REFS.get(&value).cloned() {
if let Some((name, span)) = extract(&attrs) {
match ITEM_REFS.get(&name).cloned() {
// Known lang item with attribute on correct target.
Some((item_index, expected_target)) if actual_target == expected_target => {
self.collect_item_extended(item_index, hir_id, span);
}
// Known lang item with attribute on incorrect target.
Some((_, expected_target)) => {
struct_span_err!(
self.tcx.sess,
self.tcx.sess.emit_err(LangItemOnIncorrectTarget {
span,
E0718,
"`{}` language item must be applied to a {}",
value,
name,
expected_target,
)
.span_label(
span,
format!(
"attribute should be applied to a {}, not a {}",
expected_target, actual_target,
),
)
.emit();
actual_target,
});
}
// Unknown lang item.
_ => {
struct_span_err!(
self.tcx.sess,
span,
E0522,
"definition of an unknown language item: `{}`",
value
)
.span_label(span, format!("definition of unknown language item `{}`", value))
.emit();
self.tcx.sess.emit_err(UnknownLangItem { span, name });
}
}
}
@ -79,74 +69,72 @@ impl<'tcx> LanguageItemCollector<'tcx> {
// Check for duplicates.
if let Some(original_def_id) = self.items.items[item_index] {
if original_def_id != item_def_id {
let lang_item = LangItem::from_u32(item_index as u32).unwrap();
let name = lang_item.name();
let mut err = match self.tcx.hir().span_if_local(item_def_id) {
Some(span) => struct_span_err!(
self.tcx.sess,
span,
E0152,
"found duplicate lang item `{}`",
name
),
None => match self.tcx.extern_crate(item_def_id) {
Some(ExternCrate { dependency_of, .. }) => {
self.tcx.sess.struct_err(&format!(
"duplicate lang item in crate `{}` (which `{}` depends on): `{}`.",
self.tcx.crate_name(item_def_id.krate),
self.tcx.crate_name(*dependency_of),
name
))
}
_ => self.tcx.sess.struct_err(&format!(
"duplicate lang item in crate `{}`: `{}`.",
self.tcx.crate_name(item_def_id.krate),
name
)),
},
};
if let Some(span) = self.tcx.hir().span_if_local(original_def_id) {
err.span_note(span, "the lang item is first defined here");
let local_span = self.tcx.hir().span_if_local(item_def_id);
let lang_item_name = LangItem::from_u32(item_index as u32).unwrap().name();
let crate_name = self.tcx.crate_name(item_def_id.krate);
let mut dependency_of = Empty;
let is_local = item_def_id.is_local();
let path = if is_local {
String::new()
} else {
match self.tcx.extern_crate(original_def_id) {
Some(ExternCrate { dependency_of, .. }) => {
err.note(&format!(
"the lang item is first defined in crate `{}` (which `{}` depends on)",
self.tcx.crate_name(original_def_id.krate),
self.tcx.crate_name(*dependency_of)
));
}
_ => {
err.note(&format!(
"the lang item is first defined in crate `{}`.",
self.tcx.crate_name(original_def_id.krate)
));
}
self.tcx
.crate_extern_paths(item_def_id.krate)
.iter()
.map(|p| p.display().to_string())
.collect::<Vec<_>>()
.join(", ")
.into()
};
let first_defined_span = self.tcx.hir().span_if_local(original_def_id);
let mut orig_crate_name = Empty;
let mut orig_dependency_of = Empty;
let orig_is_local = original_def_id.is_local();
let orig_path = if orig_is_local {
String::new()
} else {
self.tcx
.crate_extern_paths(original_def_id.krate)
.iter()
.map(|p| p.display().to_string())
.collect::<Vec<_>>()
.join(", ")
.into()
};
if first_defined_span.is_none() {
orig_crate_name = self.tcx.crate_name(original_def_id.krate);
if let Some(ExternCrate { dependency_of: inner_dependency_of, .. }) =
self.tcx.extern_crate(original_def_id)
{
orig_dependency_of = self.tcx.crate_name(*inner_dependency_of);
}
let mut note_def = |which, def_id: DefId| {
let crate_name = self.tcx.crate_name(def_id.krate);
let note = if def_id.is_local() {
format!("{} definition in the local crate (`{}`)", which, crate_name)
} else {
let paths: Vec<_> = self
.tcx
.crate_extern_paths(def_id.krate)
.iter()
.map(|p| p.display().to_string())
.collect();
format!(
"{} definition in `{}` loaded from {}",
which,
crate_name,
paths.join(", ")
)
};
err.note(&note);
};
note_def("first", original_def_id);
note_def("second", item_def_id);
}
err.emit();
let duplicate = if local_span.is_some() {
Duplicate::Plain
} else {
match self.tcx.extern_crate(item_def_id) {
Some(ExternCrate { dependency_of: inner_dependency_of, .. }) => {
dependency_of = self.tcx.crate_name(*inner_dependency_of);
Duplicate::CrateDepends
}
_ => Duplicate::Crate,
}
};
self.tcx.sess.emit_err(DuplicateLangItem {
local_span,
lang_item_name,
crate_name,
dependency_of,
is_local,
path,
first_defined_span,
orig_crate_name,
orig_dependency_of,
orig_is_local,
orig_path,
duplicate,
});
}
}
@ -179,41 +167,30 @@ impl<'tcx> LanguageItemCollector<'tcx> {
None => (0, *item_span),
};
let mut at_least = false;
let required = match lang_item.required_generics() {
GenericRequirement::Exact(num) if num != actual_num => {
Some((format!("{}", num), pluralize!(num)))
}
GenericRequirement::Exact(num) if num != actual_num => Some(num),
GenericRequirement::Minimum(num) if actual_num < num => {
Some((format!("at least {}", num), pluralize!(num)))
}
at_least = true;
Some(num)}
,
// If the number matches, or there is no requirement, handle it normally
_ => None,
};
if let Some((range_str, pluralized)) = required {
if let Some(num) = required {
// We are issuing E0718 "incorrect target" here, because while the
// item kind of the target is correct, the target is still wrong
// because of the wrong number of generic arguments.
struct_span_err!(
self.tcx.sess,
self.tcx.sess.emit_err(IncorrectTarget {
span,
E0718,
"`{}` language item must be applied to a {} with {} generic argument{}",
name,
kind.descr(),
range_str,
pluralized,
)
.span_label(
generics_span,
format!(
"this {} has {} generic argument{}",
kind.descr(),
actual_num,
pluralize!(actual_num),
),
)
.emit();
name: name.as_str(),
kind: kind.descr(),
num,
actual_num,
at_least,
});
// return early to not collect the lang item
return;

View file

@ -3,10 +3,13 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::abi::{HasDataLayout, TargetDataLayout};
use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField};
pub fn test_layout(tcx: TyCtxt<'_>) {
if tcx.features().rustc_attrs {
// if the `rustc_attrs` feature is not enabled, don't bother testing layout
@ -35,62 +38,64 @@ fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attri
for meta_item in meta_items {
match meta_item.name_or_empty() {
sym::abi => {
tcx.sess.span_err(
tcx.def_span(item_def_id.to_def_id()),
&format!("abi: {:?}", ty_layout.abi),
);
tcx.sess.emit_err(Abi {
span: tcx.def_span(item_def_id.to_def_id()),
abi: format!("{:?}", ty_layout.abi),
});
}
sym::align => {
tcx.sess.span_err(
tcx.def_span(item_def_id.to_def_id()),
&format!("align: {:?}", ty_layout.align),
);
tcx.sess.emit_err(Align {
span: tcx.def_span(item_def_id.to_def_id()),
align: format!("{:?}", ty_layout.align),
});
}
sym::size => {
tcx.sess.span_err(
tcx.def_span(item_def_id.to_def_id()),
&format!("size: {:?}", ty_layout.size),
);
tcx.sess.emit_err(Size {
span: tcx.def_span(item_def_id.to_def_id()),
size: format!("{:?}", ty_layout.size),
});
}
sym::homogeneous_aggregate => {
tcx.sess.span_err(
tcx.def_span(item_def_id.to_def_id()),
&format!(
"homogeneous_aggregate: {:?}",
ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
tcx.sess.emit_err(HomogeneousAggregate {
span: tcx.def_span(item_def_id.to_def_id()),
homogeneous_aggregate: format!(
"{:?}",
ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env })
),
);
});
}
sym::debug => {
let normalized_ty = tcx.normalize_erasing_regions(
param_env.with_reveal_all_normalized(tcx),
ty,
);
tcx.sess.span_err(
tcx.def_span(item_def_id.to_def_id()),
&format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
let normalized_ty = format!(
"{:?}",
tcx.normalize_erasing_regions(
param_env.with_reveal_all_normalized(tcx),
ty,
)
);
let ty_layout = format!("{:#?}", *ty_layout);
tcx.sess.emit_err(LayoutOf {
span: tcx.def_span(item_def_id.to_def_id()),
normalized_ty,
ty_layout,
});
}
name => {
tcx.sess.span_err(
meta_item.span(),
&format!("unrecognized field name `{}`", name),
);
tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
}
}
}
}
Err(layout_error) => {
tcx.sess.span_err(
tcx.def_span(item_def_id.to_def_id()),
&format!("layout error: {:?}", layout_error),
);
tcx.sess.emit_fatal(Spanned {
node: layout_error,
span: tcx.def_span(item_def_id.to_def_id()),
});
}
}
}

View file

@ -5,6 +5,8 @@
//! This API is completely unstable and subject to change.
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(iter_intersperse)]
#![feature(let_chains)]

View file

@ -6,7 +6,6 @@
use rustc_ast::{Attribute, MetaItemKind};
use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER};
use rustc_errors::struct_span_err;
use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::lib_features::LibFeatures;
@ -15,6 +14,8 @@ use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
use rustc_span::{sym, Span};
use crate::errors::{FeaturePreviouslyDeclared, FeatureStableTwice};
fn new_lib_features() -> LibFeatures {
LibFeatures { stable: Default::default(), unstable: Default::default() }
}
@ -92,14 +93,12 @@ impl<'tcx> LibFeatureCollector<'tcx> {
(Some(since), _, false) => {
if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) {
if *prev_since != since {
self.span_feature_error(
self.tcx.sess.emit_err(FeatureStableTwice {
span,
&format!(
"feature `{}` is declared stable since {}, \
but was previously declared stable since {}",
feature, since, prev_since,
),
);
feature,
since,
prev_since: *prev_since,
});
return;
}
}
@ -110,22 +109,17 @@ impl<'tcx> LibFeatureCollector<'tcx> {
self.lib_features.unstable.insert(feature, span);
}
(Some(_), _, true) | (None, true, _) => {
self.span_feature_error(
let declared = if since.is_some() { "stable" } else { "unstable" };
let prev_declared = if since.is_none() { "stable" } else { "unstable" };
self.tcx.sess.emit_err(FeaturePreviouslyDeclared {
span,
&format!(
"feature `{}` is declared {}, but was previously declared {}",
feature,
if since.is_some() { "stable" } else { "unstable" },
if since.is_none() { "stable" } else { "unstable" },
),
);
feature,
declared,
prev_declared,
});
}
}
}
fn span_feature_error(&self, span: Span, msg: &str) {
struct_span_err!(self.tcx.sess, span, E0711, "{}", &msg).emit();
}
}
impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> {

View file

@ -1,6 +1,5 @@
use Context::*;
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
@ -13,6 +12,11 @@ use rustc_session::Session;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::Span;
use crate::errors::{
BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
};
#[derive(Clone, Copy, Debug, PartialEq)]
enum Context {
Normal,
@ -90,7 +94,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
Ok(loop_id) => Some(loop_id),
Err(hir::LoopIdError::OutsideLoopScope) => None,
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
self.emit_unlabled_cf_in_while_condition(e.span, "break");
self.sess.emit_err(UnlabeledCfInWhileCondition {
span: e.span,
cf_type: "break",
});
None
}
Err(hir::LoopIdError::UnresolvedLabel) => None,
@ -116,69 +123,22 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
match loop_kind {
None | Some(hir::LoopSource::Loop) => (),
Some(kind) => {
let mut err = struct_span_err!(
self.sess,
e.span,
E0571,
"`break` with value from a `{}` loop",
kind.name()
let suggestion = format!(
"break{}",
break_label
.label
.map_or_else(String::new, |l| format!(" {}", l.ident))
);
err.span_label(
e.span,
"can only break with a value inside `loop` or breakable block",
);
if let Some(head) = head {
err.span_label(
head,
&format!(
"you can't `break` with a value in a `{}` loop",
kind.name()
),
);
}
err.span_suggestion(
e.span,
&format!(
"use `break` on its own without a value inside this `{}` loop",
kind.name(),
),
format!(
"break{}",
break_label
.label
.map_or_else(String::new, |l| format!(" {}", l.ident))
),
Applicability::MaybeIncorrect,
);
if let (Some(label), None) = (loop_label, break_label.label) {
match break_expr.kind {
hir::ExprKind::Path(hir::QPath::Resolved(
None,
hir::Path {
segments: [segment],
res: hir::def::Res::Err,
..
},
)) if label.ident.to_string()
== format!("'{}", segment.ident) =>
{
// This error is redundant, we will have already emitted a
// suggestion to use the label when `segment` wasn't found
// (hence the `Res::Err` check).
err.delay_as_bug();
}
_ => {
err.span_suggestion(
break_expr.span,
"alternatively, you might have meant to use the \
available loop label",
label.ident,
Applicability::MaybeIncorrect,
);
}
}
}
err.emit();
self.sess.emit_err(BreakNonLoop {
span: e.span,
head,
kind: kind.name(),
suggestion,
loop_label,
break_label: break_label.label,
break_expr_kind: &break_expr.kind,
break_expr_span: break_expr.span,
});
}
}
}
@ -191,19 +151,17 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
match destination.target_id {
Ok(loop_id) => {
if let Node::Block(block) = self.hir_map.find(loop_id).unwrap() {
struct_span_err!(
self.sess,
e.span,
E0696,
"`continue` pointing to a labeled block"
)
.span_label(e.span, "labeled blocks cannot be `continue`'d")
.span_label(block.span, "labeled block the `continue` points to")
.emit();
self.sess.emit_err(ContinueLabeledBlock {
span: e.span,
block_span: block.span,
});
}
}
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
self.emit_unlabled_cf_in_while_condition(e.span, "continue");
self.sess.emit_err(UnlabeledCfInWhileCondition {
span: e.span,
cf_type: "continue",
});
}
Err(_) => {}
}
@ -226,21 +184,16 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
}
fn require_break_cx(&self, name: &str, span: Span) {
let err_inside_of = |article, ty, closure_span| {
struct_span_err!(self.sess, span, E0267, "`{}` inside of {} {}", name, article, ty)
.span_label(span, format!("cannot `{}` inside of {} {}", name, article, ty))
.span_label(closure_span, &format!("enclosing {}", ty))
.emit();
};
match self.cx {
LabeledBlock | Loop(_) => {}
Closure(closure_span) => err_inside_of("a", "closure", closure_span),
AsyncClosure(closure_span) => err_inside_of("an", "`async` block", closure_span),
Closure(closure_span) => {
self.sess.emit_err(BreakInsideClosure { span, closure_span, name });
}
AsyncClosure(closure_span) => {
self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name });
}
Normal | AnonConst => {
struct_span_err!(self.sess, span, E0268, "`{}` outside of a loop", name)
.span_label(span, format!("cannot `{}` outside of a loop", name))
.emit();
self.sess.emit_err(OutsideLoop { span, name });
}
}
}
@ -251,37 +204,13 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
label: &Destination,
cf_type: &str,
) -> bool {
if !span.is_desugaring(DesugaringKind::QuestionMark) && self.cx == LabeledBlock {
if label.label.is_none() {
struct_span_err!(
self.sess,
span,
E0695,
"unlabeled `{}` inside of a labeled block",
cf_type
)
.span_label(
span,
format!(
"`{}` statements that would diverge to or through \
a labeled block need to bear a label",
cf_type
),
)
.emit();
return true;
}
if !span.is_desugaring(DesugaringKind::QuestionMark)
&& self.cx == LabeledBlock
&& label.label.is_none()
{
self.sess.emit_err(UnlabeledInLabeledBlock { span, cf_type });
return true;
}
false
}
fn emit_unlabled_cf_in_while_condition(&mut self, span: Span, cf_type: &str) {
struct_span_err!(
self.sess,
span,
E0590,
"`break` or `continue` with no label in the condition of a `while` loop"
)
.span_label(span, format!("unlabeled `{}` in the condition of a `while` loop", cf_type))
.emit();
}
}

View file

@ -1,7 +1,6 @@
//! Checks validity of naked functions.
use rustc_ast::InlineAsmOptions;
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
@ -14,6 +13,12 @@ use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
use crate::errors::{
CannotInlineNakedFunction, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions,
NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed,
UndefinedNakedFunctionAbi,
};
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { check_mod_naked_functions, ..*providers };
}
@ -56,7 +61,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline);
for attr in attrs {
tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
tcx.sess.emit_err(CannotInlineNakedFunction { span: attr.span });
}
}
@ -65,12 +70,11 @@ fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
if abi == Abi::Rust {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let span = tcx.def_span(def_id);
tcx.struct_span_lint_hir(
tcx.emit_spanned_lint(
UNDEFINED_NAKED_FUNCTION_ABI,
hir_id,
span,
"Rust ABI is unsupported in naked functions",
|lint| lint,
UndefinedNakedFunctionAbi,
);
}
}
@ -82,12 +86,7 @@ fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
hir::PatKind::Wild
| hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, _, None) => {}
_ => {
tcx.sess
.struct_span_err(
param.pat.span,
"patterns not allowed in naked function parameters",
)
.emit();
tcx.sess.emit_err(NoPatterns { span: param.pat.span });
}
}
}
@ -117,14 +116,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
)) = expr.kind
{
if self.params.contains(var_hir_id) {
self.tcx
.sess
.struct_span_err(
expr.span,
"referencing function parameters is not allowed in naked functions",
)
.help("follow the calling convention in asm block to use parameters")
.emit();
self.tcx.sess.emit_err(ParamsNotAllowed { span: expr.span });
return;
}
}
@ -139,26 +131,21 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<
if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
// Ok.
} else {
let mut diag = struct_span_err!(
tcx.sess,
tcx.def_span(def_id),
E0787,
"naked functions must contain a single asm block"
);
let mut must_show_error = false;
let mut has_asm = false;
let mut has_err = false;
let mut multiple_asms = vec![];
let mut non_asms = vec![];
for &(kind, span) in &this.items {
match kind {
ItemKind::Asm if has_asm => {
must_show_error = true;
diag.span_label(span, "multiple asm blocks are unsupported in naked functions");
multiple_asms.push(span);
}
ItemKind::Asm => has_asm = true,
ItemKind::NonAsm => {
must_show_error = true;
diag.span_label(span, "non-asm is unsupported in naked functions");
non_asms.push(span);
}
ItemKind::Err => has_err = true,
}
@ -168,9 +155,11 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<
// errors, then don't show an additional error. This allows for appending/prepending
// `compile_error!("...")` statements and reduces error noise.
if must_show_error || !has_err {
diag.emit();
} else {
diag.cancel();
tcx.sess.emit_err(NakedFunctionsAsmBlock {
span: tcx.def_span(def_id),
multiple_asms,
non_asms,
});
}
}
}
@ -251,13 +240,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
})
.collect();
if !unsupported_operands.is_empty() {
struct_span_err!(
self.tcx.sess,
unsupported_operands,
E0787,
"only `const` and `sym` operands are supported in naked functions",
)
.emit();
self.tcx.sess.emit_err(NakedFunctionsOperands { unsupported_operands });
}
let unsupported_options: Vec<&'static str> = [
@ -273,14 +256,10 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
.collect();
if !unsupported_options.is_empty() {
struct_span_err!(
self.tcx.sess,
self.tcx.sess.emit_err(NakedFunctionsAsmOptions {
span,
E0787,
"asm options unsupported in naked functions: {}",
unsupported_options.join(", ")
)
.emit();
unsupported_options: unsupported_options.join(", "),
});
}
if !asm.options.contains(InlineAsmOptions::NORETURN) {
@ -290,20 +269,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
.map_or_else(|| asm.template_strs.last().unwrap().2, |op| op.1)
.shrink_to_hi();
struct_span_err!(
self.tcx.sess,
span,
E0787,
"asm in naked functions must use `noreturn` option"
)
.span_suggestion(
last_span,
"consider specifying that the asm block is responsible \
for returning from the function",
", options(noreturn)",
Applicability::MachineApplicable,
)
.emit();
self.tcx.sess.emit_err(NakedFunctionsMustUseNoreturn { span, last_span });
}
}
}

View file

@ -1,13 +1,18 @@
//! A pass that annotates every item and method with its stability level,
//! propagating default levels lexically from parent to children ast nodes.
use crate::errors;
use crate::errors::{
self, CannotStabilizeDeprecated, DeprecatedAttribute, DuplicateFeatureErr,
FeatureOnlyOnNightly, ImpliedFeatureNotExist, InvalidDeprecationVersion, InvalidStability,
MissingConstErr, MissingConstStabAttr, MissingStabilityAttr, TraitImplConstStable,
UnknownFeature, UselessStability,
};
use rustc_attr::{
self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable,
UnstableReason, VERSION_PLACEHOLDER,
};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_errors::{struct_span_err, Applicability};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@ -20,7 +25,6 @@ use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
use rustc_middle::ty::{query::Providers, TyCtxt};
use rustc_session::lint;
use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
@ -179,7 +183,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
if !self.in_trait_impl
|| (self.in_trait_impl && !self.tcx.is_const_fn_raw(def_id.to_def_id()))
{
missing_const_err(&self.tcx.sess, fn_sig.span, const_span);
self.tcx
.sess
.emit_err(MissingConstErr { fn_sig_span: fn_sig.span, const_span });
}
}
}
@ -197,14 +203,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
if let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr {
if stab.is_none() {
struct_span_err!(
self.tcx.sess,
*span,
E0549,
"deprecated attribute must be paired with \
either stable or unstable attribute"
)
.emit();
self.tcx.sess.emit_err(DeprecatedAttribute { span: *span });
}
}
@ -220,10 +219,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
if kind == AnnotationKind::Prohibited
|| (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
{
self.tcx.sess.struct_span_err(span,"this stability annotation is useless")
.span_label(span, "useless stability annotation")
.span_label(item_sp, "the stability attribute annotates this item")
.emit();
self.tcx.sess.emit_err(UselessStability { span, item_sp });
}
debug!("annotate: found {:?}", stab);
@ -239,19 +235,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
{
match stab_v.parse::<u64>() {
Err(_) => {
self.tcx.sess.struct_span_err(span, "invalid stability version found")
.span_label(span, "invalid stability version")
.span_label(item_sp, "the stability attribute annotates this item")
.emit();
self.tcx.sess.emit_err(InvalidStability { span, item_sp });
break;
}
Ok(stab_vp) => match dep_v.parse::<u64>() {
Ok(dep_vp) => match dep_vp.cmp(&stab_vp) {
Ordering::Less => {
self.tcx.sess.struct_span_err(span, "an API can't be stabilized after it is deprecated")
.span_label(span, "invalid version")
.span_label(item_sp, "the stability attribute annotates this item")
.emit();
self.tcx
.sess
.emit_err(CannotStabilizeDeprecated { span, item_sp });
break;
}
Ordering::Equal => continue,
@ -259,10 +251,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
},
Err(_) => {
if dep_v != "TBD" {
self.tcx.sess.struct_span_err(span, "invalid deprecation version found")
.span_label(span, "invalid deprecation version")
.span_label(item_sp, "the stability attribute annotates this item")
.emit();
self.tcx
.sess
.emit_err(InvalidDeprecationVersion { span, item_sp });
}
break;
}
@ -271,7 +262,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
}
}
if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = stab {
if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } =
stab
{
self.index.implications.insert(implied_by, feature);
}
@ -531,7 +524,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
let stab = self.tcx.stability().local_stability(def_id);
if !self.tcx.sess.opts.test && stab.is_none() && self.access_levels.is_reachable(def_id) {
let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
self.tcx.sess.span_err(span, &format!("{} has missing stability attribute", descr));
self.tcx.sess.emit_err(MissingStabilityAttr { span, descr });
}
}
@ -551,7 +544,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
if is_const && is_stable && missing_const_stability_attribute && is_reachable {
let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
self.tcx.sess.span_err(span, &format!("{descr} has missing const stability attribute"));
self.tcx.sess.emit_err(MissingConstStabAttr { span, descr });
}
}
}
@ -764,11 +757,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
&& *constness == hir::Constness::Const
&& const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
{
self.tcx
.sess
.struct_span_err(item.span, "trait implementations cannot be const stable yet")
.note("see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information")
.emit();
self.tcx.sess.emit_err(TraitImplConstStable { span: item.span });
}
}
@ -929,7 +918,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
}
if !lang_features.insert(feature) {
// Warn if the user enables a lang feature multiple times.
duplicate_feature_err(tcx.sess, span, feature);
tcx.sess.emit_err(DuplicateFeatureErr { span, feature });
}
}
@ -937,18 +926,14 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
let mut remaining_lib_features = FxIndexMap::default();
for (feature, span) in declared_lib_features {
if !tcx.sess.opts.unstable_features.is_nightly_build() {
struct_span_err!(
tcx.sess,
*span,
E0554,
"`#![feature]` may not be used on the {} release channel",
env!("CFG_RELEASE_CHANNEL")
)
.emit();
tcx.sess.emit_err(FeatureOnlyOnNightly {
span: *span,
release_channel: env!("CFG_RELEASE_CHANNEL"),
});
}
if remaining_lib_features.contains_key(&feature) {
// Warn if the user enables a lib feature multiple times.
duplicate_feature_err(tcx.sess, *span, *feature);
tcx.sess.emit_err(DuplicateFeatureErr { span: *span, feature: *feature });
}
remaining_lib_features.insert(feature, *span);
}
@ -1049,23 +1034,18 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
}
for (feature, span) in remaining_lib_features {
struct_span_err!(tcx.sess, span, E0635, "unknown feature `{}`", feature).emit();
tcx.sess.emit_err(UnknownFeature { span, feature: *feature });
}
for (implied_by, feature) in remaining_implications {
let local_defined_features = tcx.lib_features(());
let span = local_defined_features
let span = *local_defined_features
.stable
.get(&feature)
.map(|(_, span)| span)
.or_else(|| local_defined_features.unstable.get(&feature))
.expect("feature that implied another does not exist");
tcx.sess
.struct_span_err(
*span,
format!("feature `{implied_by}` implying `{feature}` does not exist"),
)
.emit();
tcx.sess.emit_err(ImpliedFeatureNotExist { span, feature, implied_by });
}
// FIXME(#44232): the `used_features` table no longer exists, so we
@ -1088,21 +1068,20 @@ fn unnecessary_partially_stable_feature_lint(
by the feature `{implies}`"
),
|lint| {
lint
.span_suggestion(
span,
&format!(
lint.span_suggestion(
span,
&format!(
"if you are using features which are still unstable, change to using `{implies}`"
),
implies,
Applicability::MaybeIncorrect,
)
.span_suggestion(
tcx.sess.source_map().span_extend_to_line(span),
"if you are using features which are now stable, remove this line",
"",
Applicability::MaybeIncorrect,
)
implies,
Applicability::MaybeIncorrect,
)
.span_suggestion(
tcx.sess.source_map().span_extend_to_line(span),
"if you are using features which are now stable, remove this line",
"",
Applicability::MaybeIncorrect,
)
},
);
}
@ -1120,20 +1099,3 @@ fn unnecessary_stable_feature_lint(
lint
});
}
fn duplicate_feature_err(sess: &Session, span: Span, feature: Symbol) {
struct_span_err!(sess, span, E0636, "the feature `{}` has already been declared", feature)
.emit();
}
fn missing_const_err(session: &Session, fn_sig_span: Span, const_span: Span) {
const ERROR_MSG: &'static str = "attributes `#[rustc_const_unstable]` \
and `#[rustc_const_stable]` require \
the function or method to be `const`";
session
.struct_span_err(fn_sig_span, ERROR_MSG)
.span_help(fn_sig_span, "make the function or method const")
.span_label(const_span, "attribute specified here")
.emit();
}

View file

@ -1,13 +1,17 @@
//! Validity checking for weak lang items
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir::lang_items::{self, LangItem};
use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
use rustc_middle::middle::lang_items::required;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::CrateType;
use crate::errors::{
AllocFuncRequired, MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler,
UnknownExternLangItem,
};
/// Checks the crate for usage of weak lang items, returning a vector of all the
/// language items required by this crate, but not defined yet.
pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItems) {
@ -31,14 +35,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem
}
} else {
let span = tcx.def_span(id.def_id);
struct_span_err!(
tcx.sess,
span,
E0264,
"unknown external lang item: `{}`",
lang_item
)
.emit();
tcx.sess.emit_err(UnknownExternLangItem { span, lang_item });
}
}
}
@ -71,20 +68,14 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
for (name, &item) in WEAK_ITEMS_REFS.iter() {
if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() {
if item == LangItem::PanicImpl {
tcx.sess.err("`#[panic_handler]` function required, but not found");
tcx.sess.emit_err(MissingPanicHandler);
} else if item == LangItem::Oom {
if !tcx.features().default_alloc_error_handler {
tcx.sess.err("`#[alloc_error_handler]` function required, but not found");
tcx.sess.note_without_error("use `#![feature(default_alloc_error_handler)]` for a default error handler");
tcx.sess.emit_err(AllocFuncRequired);
tcx.sess.emit_note(MissingAllocErrorHandler);
}
} else {
tcx
.sess
.diagnostic()
.struct_err(&format!("language item required, but not found: `{}`", name))
.note(&format!("this can occur when a binary crate with `#![no_std]` is compiled for a target where `{}` is defined in the standard library", name))
.help(&format!("you may be able to compile for a target that doesn't need `{}`, specify a target with `--target` or in `.cargo/config`", name))
.emit();
tcx.sess.emit_err(MissingLangItem { name: *name });
}
}
}

View file

@ -12,7 +12,7 @@ use rustc_data_structures::sync::{Lock, Lrc};
use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
use rustc_errors::{
fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, StashKey,
EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey,
};
use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
use rustc_span::edition::Edition;
@ -354,6 +354,17 @@ impl ParseSess {
self.create_warning(warning).emit()
}
pub fn create_note<'a>(
&'a self,
note: impl IntoDiagnostic<'a, Noted>,
) -> DiagnosticBuilder<'a, Noted> {
note.into_diagnostic(&self.span_diagnostic)
}
pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
self.create_note(note).emit()
}
pub fn create_fatal<'a>(
&'a self,
fatal: impl IntoDiagnostic<'a, !>,

View file

@ -28,7 +28,7 @@ use rustc_errors::json::JsonEmitter;
use rustc_errors::registry::Registry;
use rustc_errors::{
error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan,
ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
};
use rustc_macros::HashStable_Generic;
pub use rustc_span::def_id::StableCrateId;
@ -489,6 +489,15 @@ impl Session {
pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
self.parse_sess.emit_warning(warning)
}
pub fn create_note<'a>(
&'a self,
note: impl IntoDiagnostic<'a, Noted>,
) -> DiagnosticBuilder<'a, Noted> {
self.parse_sess.create_note(note)
}
pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
self.parse_sess.emit_note(note)
}
pub fn create_fatal<'a>(
&'a self,
fatal: impl IntoDiagnostic<'a, !>,

View file

@ -4,6 +4,6 @@ use std::borrow::Cow;
#[rustc_layout(debug)]
type Edges<'a, E> = Cow<'a, [E]>;
//~^ ERROR layout error: NormalizationFailure
//~^ 6:1: 6:18: unable to determine layout for `<[E] as ToOwned>::Owned` because `<[E] as ToOwned>::Owned` cannot be normalized
fn main() {}

View file

@ -1,4 +1,4 @@
error: layout error: NormalizationFailure(<[E] as std::borrow::ToOwned>::Owned, Type(<[E] as std::borrow::ToOwned>::Owned))
error: unable to determine layout for `<[E] as ToOwned>::Owned` because `<[E] as ToOwned>::Owned` cannot be normalized
--> $DIR/issue-85103.rs:6:1
|
LL | type Edges<'a, E> = Cow<'a, [E]>;