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:
commit
32471a7035
24 changed files with 1793 additions and 756 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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`].
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(), ¬e);
|
||||
} else {
|
||||
err.note(¬e);
|
||||
}
|
||||
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) {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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(¬e);
|
||||
};
|
||||
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;
|
||||
|
|
|
@ -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()),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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, !>,
|
||||
|
|
|
@ -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, !>,
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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]>;
|
||||
|
|
Loading…
Add table
Reference in a new issue