Auto merge of #102948 - Dylan-DPC:rollup-j8h74rb, r=Dylan-DPC
Rollup of 8 pull requests Successful merges: - #102110 (Migrate rustc_passes diagnostics) - #102187 (Use correct location for type tests in promoted constants) - #102239 (Move style guide to rust-lang/rust) - #102578 (Panic for invalid arguments of `{integer primitive}::ilog{,2,10}` in all modes) - #102811 (Use memset to initialize readbuf) - #102890 (Check representability in adt_sized_constraint) - #102913 (unify `IsPattern` and `IsImport` enum in `show_candidates`) - #102924 (rustdoc: remove unused classes from sidebar links) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e6ce5627a9
66 changed files with 4106 additions and 1067 deletions
|
@ -584,6 +584,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
// modify their locations.
|
||||
let all_facts = &mut None;
|
||||
let mut constraints = Default::default();
|
||||
let mut type_tests = Default::default();
|
||||
let mut closure_bounds = Default::default();
|
||||
let mut liveness_constraints =
|
||||
LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body)));
|
||||
|
@ -595,6 +596,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
&mut this.cx.borrowck_context.constraints.outlives_constraints,
|
||||
&mut constraints,
|
||||
);
|
||||
mem::swap(&mut this.cx.borrowck_context.constraints.type_tests, &mut type_tests);
|
||||
mem::swap(
|
||||
&mut this.cx.borrowck_context.constraints.closure_bounds_mapping,
|
||||
&mut closure_bounds,
|
||||
|
@ -619,6 +621,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
swap_constraints(self);
|
||||
|
||||
let locations = location.to_locations();
|
||||
|
||||
// Use location of promoted const in collected constraints
|
||||
for type_test in type_tests.iter() {
|
||||
let mut type_test = type_test.clone();
|
||||
type_test.locations = locations;
|
||||
self.cx.borrowck_context.constraints.type_tests.push(type_test)
|
||||
}
|
||||
for constraint in constraints.outlives().iter() {
|
||||
let mut constraint = constraint.clone();
|
||||
constraint.locations = locations;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -380,7 +380,6 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
let def = tcx.adt_def(def_id);
|
||||
let span = tcx.def_span(def_id);
|
||||
def.destructor(tcx); // force the destructor to be evaluated
|
||||
let _ = tcx.representability(def_id);
|
||||
|
||||
if def.repr().simd() {
|
||||
check_simd(tcx, span, def_id);
|
||||
|
@ -394,7 +393,6 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
let def = tcx.adt_def(def_id);
|
||||
let span = tcx.def_span(def_id);
|
||||
def.destructor(tcx); // force the destructor to be evaluated
|
||||
let _ = tcx.representability(def_id);
|
||||
check_transparent(tcx, span, def);
|
||||
check_union_fields(tcx, span, def_id);
|
||||
check_packed(tcx, span, def);
|
||||
|
@ -1489,7 +1487,6 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
|
|||
|
||||
detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
|
||||
|
||||
let _ = tcx.representability(def_id);
|
||||
check_transparent(tcx, sp, def);
|
||||
}
|
||||
|
||||
|
|
|
@ -1041,6 +1041,8 @@ fn check_type_defn<'tcx, F>(
|
|||
) where
|
||||
F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>,
|
||||
{
|
||||
let _ = tcx.representability(item.def_id.def_id);
|
||||
|
||||
enter_wf_checking_ctxt(tcx, item.span, item.def_id.def_id, |wfcx| {
|
||||
let variants = lookup_fields(wfcx);
|
||||
let packed = tcx.adt_def(item.def_id).repr().packed();
|
||||
|
|
|
@ -613,16 +613,8 @@ rustc_queries! {
|
|||
separate_provide_extern
|
||||
}
|
||||
|
||||
// The cycle error here should be reported as an error by `check_representable`.
|
||||
// We consider the type as Sized in the meanwhile to avoid
|
||||
// further errors (done in impl Value for AdtSizedConstraint).
|
||||
// Use `cycle_delay_bug` to delay the cycle error here to be emitted later
|
||||
// in case we accidentally otherwise don't emit an error.
|
||||
query adt_sized_constraint(
|
||||
key: DefId
|
||||
) -> AdtSizedConstraint<'tcx> {
|
||||
query adt_sized_constraint(key: DefId) -> &'tcx [Ty<'tcx>] {
|
||||
desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) }
|
||||
cycle_delay_bug
|
||||
}
|
||||
|
||||
query adt_dtorck_constraint(
|
||||
|
|
|
@ -26,9 +26,6 @@ use super::{
|
|||
Destructor, FieldDef, GenericPredicates, ReprOptions, Ty, TyCtxt, VariantDef, VariantDiscr,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, HashStable, Debug)]
|
||||
pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]);
|
||||
|
||||
bitflags! {
|
||||
#[derive(HashStable, TyEncodable, TyDecodable)]
|
||||
pub struct AdtFlags: u32 {
|
||||
|
@ -563,7 +560,7 @@ impl<'tcx> AdtDef<'tcx> {
|
|||
/// Due to normalization being eager, this applies even if
|
||||
/// the associated type is behind a pointer (e.g., issue #31299).
|
||||
pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> {
|
||||
ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0)
|
||||
ty::EarlyBinder(tcx.adt_sized_constraint(self.did()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -32,7 +32,7 @@ use crate::ty::layout::TyAndLayout;
|
|||
use crate::ty::subst::{GenericArg, SubstsRef};
|
||||
use crate::ty::util::AlwaysRequiresDrop;
|
||||
use crate::ty::GeneratorDiagnosticData;
|
||||
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
|
||||
use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
use rustc_attr as attr;
|
||||
|
|
|
@ -3,7 +3,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_middle::ty::Representability;
|
||||
use rustc_middle::ty::{self, AdtSizedConstraint, DefIdTree, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
|
||||
use rustc_query_system::query::QueryInfo;
|
||||
use rustc_query_system::Value;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
|
@ -31,18 +31,6 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for AdtSizedConstraint<'_> {
|
||||
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
|
||||
// SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`.
|
||||
// FIXME: Represent the above fact in the trait system somehow.
|
||||
unsafe {
|
||||
std::mem::transmute::<AdtSizedConstraint<'tcx>, AdtSizedConstraint<'_>>(
|
||||
AdtSizedConstraint(tcx.intern_type_list(&[tcx.ty_error()])),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
|
||||
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
|
||||
let err = tcx.ty_error();
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,8 +139,7 @@ impl<'a> Resolver<'a> {
|
|||
&candidates,
|
||||
if instead { Instead::Yes } else { Instead::No },
|
||||
found_use,
|
||||
IsPattern::No,
|
||||
IsImport::No,
|
||||
DiagnosticMode::Normal,
|
||||
path,
|
||||
);
|
||||
err.emit();
|
||||
|
@ -699,8 +698,7 @@ impl<'a> Resolver<'a> {
|
|||
&import_suggestions,
|
||||
Instead::No,
|
||||
FoundUse::Yes,
|
||||
IsPattern::Yes,
|
||||
IsImport::No,
|
||||
DiagnosticMode::Pattern,
|
||||
vec![],
|
||||
);
|
||||
}
|
||||
|
@ -1496,8 +1494,7 @@ impl<'a> Resolver<'a> {
|
|||
&import_suggestions,
|
||||
Instead::No,
|
||||
FoundUse::Yes,
|
||||
IsPattern::No,
|
||||
IsImport::No,
|
||||
DiagnosticMode::Normal,
|
||||
vec![],
|
||||
);
|
||||
|
||||
|
@ -2458,18 +2455,13 @@ enum FoundUse {
|
|||
No,
|
||||
}
|
||||
|
||||
/// Whether a binding is part of a pattern or an expression. Used for diagnostics.
|
||||
enum IsPattern {
|
||||
/// Whether a binding is part of a pattern or a use statement. Used for diagnostics.
|
||||
enum DiagnosticMode {
|
||||
Normal,
|
||||
/// The binding is part of a pattern
|
||||
Yes,
|
||||
/// The binding is part of an expression
|
||||
No,
|
||||
}
|
||||
|
||||
/// Whether a binding is part of a use statement. Used for diagnostics.
|
||||
enum IsImport {
|
||||
Yes,
|
||||
No,
|
||||
Pattern,
|
||||
/// The binding is part of a use statement
|
||||
Import,
|
||||
}
|
||||
|
||||
pub(crate) fn import_candidates(
|
||||
|
@ -2488,8 +2480,7 @@ pub(crate) fn import_candidates(
|
|||
candidates,
|
||||
Instead::Yes,
|
||||
FoundUse::Yes,
|
||||
IsPattern::No,
|
||||
IsImport::Yes,
|
||||
DiagnosticMode::Import,
|
||||
vec![],
|
||||
);
|
||||
}
|
||||
|
@ -2506,8 +2497,7 @@ fn show_candidates(
|
|||
candidates: &[ImportSuggestion],
|
||||
instead: Instead,
|
||||
found_use: FoundUse,
|
||||
is_pattern: IsPattern,
|
||||
is_import: IsImport,
|
||||
mode: DiagnosticMode,
|
||||
path: Vec<Segment>,
|
||||
) {
|
||||
if candidates.is_empty() {
|
||||
|
@ -2542,7 +2532,7 @@ fn show_candidates(
|
|||
};
|
||||
|
||||
let instead = if let Instead::Yes = instead { " instead" } else { "" };
|
||||
let mut msg = if let IsPattern::Yes = is_pattern {
|
||||
let mut msg = if let DiagnosticMode::Pattern = mode {
|
||||
format!(
|
||||
"if you meant to match on {}{}{}, use the full path in the pattern",
|
||||
kind, instead, name
|
||||
|
@ -2555,19 +2545,24 @@ fn show_candidates(
|
|||
err.note(note);
|
||||
}
|
||||
|
||||
if let (IsPattern::Yes, Some(span)) = (is_pattern, use_placement_span) {
|
||||
err.span_suggestions(
|
||||
span,
|
||||
&msg,
|
||||
accessible_path_strings.into_iter().map(|a| a.0),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else if let Some(span) = use_placement_span {
|
||||
if let Some(span) = use_placement_span {
|
||||
let add_use = match mode {
|
||||
DiagnosticMode::Pattern => {
|
||||
err.span_suggestions(
|
||||
span,
|
||||
&msg,
|
||||
accessible_path_strings.into_iter().map(|a| a.0),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
return;
|
||||
}
|
||||
DiagnosticMode::Import => "",
|
||||
DiagnosticMode::Normal => "use ",
|
||||
};
|
||||
for candidate in &mut accessible_path_strings {
|
||||
// produce an additional newline to separate the new use statement
|
||||
// from the directly following item.
|
||||
let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" };
|
||||
let add_use = if let IsImport::Yes = is_import { "" } else { "use " };
|
||||
candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline);
|
||||
}
|
||||
|
||||
|
@ -2598,11 +2593,14 @@ fn show_candidates(
|
|||
|
||||
err.note(&msg);
|
||||
}
|
||||
} else if matches!(is_import, IsImport::No) {
|
||||
} else if !matches!(mode, DiagnosticMode::Import) {
|
||||
assert!(!inaccessible_path_strings.is_empty());
|
||||
|
||||
let prefix =
|
||||
if let IsPattern::Yes = is_pattern { "you might have meant to match on " } else { "" };
|
||||
let prefix = if let DiagnosticMode::Pattern = mode {
|
||||
"you might have meant to match on "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
if inaccessible_path_strings.len() == 1 {
|
||||
let (name, descr, def_id, note) = &inaccessible_path_strings[0];
|
||||
let msg = format!(
|
||||
|
@ -2610,7 +2608,7 @@ fn show_candidates(
|
|||
prefix,
|
||||
descr,
|
||||
name,
|
||||
if let IsPattern::Yes = is_pattern { ", which" } else { "" }
|
||||
if let DiagnosticMode::Pattern = mode { ", which" } else { "" }
|
||||
);
|
||||
|
||||
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
|
||||
|
|
|
@ -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, !>,
|
||||
|
|
|
@ -85,9 +85,13 @@ fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
|
|||
/// - a type parameter or projection whose Sizedness can't be known
|
||||
/// - a tuple of type parameters or projections, if there are multiple
|
||||
/// such.
|
||||
/// - an Error, if a type contained itself. The representability
|
||||
/// check should catch this case.
|
||||
fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstraint<'_> {
|
||||
/// - an Error, if a type is infinitely sized
|
||||
fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
if matches!(tcx.representability(def_id), ty::Representability::Infinite) {
|
||||
return tcx.intern_type_list(&[tcx.ty_error()]);
|
||||
}
|
||||
}
|
||||
let def = tcx.adt_def(def_id);
|
||||
|
||||
let result = tcx.mk_type_list(
|
||||
|
@ -99,7 +103,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain
|
|||
|
||||
debug!("adt_sized_constraint: {:?} => {:?}", def, result);
|
||||
|
||||
ty::AdtSizedConstraint(result)
|
||||
result
|
||||
}
|
||||
|
||||
/// See `ParamEnv` struct definition for details.
|
||||
|
|
|
@ -2279,9 +2279,8 @@ macro_rules! int_impl {
|
|||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// When the number is negative, zero, or if the base is not at least 2; it
|
||||
/// panics in debug mode and the return value is 0 in release
|
||||
/// mode.
|
||||
/// This function will panic if `self` is less than or equal to zero,
|
||||
/// or if `base` is less then 2.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -2294,27 +2293,16 @@ macro_rules! int_impl {
|
|||
without modifying the original"]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
#[allow(arithmetic_overflow)]
|
||||
pub const fn ilog(self, base: Self) -> u32 {
|
||||
match self.checked_ilog(base) {
|
||||
Some(n) => n,
|
||||
None => {
|
||||
// In debug builds, trigger a panic on None.
|
||||
// This should optimize completely out in release builds.
|
||||
let _ = Self::MAX + 1;
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
assert!(base >= 2, "base of integer logarithm must be at least 2");
|
||||
self.checked_ilog(base).expect("argument of integer logarithm must be positive")
|
||||
}
|
||||
|
||||
/// Returns the base 2 logarithm of the number, rounded down.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// When the number is negative or zero it panics in debug mode and the return value
|
||||
/// is 0 in release mode.
|
||||
/// This function will panic if `self` is less than or equal to zero.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -2327,27 +2315,15 @@ macro_rules! int_impl {
|
|||
without modifying the original"]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
#[allow(arithmetic_overflow)]
|
||||
pub const fn ilog2(self) -> u32 {
|
||||
match self.checked_ilog2() {
|
||||
Some(n) => n,
|
||||
None => {
|
||||
// In debug builds, trigger a panic on None.
|
||||
// This should optimize completely out in release builds.
|
||||
let _ = Self::MAX + 1;
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
self.checked_ilog2().expect("argument of integer logarithm must be positive")
|
||||
}
|
||||
|
||||
/// Returns the base 10 logarithm of the number, rounded down.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// When the number is negative or zero it panics in debug mode and the return value
|
||||
/// is 0 in release mode.
|
||||
/// This function will panic if `self` is less than or equal to zero.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -2360,19 +2336,8 @@ macro_rules! int_impl {
|
|||
without modifying the original"]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
#[allow(arithmetic_overflow)]
|
||||
pub const fn ilog10(self) -> u32 {
|
||||
match self.checked_ilog10() {
|
||||
Some(n) => n,
|
||||
None => {
|
||||
// In debug builds, trigger a panic on None.
|
||||
// This should optimize completely out in release builds.
|
||||
let _ = Self::MAX + 1;
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
self.checked_ilog10().expect("argument of integer logarithm must be positive")
|
||||
}
|
||||
|
||||
/// Returns the logarithm of the number with respect to an arbitrary base,
|
||||
|
|
|
@ -692,8 +692,7 @@ macro_rules! uint_impl {
|
|||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// When the number is zero, or if the base is not at least 2;
|
||||
/// it panics in debug mode and the return value is 0 in release mode.
|
||||
/// This function will panic if `self` is zero, or if `base` is less then 2.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -706,27 +705,16 @@ macro_rules! uint_impl {
|
|||
without modifying the original"]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
#[allow(arithmetic_overflow)]
|
||||
pub const fn ilog(self, base: Self) -> u32 {
|
||||
match self.checked_ilog(base) {
|
||||
Some(n) => n,
|
||||
None => {
|
||||
// In debug builds, trigger a panic on None.
|
||||
// This should optimize completely out in release builds.
|
||||
let _ = Self::MAX + 1;
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
assert!(base >= 2, "base of integer logarithm must be at least 2");
|
||||
self.checked_ilog(base).expect("argument of integer logarithm must be positive")
|
||||
}
|
||||
|
||||
/// Returns the base 2 logarithm of the number, rounded down.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// When the number is zero it panics in debug mode and
|
||||
/// the return value is 0 in release mode.
|
||||
/// This function will panic if `self` is zero.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -739,27 +727,15 @@ macro_rules! uint_impl {
|
|||
without modifying the original"]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
#[allow(arithmetic_overflow)]
|
||||
pub const fn ilog2(self) -> u32 {
|
||||
match self.checked_ilog2() {
|
||||
Some(n) => n,
|
||||
None => {
|
||||
// In debug builds, trigger a panic on None.
|
||||
// This should optimize completely out in release builds.
|
||||
let _ = Self::MAX + 1;
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
self.checked_ilog2().expect("argument of integer logarithm must be positive")
|
||||
}
|
||||
|
||||
/// Returns the base 10 logarithm of the number, rounded down.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// When the number is zero it panics in debug mode and the
|
||||
/// return value is 0 in release mode.
|
||||
/// This function will panic if `self` is zero.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -772,19 +748,8 @@ macro_rules! uint_impl {
|
|||
without modifying the original"]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
#[allow(arithmetic_overflow)]
|
||||
pub const fn ilog10(self) -> u32 {
|
||||
match self.checked_ilog10() {
|
||||
Some(n) => n,
|
||||
None => {
|
||||
// In debug builds, trigger a panic on None.
|
||||
// This should optimize completely out in release builds.
|
||||
let _ = Self::MAX + 1;
|
||||
|
||||
0
|
||||
},
|
||||
}
|
||||
self.checked_ilog10().expect("argument of integer logarithm must be positive")
|
||||
}
|
||||
|
||||
/// Returns the logarithm of the number with respect to an arbitrary base,
|
||||
|
|
|
@ -164,3 +164,33 @@ fn ilog10_u64() {
|
|||
fn ilog10_u128() {
|
||||
ilog10_loop! { u128, 38 }
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "argument of integer logarithm must be positive")]
|
||||
fn ilog2_of_0_panic() {
|
||||
let _ = 0u32.ilog2();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "argument of integer logarithm must be positive")]
|
||||
fn ilog10_of_0_panic() {
|
||||
let _ = 0u32.ilog10();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "argument of integer logarithm must be positive")]
|
||||
fn ilog3_of_0_panic() {
|
||||
let _ = 0u32.ilog(3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "base of integer logarithm must be at least 2")]
|
||||
fn ilog0_of_1_panic() {
|
||||
let _ = 1u32.ilog(0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "base of integer logarithm must be at least 2")]
|
||||
fn ilog1_of_1_panic() {
|
||||
let _ = 1u32.ilog(1);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use crate::cmp;
|
||||
use crate::fmt::{self, Debug, Formatter};
|
||||
use crate::io::{Result, Write};
|
||||
use crate::mem::{self, MaybeUninit};
|
||||
use crate::{cmp, ptr};
|
||||
|
||||
/// A borrowed byte buffer which is incrementally filled and initialized.
|
||||
///
|
||||
|
@ -250,8 +250,11 @@ impl<'a> BorrowedCursor<'a> {
|
|||
/// Initializes all bytes in the cursor.
|
||||
#[inline]
|
||||
pub fn ensure_init(&mut self) -> &mut Self {
|
||||
for byte in self.uninit_mut() {
|
||||
byte.write(0);
|
||||
let uninit = self.uninit_mut();
|
||||
// SAFETY: 0 is a valid value for MaybeUninit<u8> and the length matches the allocation
|
||||
// since it is comes from a slice reference.
|
||||
unsafe {
|
||||
ptr::write_bytes(uninit.as_mut_ptr(), 0, uninit.len());
|
||||
}
|
||||
self.buf.init = self.buf.capacity();
|
||||
|
||||
|
|
|
@ -704,6 +704,7 @@ impl<'a> Builder<'a> {
|
|||
doc::Miri,
|
||||
doc::EmbeddedBook,
|
||||
doc::EditionGuide,
|
||||
doc::StyleGuide,
|
||||
),
|
||||
Kind::Dist => describe!(
|
||||
dist::Docs,
|
||||
|
|
|
@ -82,6 +82,7 @@ book!(
|
|||
Reference, "src/doc/reference", "reference", submodule;
|
||||
RustByExample, "src/doc/rust-by-example", "rust-by-example", submodule;
|
||||
RustdocBook, "src/doc/rustdoc", "rustdoc";
|
||||
StyleGuide, "src/doc/style-guide", "style-guide";
|
||||
);
|
||||
|
||||
fn open(builder: &Builder<'_>, path: impl AsRef<Path>) {
|
||||
|
|
|
@ -113,6 +113,12 @@ resources useful.
|
|||
[The Reference](reference/index.html) is not a formal spec, but is more detailed and
|
||||
comprehensive than the book.
|
||||
|
||||
## The Style Guide
|
||||
|
||||
[The Rust Style Guide](style-guide/index.html) describes the standard formatting of Rust
|
||||
code. Most developers use rustfmt to format their code, and rustfmt's default
|
||||
formatting matches this style guide.
|
||||
|
||||
## The Rustonomicon
|
||||
|
||||
[The Rustonomicon](nomicon/index.html) is your guidebook to the dark arts of unsafe
|
||||
|
|
8
src/doc/style-guide/book.toml
Normal file
8
src/doc/style-guide/book.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[book]
|
||||
title = "The Rust Style Guide"
|
||||
author = "The Rust Style Team"
|
||||
multilingual = false
|
||||
src = "src"
|
||||
|
||||
[output.html]
|
||||
git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/style-guide/"
|
190
src/doc/style-guide/src/README.md
Normal file
190
src/doc/style-guide/src/README.md
Normal file
|
@ -0,0 +1,190 @@
|
|||
# Rust Style Guide
|
||||
|
||||
## Motivation - why use a formatting tool?
|
||||
|
||||
Formatting code is a mostly mechanical task which takes both time and mental
|
||||
effort. By using an automatic formatting tool, a programmer is relieved of
|
||||
this task and can concentrate on more important things.
|
||||
|
||||
Furthermore, by sticking to an established style guide (such as this one),
|
||||
programmers don't need to formulate ad hoc style rules, nor do they need to
|
||||
debate with other programmers what style rules should be used, saving time,
|
||||
communication overhead, and mental energy.
|
||||
|
||||
Humans comprehend information through pattern matching. By ensuring that all
|
||||
Rust code has similar formatting, less mental effort is required to comprehend a
|
||||
new project, lowering the barrier to entry for new developers.
|
||||
|
||||
Thus, there are productivity benefits to using a formatting tool (such as
|
||||
rustfmt), and even larger benefits by using a community-consistent formatting,
|
||||
typically by using a formatting tool's default settings.
|
||||
|
||||
|
||||
## Formatting conventions
|
||||
|
||||
### Indentation and line width
|
||||
|
||||
* Use spaces, not tabs.
|
||||
* Each level of indentation must be four spaces (that is, all indentation
|
||||
outside of string literals and comments must be a multiple of four).
|
||||
* The maximum width for a line is 100 characters.
|
||||
* A tool should be configurable for all three of these variables.
|
||||
|
||||
|
||||
### Blank lines
|
||||
|
||||
Separate items and statements by either zero or one blank lines (i.e., one or
|
||||
two newlines). E.g,
|
||||
|
||||
```rust
|
||||
fn foo() {
|
||||
let x = ...;
|
||||
|
||||
let y = ...;
|
||||
let z = ...;
|
||||
}
|
||||
|
||||
fn bar() {}
|
||||
fn baz() {}
|
||||
```
|
||||
|
||||
Formatting tools should make the bounds on blank lines configurable: there
|
||||
should be separate minimum and maximum numbers of newlines between both
|
||||
statements and (top-level) items (i.e., four options). As described above, the
|
||||
defaults for both statements and items should be minimum: 1, maximum: 2.
|
||||
|
||||
|
||||
### [Module-level items](items.md)
|
||||
### [Statements](statements.md)
|
||||
### [Expressions](expressions.md)
|
||||
### [Types](types.md)
|
||||
|
||||
|
||||
### Comments
|
||||
|
||||
The following guidelines for comments are recommendations only, a mechanical
|
||||
formatter might skip formatting of comments.
|
||||
|
||||
Prefer line comments (`//`) to block comments (`/* ... */`).
|
||||
|
||||
When using line comments there should be a single space after the opening sigil.
|
||||
|
||||
When using single-line block comments there should be a single space after the
|
||||
opening sigil and before the closing sigil. Multi-line block comments should
|
||||
have a newline after the opening sigil and before the closing sigil.
|
||||
|
||||
Prefer to put a comment on its own line. Where a comment follows code, there
|
||||
should be a single space before it. Where a block comment is inline, there
|
||||
should be surrounding whitespace as if it were an identifier or keyword. There
|
||||
should be no trailing whitespace after a comment or at the end of any line in a
|
||||
multi-line comment. Examples:
|
||||
|
||||
```rust
|
||||
// A comment on an item.
|
||||
struct Foo { ... }
|
||||
|
||||
fn foo() {} // A comment after an item.
|
||||
|
||||
pub fn foo(/* a comment before an argument */ x: T) {...}
|
||||
```
|
||||
|
||||
Comments should usually be complete sentences. Start with a capital letter, end
|
||||
with a period (`.`). An inline block comment may be treated as a note without
|
||||
punctuation.
|
||||
|
||||
Source lines which are entirely a comment should be limited to 80 characters
|
||||
in length (including comment sigils, but excluding indentation) or the maximum
|
||||
width of the line (including comment sigils and indentation), whichever is
|
||||
smaller:
|
||||
|
||||
```rust
|
||||
// This comment goes up to the ................................. 80 char margin.
|
||||
|
||||
{
|
||||
// This comment is .............................................. 80 chars wide.
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
{
|
||||
{
|
||||
{
|
||||
{
|
||||
// This comment is limited by the ......................... 100 char margin.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Doc comments
|
||||
|
||||
Prefer line comments (`///`) to block comments (`/** ... */`).
|
||||
|
||||
Prefer outer doc comments (`///` or `/** ... */`), only use inner doc comments
|
||||
(`//!` and `/*! ... */`) to write module-level or crate-level documentation.
|
||||
|
||||
Doc comments should come before attributes.
|
||||
|
||||
### Attributes
|
||||
|
||||
Put each attribute on its own line, indented to the level of the item.
|
||||
In the case of inner attributes (`#!`), indent it to the level of the inside of
|
||||
the item. Prefer outer attributes, where possible.
|
||||
|
||||
For attributes with argument lists, format like functions.
|
||||
|
||||
```rust
|
||||
#[repr(C)]
|
||||
#[foo(foo, bar)]
|
||||
struct CRepr {
|
||||
#![repr(C)]
|
||||
x: f32,
|
||||
y: f32,
|
||||
}
|
||||
```
|
||||
|
||||
For attributes with an equal sign, there should be a single space before and
|
||||
after the `=`, e.g., `#[foo = 42]`.
|
||||
|
||||
There must only be a single `derive` attribute. Note for tool authors: if
|
||||
combining multiple `derive` attributes into a single attribute, the ordering of
|
||||
the derived names should be preserved. E.g., `#[derive(bar)] #[derive(foo)]
|
||||
struct Baz;` should be formatted to `#[derive(bar, foo)] struct Baz;`.
|
||||
|
||||
### *small* items
|
||||
|
||||
In many places in this guide we specify that a formatter may format an item
|
||||
differently if it is *small*, for example struct literals:
|
||||
|
||||
```rust
|
||||
// Normal formatting
|
||||
Foo {
|
||||
f1: an_expression,
|
||||
f2: another_expression(),
|
||||
}
|
||||
|
||||
// *small* formatting
|
||||
Foo { f1, f2 }
|
||||
```
|
||||
|
||||
We leave it to individual tools to decide on exactly what *small* means. In
|
||||
particular, tools are free to use different definitions in different
|
||||
circumstances.
|
||||
|
||||
Some suitable heuristics are the size of the item (in characters) or the
|
||||
complexity of an item (for example, that all components must be simple names,
|
||||
not more complex sub-expressions). For more discussion on suitable heuristics,
|
||||
see [this issue](https://github.com/rust-lang-nursery/fmt-rfcs/issues/47).
|
||||
|
||||
Tools should give the user an option to ignore such heuristics and always use
|
||||
the normal formatting.
|
||||
|
||||
|
||||
## [Non-formatting conventions](advice.md)
|
||||
|
||||
## [Cargo.toml conventions](cargo.md)
|
||||
|
||||
## [Principles used for deciding these guidelines](principles.md)
|
11
src/doc/style-guide/src/SUMMARY.md
Normal file
11
src/doc/style-guide/src/SUMMARY.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Summary
|
||||
|
||||
[Introduction](README.md)
|
||||
|
||||
- [Module-level items](items.md)
|
||||
- [Statements](statements.md)
|
||||
- [Expressions](expressions.md)
|
||||
- [Types](types.md)
|
||||
- [Non-formatting conventions](advice.md)
|
||||
- [`Cargo.toml` conventions](cargo.md)
|
||||
- [Principles used for deciding these guidelines](principles.md)
|
34
src/doc/style-guide/src/advice.md
Normal file
34
src/doc/style-guide/src/advice.md
Normal file
|
@ -0,0 +1,34 @@
|
|||
# Other style advice
|
||||
|
||||
## Expressions
|
||||
|
||||
Prefer to use Rust's expression oriented nature where possible;
|
||||
|
||||
```rust
|
||||
// use
|
||||
let x = if y { 1 } else { 0 };
|
||||
// not
|
||||
let x;
|
||||
if y {
|
||||
x = 1;
|
||||
} else {
|
||||
x = 0;
|
||||
}
|
||||
```
|
||||
|
||||
## Names
|
||||
|
||||
* Types shall be `UpperCamelCase`,
|
||||
* Enum variants shall be `UpperCamelCase`,
|
||||
* Struct fields shall be `snake_case`,
|
||||
* Function and method names shall be `snake_case`,
|
||||
* Local variables shall be `snake_case`,
|
||||
* Macro names shall be `snake_case`,
|
||||
* Constants (`const`s and immutable `static`s) shall be `SCREAMING_SNAKE_CASE`.
|
||||
* When a name is forbidden because it is a reserved word (e.g., `crate`), use a
|
||||
trailing underscore to make the name legal (e.g., `crate_`), or use raw
|
||||
identifiers if possible.
|
||||
|
||||
### Modules
|
||||
|
||||
Avoid `#[path]` annotations where possible.
|
78
src/doc/style-guide/src/cargo.md
Normal file
78
src/doc/style-guide/src/cargo.md
Normal file
|
@ -0,0 +1,78 @@
|
|||
# Cargo.toml conventions
|
||||
|
||||
## Formatting conventions
|
||||
|
||||
Use the same line width and indentation as Rust code.
|
||||
|
||||
Put a blank line between the last key-value pair in a section and the header of
|
||||
the next section. Do not place a blank line between section headers and the
|
||||
key-value pairs in that section, or between key-value pairs in a section.
|
||||
|
||||
Sort key names alphabetically within each section, with the exception of the
|
||||
`[package]` section. Put the `[package]` section at the top of the file; put
|
||||
the `name` and `version` keys in that order at the top of that section,
|
||||
followed by the remaining keys other than `description` in alphabetical order,
|
||||
followed by the `description` at the end of that section.
|
||||
|
||||
Don't use quotes around any standard key names; use bare keys. Only use quoted
|
||||
keys for non-standard keys whose names require them, and avoid introducing such
|
||||
key names when possible. See the [TOML
|
||||
specification](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md#table)
|
||||
for details.
|
||||
|
||||
Put a single space both before and after the `=` between a key and value. Do
|
||||
not indent any key names; start all key names at the start of a line.
|
||||
|
||||
Use multi-line strings (rather than newline escape sequences) for any string
|
||||
values that include multiple lines, such as the crate description.
|
||||
|
||||
For array values, such as a list of authors, put the entire list on the same
|
||||
line as the key, if it fits. Otherwise, use block indentation: put a newline
|
||||
after the opening square bracket, indent each item by one indentation level,
|
||||
put a comma after each item (including the last), and put the closing square
|
||||
bracket at the start of a line by itself after the last item.
|
||||
|
||||
```rust
|
||||
authors = [
|
||||
"A Uthor <a.uthor@example.org>",
|
||||
"Another Author <author@example.net>",
|
||||
]
|
||||
```
|
||||
|
||||
For table values, such as a crate dependency with a path, write the entire
|
||||
table using curly braces and commas on the same line as the key if it fits. If
|
||||
the entire table does not fit on the same line as the key, separate it out into
|
||||
a separate section with key-value pairs:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
crate1 = { path = "crate1", version = "1.2.3" }
|
||||
|
||||
[dependencies.extremely_long_crate_name_goes_here]
|
||||
path = "extremely_long_path_name_goes_right_here"
|
||||
version = "4.5.6"
|
||||
```
|
||||
|
||||
## Metadata conventions
|
||||
|
||||
The authors list should consist of strings that each contain an author name
|
||||
followed by an email address in angle brackets: `Full Name <email@address>`.
|
||||
It should not contain bare email addresses, or names without email addresses.
|
||||
(The authors list may also include a mailing list address without an associated
|
||||
name.)
|
||||
|
||||
The license field must contain a valid [SPDX
|
||||
expression](https://spdx.org/spdx-specification-21-web-version#h.jxpfx0ykyb60),
|
||||
using valid [SPDX license names](https://spdx.org/licenses/). (As an exception,
|
||||
by widespread convention, the license field may use `/` in place of ` OR `; for
|
||||
example, `MIT/Apache-2.0`.)
|
||||
|
||||
The homepage field, if present, must consist of a single URL, including the
|
||||
scheme (e.g. `https://example.org/`, not just `example.org`.)
|
||||
|
||||
Within the description field, wrap text at 80 columns. Don't start the
|
||||
description field with the name of the crate (e.g. "cratename is a ..."); just
|
||||
describe the crate itself. If providing a multi-sentence description, the first
|
||||
sentence should go on a line by itself and summarize the crate, like the
|
||||
subject of an email or commit message; subsequent sentences can then describe
|
||||
the crate in more detail.
|
850
src/doc/style-guide/src/expressions.md
Normal file
850
src/doc/style-guide/src/expressions.md
Normal file
|
@ -0,0 +1,850 @@
|
|||
## Expressions
|
||||
|
||||
### Blocks
|
||||
|
||||
A block expression should have a newline after the initial `{` and before the
|
||||
terminal `}`. Any qualifier before the block (e.g., `unsafe`) should always be
|
||||
on the same line as the opening brace, and separated with a single space. The
|
||||
contents of the block should be block indented:
|
||||
|
||||
```rust
|
||||
fn block_as_stmt() {
|
||||
a_call();
|
||||
|
||||
{
|
||||
a_call_inside_a_block();
|
||||
|
||||
// a comment in a block
|
||||
the_value
|
||||
}
|
||||
}
|
||||
|
||||
fn block_as_expr() {
|
||||
let foo = {
|
||||
a_call_inside_a_block();
|
||||
|
||||
// a comment in a block
|
||||
the_value
|
||||
};
|
||||
}
|
||||
|
||||
fn unsafe_block_as_stmt() {
|
||||
a_call();
|
||||
|
||||
unsafe {
|
||||
a_call_inside_a_block();
|
||||
|
||||
// a comment in a block
|
||||
the_value
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If a block has an attribute, it should be on its own line:
|
||||
|
||||
```rust
|
||||
fn block_as_stmt() {
|
||||
#[an_attribute]
|
||||
{
|
||||
#![an_inner_attribute]
|
||||
|
||||
// a comment in a block
|
||||
the_value
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Avoid writing comments on the same line as the braces.
|
||||
|
||||
An empty block should be written as `{}`.
|
||||
|
||||
A block may be written on a single line if:
|
||||
|
||||
* it is either used in expression position (not statement position) or is an
|
||||
unsafe block in statement position
|
||||
* contains a single-line expression and no statements
|
||||
* contains no comments
|
||||
|
||||
A single line block should have spaces after the opening brace and before the
|
||||
closing brace.
|
||||
|
||||
Examples:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
// Single line
|
||||
let _ = { a_call() };
|
||||
let _ = unsafe { a_call() };
|
||||
|
||||
// Not allowed on one line
|
||||
// Statement position.
|
||||
{
|
||||
a_call()
|
||||
}
|
||||
|
||||
// Contains a statement
|
||||
let _ = {
|
||||
a_call();
|
||||
};
|
||||
unsafe {
|
||||
a_call();
|
||||
}
|
||||
|
||||
// Contains a comment
|
||||
let _ = {
|
||||
// A comment
|
||||
};
|
||||
let _ = {
|
||||
// A comment
|
||||
a_call()
|
||||
};
|
||||
|
||||
// Multiple lines
|
||||
let _ = {
|
||||
a_call();
|
||||
another_call()
|
||||
};
|
||||
let _ = {
|
||||
a_call(
|
||||
an_argument,
|
||||
another_arg,
|
||||
)
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Closures
|
||||
|
||||
Don't put any extra spaces before the first `|` (unless the closure is prefixed
|
||||
by `move`); put a space between the second `|` and the expression of the
|
||||
closure. Between the `|`s, you should use function definition syntax, however,
|
||||
elide types where possible.
|
||||
|
||||
Use closures without the enclosing `{}`, if possible. Add the `{}` when you have
|
||||
a return type, when there are statements, there are comments in the body, or the
|
||||
body expression spans multiple lines and is a control-flow expression. If using
|
||||
braces, follow the rules above for blocks. Examples:
|
||||
|
||||
```rust
|
||||
|arg1, arg2| expr
|
||||
|
||||
move |arg1: i32, arg2: i32| -> i32 {
|
||||
expr1;
|
||||
expr2
|
||||
}
|
||||
|
||||
|| Foo {
|
||||
field1,
|
||||
field2: 0,
|
||||
}
|
||||
|
||||
|| {
|
||||
if true {
|
||||
blah
|
||||
} else {
|
||||
boo
|
||||
}
|
||||
}
|
||||
|
||||
|x| unsafe {
|
||||
expr
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Struct literals
|
||||
|
||||
If a struct literal is *small* it may be formatted on a single line. If not,
|
||||
each field should be on it's own, block-indented line. There should be a
|
||||
trailing comma in the multi-line form only. There should be a space after the
|
||||
colon only.
|
||||
|
||||
There should be a space before the opening brace. In the single-line form there
|
||||
should be spaces after the opening brace and before the closing brace.
|
||||
|
||||
```rust
|
||||
Foo { field1, field2: 0 }
|
||||
let f = Foo {
|
||||
field1,
|
||||
field2: an_expr,
|
||||
};
|
||||
```
|
||||
|
||||
Functional record update syntax is treated like a field, but it must never have
|
||||
a trailing comma. There should be no space after `..`.
|
||||
|
||||
let f = Foo {
|
||||
field1,
|
||||
..an_expr
|
||||
};
|
||||
|
||||
|
||||
### Tuple literals
|
||||
|
||||
Use a single-line form where possible. There should not be spaces around the
|
||||
parentheses. Where a single-line form is not possible, each element of the tuple
|
||||
should be on its own block-indented line and there should be a trailing comma.
|
||||
|
||||
```rust
|
||||
(a, b, c)
|
||||
|
||||
let x = (
|
||||
a_long_expr,
|
||||
another_very_long_expr,
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
### Tuple struct literals
|
||||
|
||||
There should be no space between the identifier and the opening parenthesis.
|
||||
Otherwise, follow the rules for tuple literals, e.g., `Foo(a, b)`.
|
||||
|
||||
|
||||
### Enum literals
|
||||
|
||||
Follow the formatting rules for the various struct literals. Prefer using the
|
||||
name of the enum as a qualifying name, unless the enum is in the prelude. E.g.,
|
||||
|
||||
```rust
|
||||
Foo::Bar(a, b)
|
||||
Foo::Baz {
|
||||
field1,
|
||||
field2: 1001,
|
||||
}
|
||||
Ok(an_expr)
|
||||
```
|
||||
|
||||
|
||||
### Array literals
|
||||
|
||||
For simple array literals, avoid line breaking, no spaces around square
|
||||
brackets, contents of the array should be separated by commas and spaces. If
|
||||
using the repeating initialiser, there should be a space after the semicolon
|
||||
only. Apply the same rules if using the `vec!` or similar macros (always use
|
||||
square brackets here). Examples:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
[1, 2, 3];
|
||||
vec![a, b, c, d];
|
||||
let a = [42; 10];
|
||||
}
|
||||
```
|
||||
|
||||
If a line must be broken, prefer breaking only after the `;`, if possible.
|
||||
Otherwise, follow the rules below for function calls. In any case, the contents
|
||||
of the initialiser should be block indented and there should be line breaks
|
||||
after the opening bracket and before the closing bracket:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
[
|
||||
a_long_expression();
|
||||
1234567890
|
||||
]
|
||||
let x = [
|
||||
an_expression,
|
||||
another_expression,
|
||||
a_third_expression,
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Array accesses, indexing, and slicing.
|
||||
|
||||
No spaces around the square brackets, avoid breaking lines if possible, never
|
||||
break a line between the target expression and the opening bracket. If the
|
||||
indexing expression covers multiple lines, then it should be block indented and
|
||||
there should be newlines after the opening brackets and before the closing
|
||||
bracket. However, this should be avoided where possible.
|
||||
|
||||
Examples:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
foo[42];
|
||||
&foo[..10];
|
||||
bar[0..100];
|
||||
foo[4 + 5 / bar];
|
||||
a_long_target[
|
||||
a_long_indexing_expression
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
### Unary operations
|
||||
|
||||
Do not include a space between a unary op and its operand (i.e., `!x`, not
|
||||
`! x`). However, there must be a space after `&mut`. Avoid line-breaking
|
||||
between a unary operator and its operand.
|
||||
|
||||
### Binary operations
|
||||
|
||||
Do include spaces around binary ops (i.e., `x + 1`, not `x+1`) (including `=`
|
||||
and other assignment operators such as `+=` or `*=`).
|
||||
|
||||
For comparison operators, because for `T op U`, `&T op &U` is also implemented:
|
||||
if you have `t: &T`, and `u: U`, prefer `*t op u` to `t op &u`. In general,
|
||||
within expressions, prefer dereferencing to taking references.
|
||||
|
||||
Use parentheses liberally, do not necessarily elide them due to precedence.
|
||||
Tools should not automatically insert or remove parentheses. Do not use spaces
|
||||
to indicate precedence.
|
||||
|
||||
If line-breaking, put the operator on a new line and block indent. Put each
|
||||
sub-expression on its own line. E.g.,
|
||||
|
||||
```rust
|
||||
foo_bar
|
||||
+ bar
|
||||
+ baz
|
||||
+ qux
|
||||
+ whatever
|
||||
```
|
||||
|
||||
Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather
|
||||
than at other binary operators.
|
||||
|
||||
### Control flow
|
||||
|
||||
Do not include extraneous parentheses for `if` and `while` expressions.
|
||||
|
||||
```rust
|
||||
if true {
|
||||
}
|
||||
```
|
||||
|
||||
is better than
|
||||
|
||||
```rust
|
||||
if (true) {
|
||||
}
|
||||
```
|
||||
|
||||
Do include extraneous parentheses if it makes an arithmetic or logic expression
|
||||
easier to understand (`(x * 15) + (y * 20)` is fine)
|
||||
|
||||
### Function calls
|
||||
|
||||
Do not put a space between the function name, and the opening parenthesis.
|
||||
|
||||
Do not put a space between an argument, and the comma which follows.
|
||||
|
||||
Do put a space between an argument, and the comma which precedes it.
|
||||
|
||||
Prefer not to break a line in the callee expression.
|
||||
|
||||
#### Single-line calls
|
||||
|
||||
Do not put a space between the function name and open paren, between the open
|
||||
paren and the first argument, or between the last argument and the close paren.
|
||||
|
||||
Do not put a comma after the last argument.
|
||||
|
||||
```rust
|
||||
foo(x, y, z)
|
||||
```
|
||||
|
||||
#### Multi-line calls
|
||||
|
||||
If the function call is not *small*, it would otherwise over-run the max width,
|
||||
or any argument or the callee is multi-line, then the call should be formatted
|
||||
across multiple lines. In this case, each argument should be on it's own block-
|
||||
indented line, there should be a newline after the opening parenthesis and
|
||||
before the closing parenthesis, and there should be a trailing comma. E.g.,
|
||||
|
||||
```rust
|
||||
a_function_call(
|
||||
arg1,
|
||||
a_nested_call(a, b),
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
### Method calls
|
||||
|
||||
Follow the function rules for calling.
|
||||
|
||||
Do not put any spaces around the `.`.
|
||||
|
||||
```rust
|
||||
x.foo().bar().baz(x, y, z);
|
||||
```
|
||||
|
||||
|
||||
### Macro uses
|
||||
|
||||
Macros which can be parsed like other constructs should be formatted like those
|
||||
constructs. For example, a macro use `foo!(a, b, c)` can be parsed like a
|
||||
function call (ignoring the `!`), therefore it should be formatted following the
|
||||
rules for function calls.
|
||||
|
||||
#### Special case macros
|
||||
|
||||
Macros which take a format string and where all other arguments are *small* may
|
||||
be formatted with arguments before and after the format string on a single line
|
||||
and the format string on its own line, rather than putting each argument on its
|
||||
own line. For example,
|
||||
|
||||
```rust
|
||||
println!(
|
||||
"Hello {} and {}",
|
||||
name1, name2,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
x, y,
|
||||
"x and y were not equal, see {}",
|
||||
reason,
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
### Casts (`as`)
|
||||
|
||||
Put spaces before and after `as`:
|
||||
|
||||
```rust
|
||||
let cstr = "Hi\0" as *const str as *const [u8] as *const std::os::raw::c_char;
|
||||
```
|
||||
|
||||
|
||||
### Chains of fields and method calls
|
||||
|
||||
A chain is a sequence of field accesses and/or method calls. A chain may also
|
||||
include the try operator ('?'). E.g., `a.b.c().d` or `foo?.bar().baz?`.
|
||||
|
||||
Prefer formatting on one line if possible, and the chain is *small*. If
|
||||
formatting on multiple lines, each field access or method call in the chain
|
||||
should be on its own line with the line-break before the `.` and after any `?`.
|
||||
Each line should be block-indented. E.g.,
|
||||
|
||||
```rust
|
||||
let foo = bar
|
||||
.baz?
|
||||
.qux();
|
||||
```
|
||||
|
||||
If the length of the last line of the first element plus its indentation is
|
||||
less than or equal to the indentation of the second line (and there is space),
|
||||
then combine the first and second lines, e.g.,
|
||||
|
||||
```rust
|
||||
x.baz?
|
||||
.qux()
|
||||
|
||||
let foo = x
|
||||
.baz?
|
||||
.qux();
|
||||
|
||||
foo(
|
||||
expr1,
|
||||
expr2,
|
||||
).baz?
|
||||
.qux();
|
||||
```
|
||||
|
||||
#### Multi-line elements
|
||||
|
||||
If any element in a chain is formatted across multiple lines, then that element
|
||||
and any later elements must be on their own line. Earlier elements may be kept
|
||||
on a single line. E.g.,
|
||||
|
||||
```rust
|
||||
a.b.c()?.d
|
||||
.foo(
|
||||
an_expr,
|
||||
another_expr,
|
||||
)
|
||||
.bar
|
||||
.baz
|
||||
```
|
||||
|
||||
Note there is block indent due to the chain and the function call in the above
|
||||
example.
|
||||
|
||||
Prefer formatting the whole chain in multi-line style and each element on one
|
||||
line, rather than putting some elements on multiple lines and some on a single
|
||||
line, e.g.,
|
||||
|
||||
```rust
|
||||
// Better
|
||||
self.pre_comment
|
||||
.as_ref()
|
||||
.map_or(false, |comment| comment.starts_with("//"))
|
||||
|
||||
// Worse
|
||||
self.pre_comment.as_ref().map_or(
|
||||
false,
|
||||
|comment| comment.starts_with("//"),
|
||||
)
|
||||
```
|
||||
|
||||
### Control flow expressions
|
||||
|
||||
This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for`
|
||||
expressions.
|
||||
|
||||
The keyword, any initial clauses, and the opening brace of the block should be
|
||||
on a single line. The usual rules for [block formatting](#blocks) should be
|
||||
applied to the block.
|
||||
|
||||
If there is an `else` component, then the closing brace, `else`, any following
|
||||
clause, and the opening brace should all be on the same line. There should be a
|
||||
single space before and after the `else` keyword. For example:
|
||||
|
||||
```rust
|
||||
if ... {
|
||||
...
|
||||
} else {
|
||||
...
|
||||
}
|
||||
|
||||
if let ... {
|
||||
...
|
||||
} else if ... {
|
||||
...
|
||||
} else {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
If the control line needs to be broken, then prefer to break before the `=` in
|
||||
`* let` expressions and before `in` in a `for` expression; the following line
|
||||
should be block indented. If the control line is broken for any reason, then the
|
||||
opening brace should be on its own line and not indented. Examples:
|
||||
|
||||
```rust
|
||||
while let Some(foo)
|
||||
= a_long_expression
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
for foo
|
||||
in a_long_expression
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
if a_long_expression
|
||||
&& another_long_expression
|
||||
|| a_third_long_expression
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Where the initial clause is multi-lined and ends with one or more closing
|
||||
parentheses, square brackets, or braces, and there is nothing else on that line,
|
||||
and that line is not indented beyond the indent on the first line of the control
|
||||
flow expression, then the opening brace of the block should be put on the same
|
||||
line with a preceding space. For example:
|
||||
|
||||
```rust
|
||||
if !self.config.file_lines().intersects(
|
||||
&self.codemap.lookup_line_range(
|
||||
stmt.span,
|
||||
),
|
||||
) { // Opening brace on same line as initial clause.
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### Single line `if else`
|
||||
|
||||
Formatters may place an `if else` or `if let else` on a single line if it occurs
|
||||
in expression context (i.e., is not a standalone statement), it contains a
|
||||
single `else` clause, and is *small*. For example:
|
||||
|
||||
```rust
|
||||
let y = if x { 0 } else { 1 };
|
||||
|
||||
// Examples that must be multi-line.
|
||||
let y = if something_very_long {
|
||||
not_small
|
||||
} else {
|
||||
also_not_small
|
||||
};
|
||||
|
||||
if x {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Match
|
||||
|
||||
Prefer not to line-break inside the discriminant expression. There must always
|
||||
be a line break after the opening brace and before the closing brace. The match
|
||||
arms must be block indented once:
|
||||
|
||||
```rust
|
||||
match foo {
|
||||
// arms
|
||||
}
|
||||
|
||||
let x = match foo.bar.baz() {
|
||||
// arms
|
||||
};
|
||||
```
|
||||
|
||||
Use a trailing comma for a match arm if and only if not using a block.
|
||||
|
||||
Never start a match arm pattern with `|`, e.g.,
|
||||
|
||||
```rust
|
||||
match foo {
|
||||
// Don't do this.
|
||||
| foo => bar,
|
||||
// Or this.
|
||||
| a_very_long_pattern
|
||||
| another_pattern
|
||||
| yet_another_pattern
|
||||
| a_forth_pattern => {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Prefer
|
||||
|
||||
|
||||
```rust
|
||||
match foo {
|
||||
foo => bar,
|
||||
a_very_long_pattern
|
||||
| another_pattern
|
||||
| yet_another_pattern
|
||||
| a_forth_pattern => {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Avoid splitting the left-hand side (before the `=>`) of a match arm where
|
||||
possible. If the right-hand side of the match arm is kept on the same line,
|
||||
never use a block (unless the block is empty).
|
||||
|
||||
If the right-hand side consists of multiple statements or has line comments or
|
||||
the start of the line cannot be fit on the same line as the left-hand side, use
|
||||
a block.
|
||||
|
||||
The body of a block arm should be block indented once.
|
||||
|
||||
Examples:
|
||||
|
||||
```rust
|
||||
match foo {
|
||||
foo => bar,
|
||||
a_very_long_patten | another_pattern if an_expression() => {
|
||||
no_room_for_this_expression()
|
||||
}
|
||||
foo => {
|
||||
// A comment.
|
||||
an_expression()
|
||||
}
|
||||
foo => {
|
||||
let a = statement();
|
||||
an_expression()
|
||||
}
|
||||
bar => {}
|
||||
// Trailing comma on last item.
|
||||
foo => bar,
|
||||
}
|
||||
```
|
||||
|
||||
If the body is a single expression with no line comments and not a control flow
|
||||
expression, then it may be started on the same line as the right-hand side. If
|
||||
not, then it must be in a block. Example,
|
||||
|
||||
```rust
|
||||
match foo {
|
||||
// A combinable expression.
|
||||
foo => a_function_call(another_call(
|
||||
argument1,
|
||||
argument2,
|
||||
)),
|
||||
// A non-combinable expression
|
||||
bar => {
|
||||
a_function_call(
|
||||
another_call(
|
||||
argument1,
|
||||
argument2,
|
||||
),
|
||||
another_argument,
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Line-breaking
|
||||
|
||||
Where it is possible to use a block form on the right-hand side and avoid
|
||||
breaking the left-hand side, do that. E.g.
|
||||
|
||||
```rust
|
||||
// Assuming the following line does done fit in the max width
|
||||
a_very_long_pattern | another_pattern => ALongStructName {
|
||||
...
|
||||
},
|
||||
// Prefer this
|
||||
a_very_long_pattern | another_pattern => {
|
||||
ALongStructName {
|
||||
...
|
||||
}
|
||||
}
|
||||
// To splitting the pattern.
|
||||
```
|
||||
|
||||
Never break after `=>` without using the block form of the body.
|
||||
|
||||
If the left-hand side must be split and there is an `if` clause, break before
|
||||
the `if` and block indent. In this case, always use a block body and start the
|
||||
body on a new line:
|
||||
|
||||
```rust
|
||||
a_very_long_pattern | another_pattern
|
||||
if expr =>
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
If required to break the pattern, put each clause of the pattern on its own
|
||||
line with no additional indent, breaking before the `|`. If there is an `if`
|
||||
clause, then you must use the above form:
|
||||
|
||||
```rust
|
||||
a_very_long_pattern
|
||||
| another_pattern
|
||||
| yet_another_pattern
|
||||
| a_forth_pattern => {
|
||||
...
|
||||
}
|
||||
a_very_long_pattern
|
||||
| another_pattern
|
||||
| yet_another_pattern
|
||||
| a_forth_pattern
|
||||
if expr =>
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
If the pattern is multi-line, and the last line is less wide than the indent, do
|
||||
not put the `if` clause on a newline. E.g.,
|
||||
|
||||
```rust
|
||||
Token::Dimension {
|
||||
value,
|
||||
ref unit,
|
||||
..
|
||||
} if num_context.is_ok(context.parsing_mode, value) => {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
If every clause in a pattern is *small*, but does not fit on one line, then the
|
||||
pattern may be formatted across multiple lines with as many clauses per line as
|
||||
possible. Again break before a `|`:
|
||||
|
||||
```rust
|
||||
foo | bar | baz
|
||||
| qux => {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
We define a pattern clause to be *small* if it matches the following grammar:
|
||||
|
||||
```
|
||||
[small, ntp]:
|
||||
- single token
|
||||
- `&[single-line, ntp]`
|
||||
|
||||
[small]:
|
||||
- `[small, ntp]`
|
||||
- unary tuple constructor `([small, ntp])`
|
||||
- `&[small]`
|
||||
```
|
||||
|
||||
E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not.
|
||||
|
||||
|
||||
### Combinable expressions
|
||||
|
||||
Where a function call has a single argument, and that argument is formatted
|
||||
across multiple-lines, the outer call may be formatted as if it were a single-
|
||||
line call. The same combining behaviour may be applied to any similar
|
||||
expressions which have multi-line, block-indented lists of sub-expressions
|
||||
delimited by parentheses (e.g., macros or tuple struct literals). E.g.,
|
||||
|
||||
```rust
|
||||
foo(bar(
|
||||
an_expr,
|
||||
another_expr,
|
||||
))
|
||||
|
||||
let x = foo(Bar {
|
||||
field: whatever,
|
||||
});
|
||||
|
||||
foo(|param| {
|
||||
action();
|
||||
foo(param)
|
||||
})
|
||||
```
|
||||
|
||||
Such behaviour should extend recursively, however, tools may choose to limit the
|
||||
depth of nesting.
|
||||
|
||||
Only where the multi-line sub-expression is a closure with an explicit block,
|
||||
this combining behaviour may be used where there are other arguments, as long as
|
||||
all the arguments and the first line of the closure fit on the first line, the
|
||||
closure is the last argument, and there is only one closure argument:
|
||||
|
||||
```rust
|
||||
foo(first_arg, x, |param| {
|
||||
action();
|
||||
foo(param)
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
### Ranges
|
||||
|
||||
Do not put spaces in ranges, e.g., `0..10`, `x..=y`, `..x.len()`, `foo..`.
|
||||
|
||||
When writing a range with both upper and lower bounds, if the line must be
|
||||
broken, break before the range operator and block indent the second line:
|
||||
|
||||
```rust
|
||||
a_long_expression
|
||||
..another_long_expression
|
||||
```
|
||||
|
||||
For the sake of indicating precedence, we recommend that if either bound is a
|
||||
compound expression, then use parentheses around it, e.g., `..(x + 1)`,
|
||||
`(x.f)..(x.f.len())`, or `0..(x - 10)`.
|
||||
|
||||
|
||||
### Hexadecimal literals
|
||||
|
||||
Hexadecimal literals may use upper- or lower-case letters, but they must not be
|
||||
mixed within the same literal. Projects should use the same case for all
|
||||
literals, but we do not make a recommendation for either lower- or upper-case.
|
||||
Tools should have an option to convert mixed case literals to upper-case, and
|
||||
may have an option to convert all literals to either lower- or upper-case.
|
||||
|
||||
|
||||
## Patterns
|
||||
|
||||
Patterns should be formatted like their corresponding expressions. See the
|
||||
section on `match` for additional formatting for patterns in match arms.
|
565
src/doc/style-guide/src/items.md
Normal file
565
src/doc/style-guide/src/items.md
Normal file
|
@ -0,0 +1,565 @@
|
|||
## Items
|
||||
|
||||
`extern crate` statements must be first in a file. They must be ordered
|
||||
alphabetically.
|
||||
|
||||
`use` statements, and module *declarations* (`mod foo;`, not `mod { ... }`)
|
||||
must come before other items. We recommend that imports come before module
|
||||
declarations; if imports and modules are separated, then they should be ordered
|
||||
alphabetically. When sorting, `self` and `super` must come before any other
|
||||
names. Module declarations should not be moved if they are annotated with
|
||||
`#[macro_use]`, since that may be semantics changing.
|
||||
|
||||
Tools should make the above ordering optional.
|
||||
|
||||
|
||||
### Function definitions
|
||||
|
||||
In Rust, one finds functions by searching for `fn [function-name]`; It's
|
||||
important that you style your code so that it's very searchable in this way.
|
||||
|
||||
The proper ordering and spacing is:
|
||||
|
||||
```rust
|
||||
[pub] [unsafe] [extern ["ABI"]] fn foo(arg1: i32, arg2: i32) -> i32 {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Avoid comments within the signature itself.
|
||||
|
||||
If the function signature does not fit on one line, then break after the opening
|
||||
parenthesis and before the closing parenthesis and put each argument on its own
|
||||
block-indented line. For example,
|
||||
|
||||
```rust
|
||||
fn foo(
|
||||
arg1: i32,
|
||||
arg2: i32,
|
||||
) -> i32 {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Note the trailing comma on the last argument.
|
||||
|
||||
|
||||
### Tuples and tuple structs
|
||||
|
||||
Write the type list as you would a parameter list to a function.
|
||||
|
||||
Build a tuple or tuple struct as you would call a function.
|
||||
|
||||
#### Single-line
|
||||
|
||||
```rust
|
||||
struct Bar(Type1, Type2);
|
||||
|
||||
let x = Bar(11, 22);
|
||||
let y = (11, 22, 33);
|
||||
```
|
||||
|
||||
### Enums
|
||||
|
||||
In the declaration, put each variant on its own line, block indented.
|
||||
|
||||
Format each variant accordingly as either a struct, tuple struct, or identifier,
|
||||
which doesn't require special formatting (but without the `struct` keyword.
|
||||
|
||||
```rust
|
||||
enum FooBar {
|
||||
First(u32),
|
||||
Second,
|
||||
Error {
|
||||
err: Box<Error>,
|
||||
line: u32,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
If a struct variant is [*small*](index.html#small-items), it may be formatted on
|
||||
one line. In this case, do not use a trailing comma for the field list, but do
|
||||
put spaces around each brace:
|
||||
|
||||
```rust
|
||||
enum FooBar {
|
||||
Error { err: Box<Error>, line: u32 },
|
||||
}
|
||||
```
|
||||
|
||||
In an enum with multiple struct variants, if any struct variant is written on
|
||||
multiple lines, then the multi-line formatting should be used for all struct
|
||||
variants. However, such a situation might be an indication that you should
|
||||
factor out the fields of the variant into their own struct.
|
||||
|
||||
|
||||
### Structs and Unions
|
||||
|
||||
Struct names follow on the same line as the `struct` keyword, with the opening
|
||||
brace on the same line when it fits within the right margin. All struct fields
|
||||
are indented once and end with a trailing comma. The closing brace is not
|
||||
indented and appears on its own line.
|
||||
|
||||
```rust
|
||||
struct Foo {
|
||||
a: A,
|
||||
b: B,
|
||||
}
|
||||
```
|
||||
|
||||
If and only if the type of a field does not fit within the right margin, it is
|
||||
pulled down to its own line and indented again.
|
||||
|
||||
```rust
|
||||
struct Foo {
|
||||
a: A,
|
||||
long_name:
|
||||
LongType,
|
||||
}
|
||||
```
|
||||
|
||||
Prefer using a unit struct (e.g., `struct Foo;`) to an empty struct (e.g.,
|
||||
`struct Foo();` or `struct Foo {}`, these only exist to simplify code
|
||||
generation), but if you must use an empty struct, keep it on one line with no
|
||||
space between the braces: `struct Foo;` or `struct Foo {}`.
|
||||
|
||||
The same guidelines are used for untagged union declarations.
|
||||
|
||||
```rust
|
||||
union Foo {
|
||||
a: A,
|
||||
b: B,
|
||||
long_name:
|
||||
LongType,
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Tuple structs
|
||||
|
||||
Put the whole struct on one line if possible. Types in the parentheses should be
|
||||
separated by a comma and space with no trailing comma. No spaces around the
|
||||
parentheses or semi-colon:
|
||||
|
||||
```rust
|
||||
pub struct Foo(String, u8);
|
||||
```
|
||||
|
||||
Prefer unit structs to empty tuple structs (these only exist to simplify code
|
||||
generation), e.g., `struct Foo;` rather than `struct Foo();`.
|
||||
|
||||
For more than a few fields, prefer a proper struct with named fields. Given
|
||||
this, a tuple struct should always fit on one line. If it does not, block format
|
||||
the fields with a field on each line and a trailing comma:
|
||||
|
||||
```rust
|
||||
pub struct Foo(
|
||||
String,
|
||||
u8,
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
### Traits
|
||||
|
||||
Trait items should be block-indented. If there are no items, the trait may be
|
||||
formatted on a single line. Otherwise there should be line-breaks after the
|
||||
opening brace and before the closing brace:
|
||||
|
||||
```rust
|
||||
trait Foo {}
|
||||
|
||||
pub trait Bar {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
If the trait has bounds, there should be a space after the colon but not before
|
||||
and before and after each `+`, e.g.,
|
||||
|
||||
```rust
|
||||
trait Foo: Debug + Bar {}
|
||||
```
|
||||
|
||||
Prefer not to line-break in the bounds if possible (consider using a `where`
|
||||
clause). Prefer to break between bounds than to break any individual bound. If
|
||||
you must break the bounds, put each bound (including the first) on its own
|
||||
block-indented line, break before the `+` and put the opening brace on its own
|
||||
line:
|
||||
|
||||
```rust
|
||||
pub trait IndexRanges:
|
||||
Index<Range<usize>, Output=Self>
|
||||
+ Index<RangeTo<usize>, Output=Self>
|
||||
+ Index<RangeFrom<usize>, Output=Self>
|
||||
+ Index<RangeFull, Output=Self>
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Impls
|
||||
|
||||
Impl items should be block indented. If there are no items, the impl may be
|
||||
formatted on a single line. Otherwise there should be line-breaks after the
|
||||
opening brace and before the closing brace:
|
||||
|
||||
```rust
|
||||
impl Foo {}
|
||||
|
||||
impl Bar for Foo {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Avoid line-breaking in the signature if possible. If a line break is required in
|
||||
a non-inherent impl, break immediately before `for`, block indent the concrete type
|
||||
and put the opening brace on its own line:
|
||||
|
||||
```rust
|
||||
impl Bar
|
||||
for Foo
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Extern crate
|
||||
|
||||
`extern crate foo;`
|
||||
|
||||
Use spaces around keywords, no spaces around the semi-colon.
|
||||
|
||||
|
||||
### Modules
|
||||
|
||||
```rust
|
||||
mod foo {
|
||||
}
|
||||
```
|
||||
|
||||
```rust
|
||||
mod foo;
|
||||
```
|
||||
|
||||
Use spaces around keywords and before the opening brace, no spaces around the
|
||||
semi-colon.
|
||||
|
||||
### macro\_rules!
|
||||
|
||||
Use `{}` for the full definition of the macro.
|
||||
|
||||
```rust
|
||||
macro_rules! foo {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Generics
|
||||
|
||||
Prefer to put a generics clause on one line. Break other parts of an item
|
||||
declaration rather than line-breaking a generics clause. If a generics clause is
|
||||
large enough to require line-breaking, you should prefer to use a `where` clause
|
||||
instead.
|
||||
|
||||
Do not put spaces before or after `<` nor before `>`. Only put a space after `>`
|
||||
if it is followed by a word or opening brace, not an opening parenthesis. There
|
||||
should be a space after each comma and no trailing comma.
|
||||
|
||||
```rust
|
||||
fn foo<T: Display, U: Debug>(x: Vec<T>, y: Vec<U>) ...
|
||||
|
||||
impl<T: Display, U: Debug> SomeType<T, U> { ...
|
||||
```
|
||||
|
||||
If the generics clause must be formatted across multiple lines, each parameter
|
||||
should have its own block-indented line, there should be newlines after the
|
||||
opening bracket and before the closing bracket, and the should be a trailing
|
||||
comma.
|
||||
|
||||
```rust
|
||||
fn foo<
|
||||
T: Display,
|
||||
U: Debug,
|
||||
>(x: Vec<T>, y: Vec<U>) ...
|
||||
```
|
||||
|
||||
If an associated type is bound in a generic type, then there should be spaces on
|
||||
either side of the `=`:
|
||||
|
||||
```rust
|
||||
<T: Example<Item = u32>>
|
||||
```
|
||||
|
||||
Prefer to use single-letter names for generic parameters.
|
||||
|
||||
|
||||
### `where` clauses
|
||||
|
||||
These rules apply for `where` clauses on any item.
|
||||
|
||||
A `where` clause may immediately follow a closing bracket of any kind.
|
||||
Otherwise, it must start a new line, with no indent. Each component of a `where`
|
||||
clause must be on its own line and be block indented. There should be a trailing
|
||||
comma, unless the clause is terminated with a semicolon. If the `where` clause
|
||||
is followed by a block (or assignment), the block should be started on a new
|
||||
line. Examples:
|
||||
|
||||
```rust
|
||||
fn function<T, U>(args)
|
||||
where
|
||||
T: Bound,
|
||||
U: AnotherBound,
|
||||
{
|
||||
body
|
||||
}
|
||||
|
||||
fn foo<T>(
|
||||
args
|
||||
) -> ReturnType
|
||||
where
|
||||
T: Bound,
|
||||
{
|
||||
body
|
||||
}
|
||||
|
||||
fn foo<T, U>(
|
||||
args,
|
||||
) where
|
||||
T: Bound,
|
||||
U: AnotherBound,
|
||||
{
|
||||
body
|
||||
}
|
||||
|
||||
fn foo<T, U>(
|
||||
args
|
||||
) -> ReturnType
|
||||
where
|
||||
T: Bound,
|
||||
U: AnotherBound; // Note, no trailing comma.
|
||||
|
||||
// Note that where clauses on `type` aliases are not enforced and should not
|
||||
// be used.
|
||||
type Foo<T>
|
||||
where
|
||||
T: Bound
|
||||
= Bar<T>;
|
||||
```
|
||||
|
||||
If a `where` clause is very short, we recommend using an inline bound on the
|
||||
type parameter.
|
||||
|
||||
|
||||
If a component of a `where` clause is long, it may be broken before `+` and
|
||||
further block indented. Each bound should go on its own line. E.g.,
|
||||
|
||||
```rust
|
||||
impl<T: ?Sized, Idx> IndexRanges<Idx> for T
|
||||
where
|
||||
T: Index<Range<Idx>, Output = Self::Output>
|
||||
+ Index<RangeTo<Idx>, Output = Self::Output>
|
||||
+ Index<RangeFrom<Idx>, Output = Self::Output>
|
||||
+ Index<RangeInclusive<Idx>, Output = Self::Output>
|
||||
+ Index<RangeToInclusive<Idx>, Output = Self::Output> + Index<RangeFull>
|
||||
```
|
||||
|
||||
#### Option - `where_single_line`
|
||||
|
||||
`where_single_line` is `false` by default. If `true`, then a where clause with
|
||||
exactly one component may be formatted on a single line if the rest of the
|
||||
item's signature is also kept on one line. In this case, there is no need for a
|
||||
trailing comma and if followed by a block, no need for a newline before the
|
||||
block. E.g.,
|
||||
|
||||
```rust
|
||||
// May be single-lined.
|
||||
fn foo<T>(args) -> ReturnType
|
||||
where T: Bound {
|
||||
body
|
||||
}
|
||||
|
||||
// Must be multi-lined.
|
||||
fn foo<T>(
|
||||
args
|
||||
) -> ReturnType
|
||||
where
|
||||
T: Bound,
|
||||
{
|
||||
body
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Type aliases
|
||||
|
||||
Type aliases should generally be kept on one line. If necessary to break the
|
||||
line, do so after the `=`; the right-hand-side should be block indented:
|
||||
|
||||
```rust
|
||||
pub type Foo = Bar<T>;
|
||||
|
||||
// If multi-line is required
|
||||
type VeryLongType<T, U: SomeBound> =
|
||||
AnEvenLongerType<T, U, Foo<T>>;
|
||||
```
|
||||
|
||||
Where possible avoid `where` clauses and keep type constraints inline. Where
|
||||
that is not possible split the line before and after the `where` clause (and
|
||||
split the `where` clause as normal), e.g.,
|
||||
|
||||
```rust
|
||||
type VeryLongType<T, U>
|
||||
where
|
||||
T: U::AnAssociatedType,
|
||||
U: SomeBound,
|
||||
= AnEvenLongerType<T, U, Foo<T>>;
|
||||
```
|
||||
|
||||
|
||||
### Associated types
|
||||
|
||||
Associated types should follow the guidelines above for type aliases. Where an
|
||||
associated type has a bound, there should be a space after the colon but not
|
||||
before:
|
||||
|
||||
```rust
|
||||
pub type Foo: Bar;
|
||||
```
|
||||
|
||||
|
||||
### extern items
|
||||
|
||||
When writing extern items (such as `extern "C" fn`), always be explicit about
|
||||
the ABI. For example, write `extern "C" fn foo ...`, not `extern fn foo ...`, or
|
||||
`extern "C" { ... }`.
|
||||
|
||||
|
||||
### Imports (`use` statements)
|
||||
|
||||
If an import can be formatted on one line, do so. There should be no spaces
|
||||
around braces.
|
||||
|
||||
```rust
|
||||
use a::b::c;
|
||||
use a::b::d::*;
|
||||
use a::b::{foo, bar, baz};
|
||||
```
|
||||
|
||||
|
||||
#### Large list imports
|
||||
|
||||
Prefer to use multiple imports rather than a multi-line import. However, tools
|
||||
should not split imports by default (they may offer this as an option).
|
||||
|
||||
If an import does require multiple lines (either because a list of single names
|
||||
does not fit within the max width, or because of the rules for nested imports
|
||||
below), then break after the opening brace and before the closing brace, use a
|
||||
trailing comma, and block indent the names.
|
||||
|
||||
|
||||
```rust
|
||||
// Prefer
|
||||
foo::{long, list, of, imports};
|
||||
foo::{more, imports};
|
||||
|
||||
// If necessary
|
||||
foo::{
|
||||
long, list, of, imports, more,
|
||||
imports, // Note trailing comma
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
#### Ordering of imports
|
||||
|
||||
A *group* of imports is a set of imports on the same or sequential lines. One or
|
||||
more blank lines or other items (e.g., a function) separate groups of imports.
|
||||
|
||||
Within a group of imports, imports must be sorted ascii-betically. Groups of
|
||||
imports must not be merged or re-ordered.
|
||||
|
||||
|
||||
E.g., input:
|
||||
|
||||
```rust
|
||||
use d;
|
||||
use c;
|
||||
|
||||
use b;
|
||||
use a;
|
||||
```
|
||||
|
||||
output:
|
||||
|
||||
```rust
|
||||
use c;
|
||||
use d;
|
||||
|
||||
use a;
|
||||
use b;
|
||||
```
|
||||
|
||||
Because of `macro_use`, attributes must also start a new group and prevent
|
||||
re-ordering.
|
||||
|
||||
Note that tools which only have access to syntax (such as Rustfmt) cannot tell
|
||||
which imports are from an external crate or the std lib, etc.
|
||||
|
||||
|
||||
#### Ordering list import
|
||||
|
||||
Names in a list import must be sorted ascii-betically, but with `self` and
|
||||
`super` first, and groups and glob imports last. This applies recursively. For
|
||||
example, `a::*` comes before `b::a` but `a::b` comes before `a::*`. E.g.,
|
||||
`use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};`.
|
||||
|
||||
|
||||
#### Normalisation
|
||||
|
||||
Tools must make the following normalisations:
|
||||
|
||||
* `use a::self;` -> `use a;`
|
||||
* `use a::{};` -> (nothing)
|
||||
* `use a::{b};` -> `use a::b;`
|
||||
|
||||
And must apply these recursively.
|
||||
|
||||
Tools must not otherwise merge or un-merge import lists or adjust glob imports
|
||||
(without an explicit option).
|
||||
|
||||
|
||||
#### Nested imports
|
||||
|
||||
If there are any nested imports in a list import, then use the multi-line form,
|
||||
even if the import fits on one line. Each nested import must be on its own line,
|
||||
but non-nested imports must be grouped on as few lines as possible.
|
||||
|
||||
For example,
|
||||
|
||||
```rust
|
||||
use a::b::{
|
||||
x, y, z,
|
||||
u::{...},
|
||||
w::{...},
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
#### Merging/un-merging imports
|
||||
|
||||
An example:
|
||||
|
||||
```rust
|
||||
// Un-merged
|
||||
use a::b;
|
||||
use a::c::d;
|
||||
|
||||
// Merged
|
||||
use a::{b, c::d};
|
||||
```
|
||||
|
||||
Tools must not merge or un-merge imports by default. They may offer merging or
|
||||
un-merging as an option.
|
51
src/doc/style-guide/src/principles.md
Normal file
51
src/doc/style-guide/src/principles.md
Normal file
|
@ -0,0 +1,51 @@
|
|||
# Guiding principles and rationale
|
||||
|
||||
When deciding on style guidelines, the style team tried to be guided by the
|
||||
following principles (in rough priority order):
|
||||
|
||||
* readability
|
||||
- scan-ability
|
||||
- avoiding misleading formatting
|
||||
- accessibility - readable and editable by users using the the widest
|
||||
variety of hardware, including non-visual accessibility interfaces
|
||||
- readability of code when quoted in rustc error messages
|
||||
|
||||
* aesthetics
|
||||
- sense of 'beauty'
|
||||
- consistent with other languages/tools
|
||||
|
||||
* specifics
|
||||
- compatibility with version control practices - preserving diffs,
|
||||
merge-friendliness, etc.
|
||||
- preventing right-ward drift
|
||||
- minimising vertical space
|
||||
|
||||
* application
|
||||
- ease of manual application
|
||||
- ease of implementation (in Rustfmt, and in other tools/editors/code generators)
|
||||
- internal consistency
|
||||
- simplicity of formatting rules
|
||||
|
||||
|
||||
## Overarching guidelines
|
||||
|
||||
Prefer block indent over visual indent. E.g.,
|
||||
|
||||
```rust
|
||||
// Block indent
|
||||
a_function_call(
|
||||
foo,
|
||||
bar,
|
||||
);
|
||||
|
||||
// Visual indent
|
||||
a_function_call(foo,
|
||||
bar);
|
||||
```
|
||||
|
||||
This makes for smaller diffs (e.g., if `a_function_call` is renamed in the above
|
||||
example) and less rightward drift.
|
||||
|
||||
Lists should have a trailing comma when followed by a newline, see the block
|
||||
indent example above. This choice makes moving code (e.g., by copy and paste)
|
||||
easier and makes smaller diffs.
|
150
src/doc/style-guide/src/statements.md
Normal file
150
src/doc/style-guide/src/statements.md
Normal file
|
@ -0,0 +1,150 @@
|
|||
### Let statements
|
||||
|
||||
There should be spaces after the `:` and on both sides of the `=` (if they are
|
||||
present). No space before the semi-colon.
|
||||
|
||||
```rust
|
||||
// A comment.
|
||||
let pattern: Type = expr;
|
||||
|
||||
let pattern;
|
||||
let pattern: Type;
|
||||
let pattern = expr;
|
||||
```
|
||||
|
||||
If possible the declaration should be formatted on a single line. If this is not
|
||||
possible, then try splitting after the `=`, if the declaration can fit on two
|
||||
lines. The expression should be block indented.
|
||||
|
||||
```rust
|
||||
let pattern: Type =
|
||||
expr;
|
||||
```
|
||||
|
||||
If the first line does not fit on a single line, then split after the colon,
|
||||
using block indentation. If the type covers multiple lines, even after line-
|
||||
breaking after the `:`, then the first line may be placed on the same line as
|
||||
the `:`, subject to the [combining rules](https://github.com/rust-lang-nursery/fmt-rfcs/issues/61) (WIP).
|
||||
|
||||
|
||||
```rust
|
||||
let pattern:
|
||||
Type =
|
||||
expr;
|
||||
```
|
||||
|
||||
e.g,
|
||||
|
||||
```rust
|
||||
let Foo {
|
||||
f: abcd,
|
||||
g: qwer,
|
||||
}: Foo<Bar> =
|
||||
Foo { f, g };
|
||||
|
||||
let (abcd,
|
||||
defg):
|
||||
Baz =
|
||||
{ ... }
|
||||
```
|
||||
|
||||
If the expression covers multiple lines, if the first line of the expression
|
||||
fits in the remaining space, it stays on the same line as the `=`, the rest of the
|
||||
expression is not indented. If the first line does not fit, then it should start
|
||||
on the next lines, and should be block indented. If the expression is a block
|
||||
and the type or pattern cover multiple lines, then the opening brace should be
|
||||
on a new line and not indented (this provides separation for the interior of the
|
||||
block from the type), otherwise the opening brace follows the `=`.
|
||||
|
||||
Examples:
|
||||
|
||||
```rust
|
||||
let foo = Foo {
|
||||
f: abcd,
|
||||
g: qwer,
|
||||
};
|
||||
|
||||
let foo =
|
||||
ALongName {
|
||||
f: abcd,
|
||||
g: qwer,
|
||||
};
|
||||
|
||||
let foo: Type = {
|
||||
an_expression();
|
||||
...
|
||||
};
|
||||
|
||||
let foo:
|
||||
ALongType =
|
||||
{
|
||||
an_expression();
|
||||
...
|
||||
};
|
||||
|
||||
let Foo {
|
||||
f: abcd,
|
||||
g: qwer,
|
||||
}: Foo<Bar> = Foo {
|
||||
f: blimblimblim,
|
||||
g: blamblamblam,
|
||||
};
|
||||
|
||||
let Foo {
|
||||
f: abcd,
|
||||
g: qwer,
|
||||
}: Foo<Bar> = foo(
|
||||
blimblimblim,
|
||||
blamblamblam,
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
### Macros in statement position
|
||||
|
||||
A macro use in statement position should use parentheses or square brackets as
|
||||
delimiters and should be terminated with a semi-colon. There should be no spaces
|
||||
between the name, `!`, the delimiters, or the `;`.
|
||||
|
||||
```rust
|
||||
// A comment.
|
||||
a_macro!(...);
|
||||
```
|
||||
|
||||
|
||||
### Expressions in statement position
|
||||
|
||||
There should be no space between the expression and the semi-colon.
|
||||
|
||||
```
|
||||
<expr>;
|
||||
```
|
||||
|
||||
All expressions in statement position should be terminated with a semi-colon,
|
||||
unless they end with a block or are used as the value for a block.
|
||||
|
||||
E.g.,
|
||||
|
||||
```rust
|
||||
{
|
||||
an_expression();
|
||||
expr_as_value()
|
||||
}
|
||||
|
||||
return foo();
|
||||
|
||||
loop {
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
Use a semi-colon where an expression has void type, even if it could be
|
||||
propagated. E.g.,
|
||||
|
||||
```rust
|
||||
fn foo() { ... }
|
||||
|
||||
fn bar() {
|
||||
foo();
|
||||
}
|
||||
```
|
58
src/doc/style-guide/src/types.md
Normal file
58
src/doc/style-guide/src/types.md
Normal file
|
@ -0,0 +1,58 @@
|
|||
## Types and Bounds
|
||||
|
||||
### Single line formatting
|
||||
|
||||
* `[T]` no spaces
|
||||
* `[T; expr]`, e.g., `[u32; 42]`, `[Vec<Foo>; 10 * 2 + foo()]` (space after colon, no spaces around square brackets)
|
||||
* `*const T`, `*mut T` (no space after `*`, space before type)
|
||||
* `&'a T`, `&T`, `&'a mut T`, `&mut T` (no space after `&`, single spaces separating other words)
|
||||
* `unsafe extern "C" fn<'a, 'b, 'c>(T, U, V) -> W` or `fn()` (single spaces around keyowrds and sigils, and after commas, no trailing commas, no spaces around brackets)
|
||||
* `!` should be treated like any other type name, `Name`
|
||||
* `(A, B, C, D)` (spaces after commas, no spaces around parens, no trailing comma unless it is a one-tuple)
|
||||
* `<Baz<T> as SomeTrait>::Foo::Bar` or `Foo::Bar` or `::Foo::Bar` (no spaces around `::` or angle brackets, single spaces around `as`)
|
||||
* `Foo::Bar<T, U, V>` (spaces after commas, no trailing comma, no spaces around angle brackets)
|
||||
* `T + T + T` (single spaces between types, and `+`).
|
||||
* `impl T + T + T` (single spaces between keyword, types, and `+`).
|
||||
|
||||
Parentheses used in types should not be surrounded by whitespace, e.g., `(Foo)`
|
||||
|
||||
|
||||
### Line breaks
|
||||
|
||||
Avoid breaking lines in types where possible. Prefer breaking at outermost scope, e.g., prefer
|
||||
|
||||
```rust
|
||||
Foo<
|
||||
Bar,
|
||||
Baz<Type1, Type2>,
|
||||
>
|
||||
```
|
||||
|
||||
to
|
||||
|
||||
```rust
|
||||
Foo<Bar, Baz<
|
||||
Type1,
|
||||
Type2,
|
||||
>>
|
||||
```
|
||||
|
||||
`[T; expr]` may be broken after the `;` if necessary.
|
||||
|
||||
Function types may be broken following the rules for function declarations.
|
||||
|
||||
Generic types may be broken following the rules for generics.
|
||||
|
||||
Types with `+` may be broken after any `+` using block indent and breaking before the `+`. When breaking such a type, all `+`s should be line broken, e.g.,
|
||||
|
||||
```rust
|
||||
impl Clone
|
||||
+ Copy
|
||||
+ Debug
|
||||
|
||||
Box<
|
||||
Clone
|
||||
+ Copy
|
||||
+ Debug
|
||||
>
|
||||
```
|
|
@ -218,55 +218,55 @@ pre.rust a,
|
|||
.sidebar h2 a,
|
||||
.sidebar h3 a,
|
||||
.mobile-topbar h2 a,
|
||||
h1.fqn a,
|
||||
h1 a,
|
||||
.search-results a,
|
||||
.module-item .stab,
|
||||
.import-item .stab,
|
||||
.result-name .primitive > i, .result-name .keyword > i,
|
||||
.content .method .where,
|
||||
.content .fn .where,
|
||||
.content .where.fmt-newline {
|
||||
.method .where,
|
||||
.fn .where,
|
||||
.where.fmt-newline {
|
||||
color: var(--main-color);
|
||||
}
|
||||
|
||||
.content span.enum, .content a.enum,
|
||||
.content span.struct, .content a.struct,
|
||||
.content span.union, .content a.union,
|
||||
.content span.primitive, .content a.primitive,
|
||||
.content span.type, .content a.type,
|
||||
.content span.foreigntype, .content a.foreigntype {
|
||||
span.enum, a.enum,
|
||||
span.struct, a.struct,
|
||||
span.union, a.union,
|
||||
span.primitive, a.primitive,
|
||||
span.type, a.type,
|
||||
span.foreigntype, a.foreigntype {
|
||||
color: var(--type-link-color);
|
||||
}
|
||||
|
||||
.content span.trait, .content a.trait,
|
||||
.content span.traitalias, .content a.traitalias {
|
||||
span.trait, a.trait,
|
||||
span.traitalias, a.traitalias {
|
||||
color: var(--trait-link-color);
|
||||
}
|
||||
|
||||
.content span.associatedtype, .content a.associatedtype,
|
||||
.content span.constant, .content a.constant,
|
||||
.content span.static, .content a.static {
|
||||
span.associatedtype, a.associatedtype,
|
||||
span.constant, a.constant,
|
||||
span.static, a.static {
|
||||
color: var(--assoc-item-link-color);
|
||||
}
|
||||
|
||||
.content span.fn, .content a.fn,
|
||||
.content .fnname,
|
||||
.content span.method, .content a.method,
|
||||
.content span.tymethod, .content a.tymethod {
|
||||
span.fn, a.fn,
|
||||
.fnname,
|
||||
span.method, a.method,
|
||||
span.tymethod, a.tymethod {
|
||||
color: var(--function-link-color);
|
||||
}
|
||||
|
||||
.content span.attr, .content a.attr,
|
||||
.content span.derive, .content a.derive,
|
||||
.content span.macro, .content a.macro {
|
||||
span.attr, a.attr,
|
||||
span.derive, a.derive,
|
||||
span.macro, a.macro {
|
||||
color: var(--macro-link-color);
|
||||
}
|
||||
|
||||
.content span.mod, .content a.mod, .block a.current.mod {
|
||||
span.mod, a.mod {
|
||||
color: var(--mod-link-color);
|
||||
}
|
||||
|
||||
.content span.keyword, .content a.keyword {
|
||||
span.keyword, a.keyword {
|
||||
color: var(--keyword-link-color);
|
||||
}
|
||||
|
||||
|
@ -685,9 +685,9 @@ pre, .rustdoc.source .example-wrap {
|
|||
}
|
||||
|
||||
/* Shift "where ..." part of method or fn definition down a line */
|
||||
.content .method .where,
|
||||
.content .fn .where,
|
||||
.content .where.fmt-newline {
|
||||
.method .where,
|
||||
.fn .where,
|
||||
.where.fmt-newline {
|
||||
display: block;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ input:focus + .slider {
|
|||
h1, h2, h3, h4 {
|
||||
color: white;
|
||||
}
|
||||
h1.fqn a {
|
||||
h1 a {
|
||||
color: #fff;
|
||||
}
|
||||
h4 {
|
||||
|
|
|
@ -451,7 +451,6 @@ function loadCss(cssFileName) {
|
|||
const name = item[0];
|
||||
const desc = item[1]; // can be null
|
||||
|
||||
let klass = shortty;
|
||||
let path;
|
||||
if (shortty === "mod") {
|
||||
path = name + "/index.html";
|
||||
|
@ -459,13 +458,12 @@ function loadCss(cssFileName) {
|
|||
path = shortty + "." + name + ".html";
|
||||
}
|
||||
const current_page = document.location.href.split("/").pop();
|
||||
if (path === current_page) {
|
||||
klass += " current";
|
||||
}
|
||||
const link = document.createElement("a");
|
||||
link.href = path;
|
||||
link.title = desc;
|
||||
link.className = klass;
|
||||
if (path === current_page) {
|
||||
link.className = "current";
|
||||
}
|
||||
link.textContent = name;
|
||||
const li = document.createElement("li");
|
||||
li.appendChild(link);
|
||||
|
|
|
@ -13,72 +13,72 @@ reload:
|
|||
|
||||
// Struct
|
||||
assert-css: (
|
||||
".sidebar a.struct:not(.current)",
|
||||
".sidebar .block.struct a:not(.current)",
|
||||
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.struct:not(.current)"
|
||||
move-cursor-to: ".sidebar .block.struct a:not(.current)"
|
||||
assert-css: (
|
||||
".sidebar a.struct:hover",
|
||||
".sidebar .block.struct a:hover",
|
||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
// Enum
|
||||
assert-css: (
|
||||
".sidebar a.enum",
|
||||
".sidebar .block.enum a",
|
||||
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.enum"
|
||||
move-cursor-to: ".sidebar .block.enum a"
|
||||
assert-css: (
|
||||
".sidebar a.enum:hover",
|
||||
".sidebar .block.enum a:hover",
|
||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
// Union
|
||||
assert-css: (
|
||||
".sidebar a.union",
|
||||
".sidebar .block.union a",
|
||||
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.union"
|
||||
move-cursor-to: ".sidebar .block.union a"
|
||||
assert-css: (
|
||||
".sidebar a.union:hover",
|
||||
".sidebar .block.union a:hover",
|
||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
// Trait
|
||||
assert-css: (
|
||||
".sidebar a.trait",
|
||||
".sidebar .block.trait a",
|
||||
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.trait"
|
||||
move-cursor-to: ".sidebar .block.trait a"
|
||||
assert-css: (
|
||||
".sidebar a.trait:hover",
|
||||
".sidebar .block.trait a:hover",
|
||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
// Function
|
||||
assert-css: (
|
||||
".sidebar a.fn",
|
||||
".sidebar .block.fn a",
|
||||
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.fn"
|
||||
move-cursor-to: ".sidebar .block.fn a"
|
||||
assert-css: (
|
||||
".sidebar a.fn:hover",
|
||||
".sidebar .block.fn a:hover",
|
||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
// Type definition
|
||||
assert-css: (
|
||||
".sidebar a.type",
|
||||
".sidebar .block.type a",
|
||||
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.type"
|
||||
move-cursor-to: ".sidebar .block.type a"
|
||||
assert-css: (
|
||||
".sidebar a.type:hover",
|
||||
".sidebar .block.type a:hover",
|
||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
// Keyword
|
||||
assert-css: (
|
||||
".sidebar a.keyword",
|
||||
".sidebar .block.keyword a",
|
||||
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.keyword"
|
||||
move-cursor-to: ".sidebar .block.keyword a"
|
||||
assert-css: (
|
||||
".sidebar a.keyword:hover",
|
||||
".sidebar .block.keyword a:hover",
|
||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
|
||||
|
@ -88,72 +88,72 @@ reload:
|
|||
|
||||
// Struct
|
||||
assert-css: (
|
||||
".sidebar a.struct:not(.current)",
|
||||
".sidebar .block.struct a:not(.current)",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.struct:not(.current)"
|
||||
move-cursor-to: ".sidebar .block.struct a:not(.current)"
|
||||
assert-css: (
|
||||
".sidebar a.struct:hover",
|
||||
".sidebar .block.struct a:hover",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||
)
|
||||
// Enum
|
||||
assert-css: (
|
||||
".sidebar a.enum",
|
||||
".sidebar .block.enum a",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.enum"
|
||||
move-cursor-to: ".sidebar .block.enum a"
|
||||
assert-css: (
|
||||
".sidebar a.enum:hover",
|
||||
".sidebar .block.enum a:hover",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||
)
|
||||
// Union
|
||||
assert-css: (
|
||||
".sidebar a.union",
|
||||
".sidebar .block.union a",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.union"
|
||||
move-cursor-to: ".sidebar .block.union a"
|
||||
assert-css: (
|
||||
".sidebar a.union:hover",
|
||||
".sidebar .block.union a:hover",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||
)
|
||||
// Trait
|
||||
assert-css: (
|
||||
".sidebar a.trait",
|
||||
".sidebar .block.trait a",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.trait"
|
||||
move-cursor-to: ".sidebar .block.trait a"
|
||||
assert-css: (
|
||||
".sidebar a.trait:hover",
|
||||
".sidebar .block.trait a:hover",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||
)
|
||||
// Function
|
||||
assert-css: (
|
||||
".sidebar a.fn",
|
||||
".sidebar .block.fn a",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.fn"
|
||||
move-cursor-to: ".sidebar .block.fn a"
|
||||
assert-css: (
|
||||
".sidebar a.fn:hover",
|
||||
".sidebar .block.fn a:hover",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||
)
|
||||
// Type definition
|
||||
assert-css: (
|
||||
".sidebar a.type",
|
||||
".sidebar .block.type a",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.type"
|
||||
move-cursor-to: ".sidebar .block.type a"
|
||||
assert-css: (
|
||||
".sidebar a.type:hover",
|
||||
".sidebar .block.type a:hover",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||
)
|
||||
// Keyword
|
||||
assert-css: (
|
||||
".sidebar a.keyword",
|
||||
".sidebar .block.keyword a",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.keyword"
|
||||
move-cursor-to: ".sidebar .block.keyword a"
|
||||
assert-css: (
|
||||
".sidebar a.keyword:hover",
|
||||
".sidebar .block.keyword a:hover",
|
||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||
)
|
||||
|
||||
|
@ -163,71 +163,71 @@ reload:
|
|||
|
||||
// Struct
|
||||
assert-css: (
|
||||
".sidebar a.struct:not(.current)",
|
||||
".sidebar .block.struct a:not(.current)",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.struct:not(.current)"
|
||||
move-cursor-to: ".sidebar .block.struct a:not(.current)"
|
||||
assert-css: (
|
||||
".sidebar a.struct:hover",
|
||||
".sidebar .block.struct a:hover",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
||||
)
|
||||
// Enum
|
||||
assert-css: (
|
||||
".sidebar a.enum",
|
||||
".sidebar .block.enum a",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.enum"
|
||||
move-cursor-to: ".sidebar .block.enum a"
|
||||
assert-css: (
|
||||
".sidebar a.enum:hover",
|
||||
".sidebar .block.enum a:hover",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
||||
)
|
||||
// Union
|
||||
assert-css: (
|
||||
".sidebar a.union",
|
||||
".sidebar .block.union a",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.union"
|
||||
move-cursor-to: ".sidebar .block.union a"
|
||||
assert-css: (
|
||||
".sidebar a.union:hover",
|
||||
".sidebar .block.union a:hover",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
||||
)
|
||||
// Trait
|
||||
assert-css: (
|
||||
".sidebar a.trait",
|
||||
".sidebar .block.trait a",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.trait"
|
||||
move-cursor-to: ".sidebar .block.trait a"
|
||||
assert-css: (
|
||||
".sidebar a.trait:hover",
|
||||
".sidebar .block.trait a:hover",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
||||
)
|
||||
// Function
|
||||
assert-css: (
|
||||
".sidebar a.fn",
|
||||
".sidebar .block.fn a",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.fn"
|
||||
move-cursor-to: ".sidebar .block.fn a"
|
||||
assert-css: (
|
||||
".sidebar a.fn:hover",
|
||||
".sidebar .block.fn a:hover",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
||||
)
|
||||
// Type definition
|
||||
assert-css: (
|
||||
".sidebar a.type",
|
||||
".sidebar .block.type a",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.type"
|
||||
move-cursor-to: ".sidebar .block.type a"
|
||||
assert-css: (
|
||||
".sidebar a.type:hover",
|
||||
".sidebar .block.type a:hover",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
||||
)
|
||||
// Keyword
|
||||
assert-css: (
|
||||
".sidebar a.keyword",
|
||||
".sidebar .block.keyword a",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar a.keyword"
|
||||
move-cursor-to: ".sidebar .block.keyword a"
|
||||
assert-css: (
|
||||
".sidebar a.keyword:hover",
|
||||
".sidebar .block.keyword a:hover",
|
||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// This test ensures that the reexport of a macro doesn't make the original macro
|
||||
// displayed twice in the sidebar.
|
||||
goto: "file://" + |DOC_PATH| + "/test_docs/macro.repro.html"
|
||||
wait-for: ".sidebar-elems .macro .macro"
|
||||
wait-for: ".sidebar-elems .block.macro a"
|
||||
assert-count: ("//*[@class='sidebar-elems']//*[@class='block macro']//a[text()='repro']", 1)
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
// check-pass
|
||||
// normalize-stderr-test: "`.*`" -> "`DEF_ID`"
|
||||
// normalize-stdout-test: "`.*`" -> "`DEF_ID`"
|
||||
// edition:2018
|
||||
|
||||
pub async fn f() -> impl std::fmt::Debug {
|
||||
// rustdoc doesn't care that this is infinitely sized
|
||||
#[derive(Debug)]
|
||||
enum E {
|
||||
//~^ ERROR recursive type `f::{closure#0}::E` has infinite size
|
||||
This(E),
|
||||
Unit,
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
error[E0072]: recursive type `DEF_ID` has infinite size
|
||||
--> $DIR/infinite-recursive-type-impl-trait-return.rs:7:5
|
||||
|
|
||||
LL | enum E {
|
||||
| ^^^^^^
|
||||
LL |
|
||||
LL | This(E),
|
||||
| - recursive without indirection
|
||||
|
|
||||
help: insert some indirection (e.g., a `DEF_ID`) to break the cycle
|
||||
|
|
||||
LL | This(Box<E>),
|
||||
| ++++ +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `DEF_ID`.
|
|
@ -1,6 +1,8 @@
|
|||
// check-pass
|
||||
|
||||
fn f() -> impl Sized {
|
||||
// rustdoc doesn't care that this is infinitely sized
|
||||
enum E {
|
||||
//~^ ERROR recursive type `f::E` has infinite size
|
||||
V(E),
|
||||
}
|
||||
unimplemented!()
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
error[E0072]: recursive type `f::E` has infinite size
|
||||
--> $DIR/infinite-recursive-type-impl-trait.rs:2:5
|
||||
|
|
||||
LL | enum E {
|
||||
| ^^^^^^
|
||||
LL |
|
||||
LL | V(E),
|
||||
| - recursive without indirection
|
||||
|
|
||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||
|
|
||||
LL | V(Box<E>),
|
||||
| ++++ +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0072`.
|
|
@ -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]>;
|
||||
|
|
30
src/test/ui/consts/issue-102117.rs
Normal file
30
src/test/ui/consts/issue-102117.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
#![feature(inline_const, const_type_id)]
|
||||
|
||||
use std::alloc::Layout;
|
||||
use std::any::TypeId;
|
||||
use std::mem::transmute;
|
||||
use std::ptr::drop_in_place;
|
||||
|
||||
pub struct VTable {
|
||||
layout: Layout,
|
||||
type_id: TypeId,
|
||||
drop_in_place: unsafe fn(*mut ()),
|
||||
}
|
||||
|
||||
impl VTable {
|
||||
pub fn new<T>() -> &'static Self {
|
||||
const {
|
||||
//~^ ERROR the parameter type `T` may not live long enough
|
||||
//~| ERROR the parameter type `T` may not live long enough
|
||||
&VTable {
|
||||
layout: Layout::new::<T>(),
|
||||
type_id: TypeId::of::<T>(),
|
||||
drop_in_place: unsafe {
|
||||
transmute::<unsafe fn(*mut T), unsafe fn(*mut ())>(drop_in_place::<T>)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
37
src/test/ui/consts/issue-102117.stderr
Normal file
37
src/test/ui/consts/issue-102117.stderr
Normal file
|
@ -0,0 +1,37 @@
|
|||
error[E0310]: the parameter type `T` may not live long enough
|
||||
--> $DIR/issue-102117.rs:16:9
|
||||
|
|
||||
LL | / const {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | &VTable {
|
||||
... |
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_________^ ...so that the type `T` will meet its required lifetime bounds
|
||||
|
|
||||
help: consider adding an explicit lifetime bound...
|
||||
|
|
||||
LL | pub fn new<T: 'static>() -> &'static Self {
|
||||
| +++++++++
|
||||
|
||||
error[E0310]: the parameter type `T` may not live long enough
|
||||
--> $DIR/issue-102117.rs:16:9
|
||||
|
|
||||
LL | / const {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | &VTable {
|
||||
... |
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_________^ ...so that the type `T` will meet its required lifetime bounds
|
||||
|
|
||||
help: consider adding an explicit lifetime bound...
|
||||
|
|
||||
LL | pub fn new<T: 'static>() -> &'static Self {
|
||||
| +++++++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0310`.
|
|
@ -3,7 +3,6 @@ use std::collections::BTreeSet;
|
|||
#[derive(Hash)]
|
||||
pub enum ElemDerived {
|
||||
//~^ ERROR recursive type `ElemDerived` has infinite size
|
||||
//~| ERROR cycle detected when computing drop-check constraints for `ElemDerived`
|
||||
A(ElemDerived)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ error[E0072]: recursive type `ElemDerived` has infinite size
|
|||
|
|
||||
LL | pub enum ElemDerived {
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL |
|
||||
LL | A(ElemDerived)
|
||||
| ----------- recursive without indirection
|
||||
|
|
||||
|
@ -12,20 +12,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
|||
LL | A(Box<ElemDerived>)
|
||||
| ++++ +
|
||||
|
||||
error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived`
|
||||
--> $DIR/issue-72554.rs:4:1
|
||||
|
|
||||
LL | pub enum ElemDerived {
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: ...which immediately requires computing drop-check constraints for `ElemDerived` again
|
||||
note: cycle used when computing drop-check constraints for `Elem`
|
||||
--> $DIR/issue-72554.rs:11:1
|
||||
|
|
||||
LL | pub enum Elem {
|
||||
| ^^^^^^^^^^^^^
|
||||
error: aborting due to previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0072, E0391.
|
||||
For more information about an error, try `rustc --explain E0072`.
|
||||
For more information about this error, try `rustc --explain E0072`.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Test that disallow lifetime parameters that are unused.
|
||||
|
||||
enum Foo<'a> { //~ ERROR parameter `'a` is never used
|
||||
//~^ ERROR recursive types `Foo` and `Bar` have infinite size
|
||||
Foo1(Bar<'a>)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
error[E0072]: recursive types `Foo` and `Bar` have infinite size
|
||||
--> $DIR/variance-regions-unused-indirect.rs:3:1
|
||||
|
|
||||
LL | enum Foo<'a> {
|
||||
| ^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | Foo1(Bar<'a>)
|
||||
| ------- recursive without indirection
|
||||
...
|
||||
LL | enum Bar<'a> {
|
||||
| ^^^^^^^^^^^^
|
||||
LL | Bar1(Foo<'a>)
|
||||
| ------- recursive without indirection
|
||||
|
|
||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||
|
|
||||
LL ~ Foo1(Box<Bar<'a>>)
|
||||
LL | }
|
||||
LL |
|
||||
LL | enum Bar<'a> {
|
||||
LL ~ Bar1(Box<Foo<'a>>)
|
||||
|
|
||||
|
||||
error[E0392]: parameter `'a` is never used
|
||||
--> $DIR/variance-regions-unused-indirect.rs:3:10
|
||||
|
|
||||
|
@ -7,13 +30,14 @@ LL | enum Foo<'a> {
|
|||
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
|
||||
|
||||
error[E0392]: parameter `'a` is never used
|
||||
--> $DIR/variance-regions-unused-indirect.rs:7:10
|
||||
--> $DIR/variance-regions-unused-indirect.rs:8:10
|
||||
|
|
||||
LL | enum Bar<'a> {
|
||||
| ^^ unused parameter
|
||||
|
|
||||
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0392`.
|
||||
Some errors have detailed explanations: E0072, E0392.
|
||||
For more information about an error, try `rustc --explain E0072`.
|
||||
|
|
|
@ -189,6 +189,11 @@ trigger_files = [
|
|||
"src/tools/bump-stage0",
|
||||
]
|
||||
|
||||
[autolabel."T-style"]
|
||||
trigger_files = [
|
||||
"src/doc/style-guide",
|
||||
]
|
||||
|
||||
[autolabel."A-translation"]
|
||||
trigger_files = [
|
||||
"compiler/rustc_error_messages",
|
||||
|
|
Loading…
Add table
Reference in a new issue