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.
|
// modify their locations.
|
||||||
let all_facts = &mut None;
|
let all_facts = &mut None;
|
||||||
let mut constraints = Default::default();
|
let mut constraints = Default::default();
|
||||||
|
let mut type_tests = Default::default();
|
||||||
let mut closure_bounds = Default::default();
|
let mut closure_bounds = Default::default();
|
||||||
let mut liveness_constraints =
|
let mut liveness_constraints =
|
||||||
LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body)));
|
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 this.cx.borrowck_context.constraints.outlives_constraints,
|
||||||
&mut constraints,
|
&mut constraints,
|
||||||
);
|
);
|
||||||
|
mem::swap(&mut this.cx.borrowck_context.constraints.type_tests, &mut type_tests);
|
||||||
mem::swap(
|
mem::swap(
|
||||||
&mut this.cx.borrowck_context.constraints.closure_bounds_mapping,
|
&mut this.cx.borrowck_context.constraints.closure_bounds_mapping,
|
||||||
&mut closure_bounds,
|
&mut closure_bounds,
|
||||||
|
@ -619,6 +621,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||||
swap_constraints(self);
|
swap_constraints(self);
|
||||||
|
|
||||||
let locations = location.to_locations();
|
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() {
|
for constraint in constraints.outlives().iter() {
|
||||||
let mut constraint = constraint.clone();
|
let mut constraint = constraint.clone();
|
||||||
constraint.locations = locations;
|
constraint.locations = locations;
|
||||||
|
|
|
@ -18,3 +18,12 @@ middle_limit_invalid =
|
||||||
|
|
||||||
middle_const_eval_non_int =
|
middle_const_eval_non_int =
|
||||||
constant evaluation of enum discriminant resulted in non-integer
|
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 =
|
passes_inner_crate_level_attr =
|
||||||
crate-level attribute should be in the root module
|
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}
|
.warn = {-passes_previously_accepted}
|
||||||
.note = {-passes_see_issue(issue: "80564")}
|
.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}
|
.warn = {-passes_previously_accepted}
|
||||||
.note = {-passes_see_issue(issue: "80564")}
|
.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}
|
.warn = {-passes_previously_accepted}
|
||||||
.note = {-passes_see_issue(issue: "65833")}
|
.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
|
.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 =
|
passes_no_coverage_propagate =
|
||||||
`#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
|
`#[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
|
.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
|
.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
|
.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
|
.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}
|
.warn = {-passes_previously_accepted}
|
||||||
.label = {passes_should_be_applied_to_fn.label}
|
.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
|
.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
|
passes_doc_alias_duplicated = doc alias is duplicated
|
||||||
.label = first defined here
|
.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 =
|
passes_doc_alias_malformed =
|
||||||
doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
|
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 =
|
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
|
`#[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_first =
|
||||||
passes_doc_inline_conflict_second = ...conflicts with this attribute
|
this attribute...
|
||||||
passes_doc_inline_conflict = conflicting doc inlining attributes
|
|
||||||
|
passes_doc_inline_conflict_second =
|
||||||
|
{"."}..conflicts with this attribute
|
||||||
|
|
||||||
|
passes_doc_inline_conflict =
|
||||||
|
conflicting doc inlining attributes
|
||||||
.help = remove one of the conflicting 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
|
.label = only applicable on `use` items
|
||||||
.not_a_use_item_label = not a `use` item
|
.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
|
.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 =
|
passes_doc_attr_not_crate_level =
|
||||||
`#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
|
`#![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
|
.suggestion = to apply to the crate, use an inner attribute
|
||||||
.help = 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
|
.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)`
|
.note = `doc(spotlight)` was renamed to `doc(notable_trait)`
|
||||||
.suggestion = use `notable_trait` instead
|
.suggestion = use `notable_trait` instead
|
||||||
.no_op_note = `doc(spotlight)` is now a no-op
|
.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
|
.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
|
.label = is not a struct, enum or type alias
|
||||||
|
|
||||||
passes_allow_incoherent_impl =
|
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
|
`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`
|
.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
|
.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}
|
.warn = {-passes_previously_accepted}
|
||||||
.label = {passes_should_be_applied_to_fn.label}
|
.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}
|
.warn = {-passes_previously_accepted}
|
||||||
.label = not an `extern` block
|
.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}
|
.warn = {-passes_previously_accepted}
|
||||||
.label = not a foreign function or static
|
.label = not a foreign function or static
|
||||||
.help = try `#[link(name = "{$value}")]` instead
|
.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
|
.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
|
.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
|
.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
|
.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
|
.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 ->
|
.label = there {$arg_count ->
|
||||||
[one] is
|
[one] is
|
||||||
*[other] are
|
*[other] are
|
||||||
|
@ -181,93 +233,438 @@ passes_rustc_legacy_const_generics_index_exceed = index exceeds number of argume
|
||||||
*[other] arguments
|
*[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}
|
.warn = {-passes_previously_accepted}
|
||||||
.label = not a function or static
|
.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}
|
.warn = {-passes_previously_accepted}
|
||||||
.label = foreign {$foreign_item_kind}
|
.label = foreign {$foreign_item_kind}
|
||||||
.note = symbol names in extern blocks are not mangled
|
.note = symbol names in extern blocks are not mangled
|
||||||
.suggestion = remove this attribute
|
.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}
|
.warn = {-passes_previously_accepted}
|
||||||
.label = not a free function, impl method or static
|
.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
|
.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_1 = expected: `natvis_file = "..."`
|
||||||
.note_2 = OR
|
.note_2 = OR
|
||||||
.note_3 = expected: `gdb_script_file = "..."`
|
.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`
|
.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
|
.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 =
|
passes_unused_default_method_body_const_note =
|
||||||
`default_method_body_is_const` has been replaced with `#[const_trait]` on traits
|
`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
|
.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
|
.label = not a function or closure
|
||||||
|
|
||||||
passes_unused_duplicate = unused attribute
|
passes_unused_duplicate =
|
||||||
|
unused attribute
|
||||||
.suggestion = remove this attribute
|
.suggestion = remove this attribute
|
||||||
.note = attribute also specified here
|
.note = attribute also specified here
|
||||||
.warn = {-passes_previously_accepted}
|
.warn = {-passes_previously_accepted}
|
||||||
|
|
||||||
passes_unused_multiple = multiple `{$name}` attributes
|
passes_unused_multiple =
|
||||||
|
multiple `{$name}` attributes
|
||||||
.suggestion = remove this attribute
|
.suggestion = remove this attribute
|
||||||
.note = attribute also specified here
|
.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
|
.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
|
.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
|
.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
|
.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
|
.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, !> {
|
impl<'a> DiagnosticBuilder<'a, !> {
|
||||||
/// Convenience function for internal use, clients should use one of the
|
/// Convenience function for internal use, clients should use one of the
|
||||||
/// `struct_*` methods on [`Handler`].
|
/// `struct_*` methods on [`Handler`].
|
||||||
|
|
|
@ -374,7 +374,7 @@ pub use diagnostic::{
|
||||||
AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay,
|
AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay,
|
||||||
DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
|
DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
|
||||||
};
|
};
|
||||||
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee};
|
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
|
||||||
use std::backtrace::Backtrace;
|
use std::backtrace::Backtrace;
|
||||||
|
|
||||||
/// A handler deals with errors and other compiler output.
|
/// 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 def = tcx.adt_def(def_id);
|
||||||
let span = tcx.def_span(def_id);
|
let span = tcx.def_span(def_id);
|
||||||
def.destructor(tcx); // force the destructor to be evaluated
|
def.destructor(tcx); // force the destructor to be evaluated
|
||||||
let _ = tcx.representability(def_id);
|
|
||||||
|
|
||||||
if def.repr().simd() {
|
if def.repr().simd() {
|
||||||
check_simd(tcx, span, def_id);
|
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 def = tcx.adt_def(def_id);
|
||||||
let span = tcx.def_span(def_id);
|
let span = tcx.def_span(def_id);
|
||||||
def.destructor(tcx); // force the destructor to be evaluated
|
def.destructor(tcx); // force the destructor to be evaluated
|
||||||
let _ = tcx.representability(def_id);
|
|
||||||
check_transparent(tcx, span, def);
|
check_transparent(tcx, span, def);
|
||||||
check_union_fields(tcx, span, def_id);
|
check_union_fields(tcx, span, def_id);
|
||||||
check_packed(tcx, span, def);
|
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);
|
detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
|
||||||
|
|
||||||
let _ = tcx.representability(def_id);
|
|
||||||
check_transparent(tcx, sp, def);
|
check_transparent(tcx, sp, def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1041,6 +1041,8 @@ fn check_type_defn<'tcx, F>(
|
||||||
) where
|
) where
|
||||||
F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>,
|
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| {
|
enter_wf_checking_ctxt(tcx, item.span, item.def_id.def_id, |wfcx| {
|
||||||
let variants = lookup_fields(wfcx);
|
let variants = lookup_fields(wfcx);
|
||||||
let packed = tcx.adt_def(item.def_id).repr().packed();
|
let packed = tcx.adt_def(item.def_id).repr().packed();
|
||||||
|
|
|
@ -613,16 +613,8 @@ rustc_queries! {
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
}
|
}
|
||||||
|
|
||||||
// The cycle error here should be reported as an error by `check_representable`.
|
query adt_sized_constraint(key: DefId) -> &'tcx [Ty<'tcx>] {
|
||||||
// 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> {
|
|
||||||
desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) }
|
desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) }
|
||||||
cycle_delay_bug
|
|
||||||
}
|
}
|
||||||
|
|
||||||
query adt_dtorck_constraint(
|
query adt_dtorck_constraint(
|
||||||
|
|
|
@ -26,9 +26,6 @@ use super::{
|
||||||
Destructor, FieldDef, GenericPredicates, ReprOptions, Ty, TyCtxt, VariantDef, VariantDiscr,
|
Destructor, FieldDef, GenericPredicates, ReprOptions, Ty, TyCtxt, VariantDef, VariantDiscr,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone, HashStable, Debug)]
|
|
||||||
pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]);
|
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
#[derive(HashStable, TyEncodable, TyDecodable)]
|
#[derive(HashStable, TyEncodable, TyDecodable)]
|
||||||
pub struct AdtFlags: u32 {
|
pub struct AdtFlags: u32 {
|
||||||
|
@ -563,7 +560,7 @@ impl<'tcx> AdtDef<'tcx> {
|
||||||
/// Due to normalization being eager, this applies even if
|
/// Due to normalization being eager, this applies even if
|
||||||
/// the associated type is behind a pointer (e.g., issue #31299).
|
/// the associated type is behind a pointer (e.g., issue #31299).
|
||||||
pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> {
|
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> {
|
impl<'a> IntoDiagnostic<'a, !> for LayoutError<'a> {
|
||||||
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'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> {
|
impl<'tcx> fmt::Display for LayoutError<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
|
|
|
@ -32,7 +32,7 @@ use crate::ty::layout::TyAndLayout;
|
||||||
use crate::ty::subst::{GenericArg, SubstsRef};
|
use crate::ty::subst::{GenericArg, SubstsRef};
|
||||||
use crate::ty::util::AlwaysRequiresDrop;
|
use crate::ty::util::AlwaysRequiresDrop;
|
||||||
use crate::ty::GeneratorDiagnosticData;
|
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 as ast;
|
||||||
use rustc_ast::expand::allocator::AllocatorKind;
|
use rustc_ast::expand::allocator::AllocatorKind;
|
||||||
use rustc_attr as attr;
|
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 as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_middle::ty::Representability;
|
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::query::QueryInfo;
|
||||||
use rustc_query_system::Value;
|
use rustc_query_system::Value;
|
||||||
use rustc_span::def_id::LocalDefId;
|
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<'_>> {
|
impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
|
||||||
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
|
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
|
||||||
let err = tcx.ty_error();
|
let err = tcx.ty_error();
|
||||||
|
|
|
@ -4,10 +4,13 @@
|
||||||
//! conflicts between multiple such attributes attached to the same
|
//! conflicts between multiple such attributes attached to the same
|
||||||
//! item.
|
//! 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_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
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_expand::base::resolve_path;
|
||||||
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -164,17 +167,17 @@ impl CheckAttrVisitor<'_> {
|
||||||
sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
|
sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
|
||||||
sym::deprecated => self.check_deprecated(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::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::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
|
||||||
sym::macro_export => self.check_macro_export(hir_id, attr, target),
|
sym::macro_export => self.check_macro_export(hir_id, attr, target),
|
||||||
sym::ignore | sym::should_panic | sym::proc_macro_derive => {
|
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 => {
|
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 => {
|
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),
|
sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id),
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -351,31 +354,17 @@ impl CheckAttrVisitor<'_> {
|
||||||
hir_id: HirId,
|
hir_id: HirId,
|
||||||
attr: &Attribute,
|
attr: &Attribute,
|
||||||
target: Target,
|
target: Target,
|
||||||
allowed_targets: &[Target],
|
allowed_target: Target,
|
||||||
) {
|
) {
|
||||||
if !allowed_targets.iter().any(|t| t == &target) {
|
if target != allowed_target {
|
||||||
let name = attr.name_or_empty();
|
self.tcx.emit_spanned_lint(
|
||||||
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(
|
|
||||||
UNUSED_ATTRIBUTES,
|
UNUSED_ATTRIBUTES,
|
||||||
hir_id,
|
hir_id,
|
||||||
attr.span,
|
attr.span,
|
||||||
&format!("`#[{name}]` only has an effect on {}", supported_names),
|
OnlyHasEffectOn {
|
||||||
|lint| lint,
|
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::Param(def_id) => tcx.item_name(def_id).to_string(),
|
||||||
ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (article, allowed_targets) = match hint.name_or_empty() {
|
match hint.name_or_empty() {
|
||||||
sym::C => {
|
sym::C => {
|
||||||
is_c = true;
|
is_c = true;
|
||||||
match target {
|
match target {
|
||||||
Target::Struct | Target::Union | Target::Enum => continue,
|
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 => {
|
sym::align => {
|
||||||
|
@ -1626,12 +1620,20 @@ impl CheckAttrVisitor<'_> {
|
||||||
|
|
||||||
match target {
|
match target {
|
||||||
Target::Struct | Target::Union | Target::Enum | Target::Fn => continue,
|
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 => {
|
sym::packed => {
|
||||||
if target != Target::Struct && target != Target::Union {
|
if target != Target::Struct && target != Target::Union {
|
||||||
("a", "struct or union")
|
self.tcx.sess.emit_err(AttrApplication::StructUnion {
|
||||||
|
hint_span: hint.span(),
|
||||||
|
span,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1639,7 +1641,9 @@ impl CheckAttrVisitor<'_> {
|
||||||
sym::simd => {
|
sym::simd => {
|
||||||
is_simd = true;
|
is_simd = true;
|
||||||
if target != Target::Struct {
|
if target != Target::Struct {
|
||||||
("a", "struct")
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.emit_err(AttrApplication::Struct { hint_span: hint.span(), span });
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1648,7 +1652,12 @@ impl CheckAttrVisitor<'_> {
|
||||||
is_transparent = true;
|
is_transparent = true;
|
||||||
match target {
|
match target {
|
||||||
Target::Struct | Target::Union | Target::Enum => continue,
|
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
|
sym::i8
|
||||||
|
@ -1665,35 +1674,18 @@ impl CheckAttrVisitor<'_> {
|
||||||
| sym::usize => {
|
| sym::usize => {
|
||||||
int_reprs += 1;
|
int_reprs += 1;
|
||||||
if target != Target::Enum {
|
if target != Target::Enum {
|
||||||
("an", "enum")
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.emit_err(AttrApplication::Enum { hint_span: hint.span(), span });
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(UnrecognizedReprHint { span: hint.span() });
|
||||||
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();
|
|
||||||
|
|
||||||
continue;
|
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.
|
// Just point at all repr hints if there are any incompatibilities.
|
||||||
|
@ -1703,14 +1695,9 @@ impl CheckAttrVisitor<'_> {
|
||||||
// Error on repr(transparent, <anything else>).
|
// Error on repr(transparent, <anything else>).
|
||||||
if is_transparent && hints.len() > 1 {
|
if is_transparent && hints.len() > 1 {
|
||||||
let hint_spans: Vec<_> = hint_spans.clone().collect();
|
let hint_spans: Vec<_> = hint_spans.clone().collect();
|
||||||
struct_span_err!(
|
self.tcx
|
||||||
self.tcx.sess,
|
.sess
|
||||||
hint_spans,
|
.emit_err(TransparentIncompatible { hint_spans, target: target.to_string() });
|
||||||
E0692,
|
|
||||||
"transparent {} cannot have other repr hints",
|
|
||||||
target
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
// Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
|
// Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
|
||||||
if (int_reprs > 1)
|
if (int_reprs > 1)
|
||||||
|
@ -1862,14 +1849,12 @@ impl CheckAttrVisitor<'_> {
|
||||||
|
|
||||||
match std::fs::File::open(&file) {
|
match std::fs::File::open(&file) {
|
||||||
Ok(_) => true,
|
Ok(_) => true,
|
||||||
Err(err) => {
|
Err(error) => {
|
||||||
self.tcx
|
self.tcx.sess.emit_err(DebugVisualizerUnreadable {
|
||||||
.sess
|
span: meta_item.span,
|
||||||
.struct_span_err(
|
file: &file,
|
||||||
meta_item.span,
|
error,
|
||||||
&format!("couldn't read {}: {}", file.display(), err),
|
});
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2180,25 +2165,11 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
|
||||||
if attr.style == AttrStyle::Inner {
|
if attr.style == AttrStyle::Inner {
|
||||||
for attr_to_check in ATTRS_TO_CHECK {
|
for attr_to_check in ATTRS_TO_CHECK {
|
||||||
if attr.has_name(*attr_to_check) {
|
if attr.has_name(*attr_to_check) {
|
||||||
let mut err = tcx.sess.struct_span_err(
|
tcx.sess.emit_err(InvalidAttrAtCrateLevel {
|
||||||
attr.span,
|
span: attr.span,
|
||||||
&format!(
|
snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(),
|
||||||
"`{}` attribute cannot be used at crate level",
|
name: *attr_to_check,
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
//! through, but errors for structured control flow in a `const` should be emitted here.
|
//! through, but errors for structured control flow in a `const` should be emitted here.
|
||||||
|
|
||||||
use rustc_attr as attr;
|
use rustc_attr as attr;
|
||||||
use rustc_errors::struct_span_err;
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
|
@ -18,6 +17,8 @@ use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::{sym, Span, Symbol};
|
use rustc_span::{sym, Span, Symbol};
|
||||||
|
|
||||||
|
use crate::errors::ExprNotAllowedInContext;
|
||||||
|
|
||||||
/// An expression that is not *always* legal in a const context.
|
/// An expression that is not *always* legal in a const context.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
enum NonConstExpr {
|
enum NonConstExpr {
|
||||||
|
@ -133,18 +134,22 @@ impl<'tcx> CheckConstVisitor<'tcx> {
|
||||||
let const_kind =
|
let const_kind =
|
||||||
const_kind.expect("`const_check_violated` may only be called inside a const context");
|
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 required_gates = required_gates.unwrap_or(&[]);
|
||||||
let missing_gates: Vec<_> =
|
let missing_gates: Vec<_> =
|
||||||
required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
|
required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
|
||||||
|
|
||||||
match missing_gates.as_slice() {
|
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 @ ..] => {
|
[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);
|
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
|
// If multiple feature gates would be required to enable this expression, include
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
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 as hir;
|
||||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
|
@ -18,6 +18,8 @@ use rustc_session::lint;
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
use crate::errors::UselessAssignment;
|
||||||
|
|
||||||
// Any local node that may call something in its body block should be
|
// 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
|
// 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
|
// function, then we should explore its block to check for codes that
|
||||||
|
@ -180,19 +182,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
||||||
&& !assign.span.from_expansion()
|
&& !assign.span.from_expansion()
|
||||||
{
|
{
|
||||||
let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..));
|
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,
|
lint::builtin::DEAD_CODE,
|
||||||
assign.hir_id,
|
assign.hir_id,
|
||||||
assign.span,
|
assign.span,
|
||||||
DelayDm(|| format!(
|
UselessAssignment { is_field_assign, ty: self.typeck_results().expr_ty(lhs) }
|
||||||
"useless assignment of {} of type `{}` to itself",
|
|
||||||
if is_field_assign { "field" } else { "variable" },
|
|
||||||
self.typeck_results().expr_ty(lhs),
|
|
||||||
)),
|
|
||||||
|lint| {
|
|
||||||
lint
|
|
||||||
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::errors::DebugVisualizerUnreadable;
|
||||||
|
|
||||||
fn check_for_debugger_visualizer<'tcx>(
|
fn check_for_debugger_visualizer<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
hir_id: HirId,
|
hir_id: HirId,
|
||||||
|
@ -54,13 +56,12 @@ fn check_for_debugger_visualizer<'tcx>(
|
||||||
debugger_visualizers
|
debugger_visualizers
|
||||||
.insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type));
|
.insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type));
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(error) => {
|
||||||
tcx.sess
|
tcx.sess.emit_err(DebugVisualizerUnreadable {
|
||||||
.struct_span_err(
|
span: meta_item.span,
|
||||||
meta_item.span,
|
file: &file,
|
||||||
&format!("couldn't read {}: {}", file.display(), err),
|
error,
|
||||||
)
|
});
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,9 @@ use rustc_hir::diagnostic_items::DiagnosticItems;
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
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>(
|
fn observe_item<'tcx>(
|
||||||
tcx: TyCtxt<'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);
|
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 let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) {
|
||||||
if original_def_id != item_def_id {
|
if original_def_id != item_def_id {
|
||||||
let mut err = match tcx.hir().span_if_local(item_def_id) {
|
let orig_span = tcx.hir().span_if_local(original_def_id);
|
||||||
Some(span) => tcx
|
let orig_crate_name = if orig_span.is_some() {
|
||||||
.sess
|
None
|
||||||
.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");
|
|
||||||
} else {
|
} else {
|
||||||
err.note(&format!(
|
Some(tcx.crate_name(original_def_id.krate))
|
||||||
"the diagnostic item is first defined in crate `{}`.",
|
};
|
||||||
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 {
|
||||||
err.emit();
|
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_ast::entry::EntryPointType;
|
||||||
use rustc_errors::struct_span_err;
|
use rustc_errors::error_code;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
|
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
|
||||||
use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
|
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::config::{sigpipe, CrateType, EntryFnType};
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::symbol::sym;
|
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> {
|
struct EntryContext<'tcx> {
|
||||||
tcx: TyCtxt<'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());
|
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
|
||||||
if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym) {
|
ctxt.tcx.sess.find_by_name(attrs, sym).map(|attr| attr.span)
|
||||||
ctxt.tcx
|
|
||||||
.sess
|
|
||||||
.struct_span_err(attr.span, &format!("`{}` attribute {}", sym, details))
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
|
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) {
|
match entry_point_type(ctxt, id, at_root) {
|
||||||
EntryPointType::None => {
|
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) => {
|
_ 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");
|
for attr in [sym::start, sym::rustc_main] {
|
||||||
err_if_attr_found(ctxt, id, sym::rustc_main, "can only be used on functions");
|
if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
|
||||||
|
ctxt.tcx.sess.emit_err(AttrOnlyInFunctions { span, attr });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EntryPointType::MainNamed => (),
|
EntryPointType::MainNamed => (),
|
||||||
EntryPointType::OtherMain => {
|
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));
|
ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
|
||||||
}
|
}
|
||||||
EntryPointType::RustcMainAttr => {
|
EntryPointType::RustcMainAttr => {
|
||||||
if ctxt.attr_main_fn.is_none() {
|
if ctxt.attr_main_fn.is_none() {
|
||||||
ctxt.attr_main_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
|
ctxt.attr_main_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
|
||||||
} else {
|
} else {
|
||||||
struct_span_err!(
|
ctxt.tcx.sess.emit_err(MultipleRustcMain {
|
||||||
ctxt.tcx.sess,
|
span: ctxt.tcx.def_span(id.def_id.to_def_id()),
|
||||||
ctxt.tcx.def_span(id.def_id.to_def_id()),
|
first: ctxt.attr_main_fn.unwrap().1,
|
||||||
E0137,
|
additional: ctxt.tcx.def_span(id.def_id.to_def_id()),
|
||||||
"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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EntryPointType::Start => {
|
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() {
|
if ctxt.start_fn.is_none() {
|
||||||
ctxt.start_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
|
ctxt.start_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
|
||||||
} else {
|
} else {
|
||||||
struct_span_err!(
|
ctxt.tcx.sess.emit_err(MultipleStartFunctions {
|
||||||
ctxt.tcx.sess,
|
span: ctxt.tcx.def_span(id.def_id),
|
||||||
ctxt.tcx.def_span(id.def_id),
|
labeled: ctxt.tcx.def_span(id.def_id.to_def_id()),
|
||||||
E0138,
|
previous: ctxt.start_fn.unwrap().1,
|
||||||
"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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
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
|
// 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(_))) {
|
if let Some(def_id) = def_id.as_local() && matches!(tcx.hir().find_by_def_id(def_id), Some(Node::ForeignItem(_))) {
|
||||||
tcx.sess
|
tcx.sess.emit_err(ExternMain { span: tcx.def_span(def_id) });
|
||||||
.struct_span_err(
|
|
||||||
tcx.def_span(def_id),
|
|
||||||
"the `main` function cannot be declared in an `extern` block",
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,12 +175,7 @@ fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 {
|
||||||
sigpipe::DEFAULT
|
sigpipe::DEFAULT
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
tcx.sess
|
tcx.sess.emit_err(UnixSigpipeValues { span: attr.span });
|
||||||
.struct_span_err(
|
|
||||||
attr.span,
|
|
||||||
"valid values for `#[unix_sigpipe = \"...\"]` are `inherit`, `sig_ign`, or `sig_dfl`",
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
sigpipe::DEFAULT
|
sigpipe::DEFAULT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,52 +194,29 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is no main function.
|
// There is no main function.
|
||||||
let mut err = struct_span_err!(
|
let mut has_filename = true;
|
||||||
tcx.sess,
|
let filename = tcx.sess.local_crate_source_file.clone().unwrap_or_else(|| {
|
||||||
DUMMY_SP,
|
has_filename = false;
|
||||||
E0601,
|
Default::default()
|
||||||
"`main` function not found in crate `{}`",
|
});
|
||||||
tcx.crate_name(LOCAL_CRATE)
|
let main_def_opt = tcx.resolutions(()).main_def;
|
||||||
);
|
let diagnostic_id = error_code!(E0601);
|
||||||
let filename = &tcx.sess.local_crate_source_file;
|
let add_teach_note = tcx.sess.teach(&diagnostic_id);
|
||||||
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")
|
|
||||||
};
|
|
||||||
// The file may be empty, which leads to the diagnostic machinery not emitting this
|
// 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. This is a relatively simple way to detect that case and emit a span-less
|
||||||
// note instead.
|
// note instead.
|
||||||
if tcx.sess.source_map().lookup_line(sp.hi()).is_ok() {
|
let file_empty = !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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(main_def) = tcx.resolutions(()).main_def && main_def.opt_fn_def_id().is_none(){
|
tcx.sess.emit_err(NoMainErr {
|
||||||
// There is something at `crate::main`, but it is not a function definition.
|
sp,
|
||||||
err.span_label(main_def.span, "non-function item at `crate::main` is found");
|
crate_name: tcx.crate_name(LOCAL_CRATE),
|
||||||
}
|
has_filename,
|
||||||
|
filename,
|
||||||
if tcx.sess.teach(&err.get_code().unwrap()) {
|
file_empty,
|
||||||
err.note(
|
non_main_fns: visitor.non_main_fns.clone(),
|
||||||
"If you don't know the basics of Rust, you can go look to the Rust Book \
|
main_def_opt,
|
||||||
to get started: https://doc.rust-lang.org/book/",
|
add_teach_note,
|
||||||
);
|
});
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
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_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)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(passes::outer_crate_level_attr)]
|
#[diag(passes::outer_crate_level_attr)]
|
||||||
|
@ -526,6 +536,15 @@ pub struct DebugVisualizerInvalid {
|
||||||
pub span: Span,
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(passes::rustc_allow_const_fn_unstable)]
|
#[diag(passes::rustc_allow_const_fn_unstable)]
|
||||||
pub struct RustcAllowConstFnUnstable {
|
pub struct RustcAllowConstFnUnstable {
|
||||||
|
@ -665,3 +684,765 @@ pub struct DeprecatedAnnotationHasNoEffect {
|
||||||
#[suggestion(applicability = "machine-applicable", code = "")]
|
#[suggestion(applicability = "machine-applicable", code = "")]
|
||||||
pub span: Span,
|
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.
|
//! * Functions called by the compiler itself.
|
||||||
|
|
||||||
use crate::check_attr::target_from_impl_item;
|
use crate::check_attr::target_from_impl_item;
|
||||||
|
use crate::errors::{
|
||||||
|
DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem,
|
||||||
|
};
|
||||||
use crate::weak_lang_items;
|
use crate::weak_lang_items;
|
||||||
|
|
||||||
use rustc_errors::{pluralize, struct_span_err};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::DefId;
|
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_hir::{HirId, LangItem, LanguageItems, Target};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::cstore::ExternCrate;
|
use rustc_session::cstore::ExternCrate;
|
||||||
use rustc_span::Span;
|
use rustc_span::{symbol::kw::Empty, Span};
|
||||||
|
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
|
|
||||||
|
pub(crate) enum Duplicate {
|
||||||
|
Plain,
|
||||||
|
Crate,
|
||||||
|
CrateDepends,
|
||||||
|
}
|
||||||
|
|
||||||
struct LanguageItemCollector<'tcx> {
|
struct LanguageItemCollector<'tcx> {
|
||||||
items: LanguageItems,
|
items: LanguageItems,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
@ -34,42 +42,24 @@ impl<'tcx> LanguageItemCollector<'tcx> {
|
||||||
|
|
||||||
fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
|
fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
|
||||||
let attrs = self.tcx.hir().attrs(hir_id);
|
let attrs = self.tcx.hir().attrs(hir_id);
|
||||||
if let Some((value, span)) = extract(&attrs) {
|
if let Some((name, span)) = extract(&attrs) {
|
||||||
match ITEM_REFS.get(&value).cloned() {
|
match ITEM_REFS.get(&name).cloned() {
|
||||||
// Known lang item with attribute on correct target.
|
// Known lang item with attribute on correct target.
|
||||||
Some((item_index, expected_target)) if actual_target == expected_target => {
|
Some((item_index, expected_target)) if actual_target == expected_target => {
|
||||||
self.collect_item_extended(item_index, hir_id, span);
|
self.collect_item_extended(item_index, hir_id, span);
|
||||||
}
|
}
|
||||||
// Known lang item with attribute on incorrect target.
|
// Known lang item with attribute on incorrect target.
|
||||||
Some((_, expected_target)) => {
|
Some((_, expected_target)) => {
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(LangItemOnIncorrectTarget {
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
span,
|
||||||
E0718,
|
name,
|
||||||
"`{}` language item must be applied to a {}",
|
|
||||||
value,
|
|
||||||
expected_target,
|
expected_target,
|
||||||
)
|
actual_target,
|
||||||
.span_label(
|
});
|
||||||
span,
|
|
||||||
format!(
|
|
||||||
"attribute should be applied to a {}, not a {}",
|
|
||||||
expected_target, actual_target,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
// Unknown lang item.
|
// Unknown lang item.
|
||||||
_ => {
|
_ => {
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(UnknownLangItem { span, name });
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
|
||||||
E0522,
|
|
||||||
"definition of an unknown language item: `{}`",
|
|
||||||
value
|
|
||||||
)
|
|
||||||
.span_label(span, format!("definition of unknown language item `{}`", value))
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,74 +69,72 @@ impl<'tcx> LanguageItemCollector<'tcx> {
|
||||||
// Check for duplicates.
|
// Check for duplicates.
|
||||||
if let Some(original_def_id) = self.items.items[item_index] {
|
if let Some(original_def_id) = self.items.items[item_index] {
|
||||||
if original_def_id != item_def_id {
|
if original_def_id != item_def_id {
|
||||||
let lang_item = LangItem::from_u32(item_index as u32).unwrap();
|
let local_span = self.tcx.hir().span_if_local(item_def_id);
|
||||||
let name = lang_item.name();
|
let lang_item_name = LangItem::from_u32(item_index as u32).unwrap().name();
|
||||||
let mut err = match self.tcx.hir().span_if_local(item_def_id) {
|
let crate_name = self.tcx.crate_name(item_def_id.krate);
|
||||||
Some(span) => struct_span_err!(
|
let mut dependency_of = Empty;
|
||||||
self.tcx.sess,
|
let is_local = item_def_id.is_local();
|
||||||
span,
|
let path = if is_local {
|
||||||
E0152,
|
String::new()
|
||||||
"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");
|
|
||||||
} else {
|
} else {
|
||||||
match self.tcx.extern_crate(original_def_id) {
|
self.tcx
|
||||||
Some(ExternCrate { dependency_of, .. }) => {
|
.crate_extern_paths(item_def_id.krate)
|
||||||
err.note(&format!(
|
.iter()
|
||||||
"the lang item is first defined in crate `{}` (which `{}` depends on)",
|
.map(|p| p.display().to_string())
|
||||||
self.tcx.crate_name(original_def_id.krate),
|
.collect::<Vec<_>>()
|
||||||
self.tcx.crate_name(*dependency_of)
|
.join(", ")
|
||||||
));
|
.into()
|
||||||
}
|
};
|
||||||
_ => {
|
let first_defined_span = self.tcx.hir().span_if_local(original_def_id);
|
||||||
err.note(&format!(
|
let mut orig_crate_name = Empty;
|
||||||
"the lang item is first defined in crate `{}`.",
|
let mut orig_dependency_of = Empty;
|
||||||
self.tcx.crate_name(original_def_id.krate)
|
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),
|
None => (0, *item_span),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut at_least = false;
|
||||||
let required = match lang_item.required_generics() {
|
let required = match lang_item.required_generics() {
|
||||||
GenericRequirement::Exact(num) if num != actual_num => {
|
GenericRequirement::Exact(num) if num != actual_num => Some(num),
|
||||||
Some((format!("{}", num), pluralize!(num)))
|
|
||||||
}
|
|
||||||
GenericRequirement::Minimum(num) if actual_num < 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
|
// If the number matches, or there is no requirement, handle it normally
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((range_str, pluralized)) = required {
|
if let Some(num) = required {
|
||||||
// We are issuing E0718 "incorrect target" here, because while the
|
// We are issuing E0718 "incorrect target" here, because while the
|
||||||
// item kind of the target is correct, the target is still wrong
|
// item kind of the target is correct, the target is still wrong
|
||||||
// because of the wrong number of generic arguments.
|
// because of the wrong number of generic arguments.
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(IncorrectTarget {
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
span,
|
||||||
E0718,
|
|
||||||
"`{}` language item must be applied to a {} with {} generic argument{}",
|
|
||||||
name,
|
|
||||||
kind.descr(),
|
|
||||||
range_str,
|
|
||||||
pluralized,
|
|
||||||
)
|
|
||||||
.span_label(
|
|
||||||
generics_span,
|
generics_span,
|
||||||
format!(
|
name: name.as_str(),
|
||||||
"this {} has {} generic argument{}",
|
kind: kind.descr(),
|
||||||
kind.descr(),
|
num,
|
||||||
actual_num,
|
actual_num,
|
||||||
pluralize!(actual_num),
|
at_least,
|
||||||
),
|
});
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
|
|
||||||
// return early to not collect the lang item
|
// return early to not collect the lang item
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -3,10 +3,13 @@ use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
|
use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
|
||||||
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
||||||
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::abi::{HasDataLayout, TargetDataLayout};
|
use rustc_target::abi::{HasDataLayout, TargetDataLayout};
|
||||||
|
|
||||||
|
use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField};
|
||||||
|
|
||||||
pub fn test_layout(tcx: TyCtxt<'_>) {
|
pub fn test_layout(tcx: TyCtxt<'_>) {
|
||||||
if tcx.features().rustc_attrs {
|
if tcx.features().rustc_attrs {
|
||||||
// if the `rustc_attrs` feature is not enabled, don't bother testing layout
|
// 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 {
|
for meta_item in meta_items {
|
||||||
match meta_item.name_or_empty() {
|
match meta_item.name_or_empty() {
|
||||||
sym::abi => {
|
sym::abi => {
|
||||||
tcx.sess.span_err(
|
tcx.sess.emit_err(Abi {
|
||||||
tcx.def_span(item_def_id.to_def_id()),
|
span: tcx.def_span(item_def_id.to_def_id()),
|
||||||
&format!("abi: {:?}", ty_layout.abi),
|
abi: format!("{:?}", ty_layout.abi),
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sym::align => {
|
sym::align => {
|
||||||
tcx.sess.span_err(
|
tcx.sess.emit_err(Align {
|
||||||
tcx.def_span(item_def_id.to_def_id()),
|
span: tcx.def_span(item_def_id.to_def_id()),
|
||||||
&format!("align: {:?}", ty_layout.align),
|
align: format!("{:?}", ty_layout.align),
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sym::size => {
|
sym::size => {
|
||||||
tcx.sess.span_err(
|
tcx.sess.emit_err(Size {
|
||||||
tcx.def_span(item_def_id.to_def_id()),
|
span: tcx.def_span(item_def_id.to_def_id()),
|
||||||
&format!("size: {:?}", ty_layout.size),
|
size: format!("{:?}", ty_layout.size),
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sym::homogeneous_aggregate => {
|
sym::homogeneous_aggregate => {
|
||||||
tcx.sess.span_err(
|
tcx.sess.emit_err(HomogeneousAggregate {
|
||||||
tcx.def_span(item_def_id.to_def_id()),
|
span: tcx.def_span(item_def_id.to_def_id()),
|
||||||
&format!(
|
homogeneous_aggregate: format!(
|
||||||
"homogeneous_aggregate: {:?}",
|
"{:?}",
|
||||||
ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
|
ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env })
|
||||||
),
|
),
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sym::debug => {
|
sym::debug => {
|
||||||
let normalized_ty = tcx.normalize_erasing_regions(
|
let normalized_ty = format!(
|
||||||
param_env.with_reveal_all_normalized(tcx),
|
"{:?}",
|
||||||
ty,
|
tcx.normalize_erasing_regions(
|
||||||
);
|
param_env.with_reveal_all_normalized(tcx),
|
||||||
tcx.sess.span_err(
|
ty,
|
||||||
tcx.def_span(item_def_id.to_def_id()),
|
)
|
||||||
&format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
|
|
||||||
);
|
);
|
||||||
|
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 => {
|
name => {
|
||||||
tcx.sess.span_err(
|
tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
|
||||||
meta_item.span(),
|
|
||||||
&format!("unrecognized field name `{}`", name),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(layout_error) => {
|
Err(layout_error) => {
|
||||||
tcx.sess.span_err(
|
tcx.sess.emit_fatal(Spanned {
|
||||||
tcx.def_span(item_def_id.to_def_id()),
|
node: layout_error,
|
||||||
&format!("layout error: {:?}", 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.
|
//! This API is completely unstable and subject to change.
|
||||||
|
|
||||||
#![allow(rustc::potential_query_instability)]
|
#![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/")]
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||||
#![feature(iter_intersperse)]
|
#![feature(iter_intersperse)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
use rustc_ast::{Attribute, MetaItemKind};
|
use rustc_ast::{Attribute, MetaItemKind};
|
||||||
use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER};
|
use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER};
|
||||||
use rustc_errors::struct_span_err;
|
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::middle::lib_features::LibFeatures;
|
use rustc_middle::middle::lib_features::LibFeatures;
|
||||||
|
@ -15,6 +14,8 @@ use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::{sym, Span};
|
use rustc_span::{sym, Span};
|
||||||
|
|
||||||
|
use crate::errors::{FeaturePreviouslyDeclared, FeatureStableTwice};
|
||||||
|
|
||||||
fn new_lib_features() -> LibFeatures {
|
fn new_lib_features() -> LibFeatures {
|
||||||
LibFeatures { stable: Default::default(), unstable: Default::default() }
|
LibFeatures { stable: Default::default(), unstable: Default::default() }
|
||||||
}
|
}
|
||||||
|
@ -92,14 +93,12 @@ impl<'tcx> LibFeatureCollector<'tcx> {
|
||||||
(Some(since), _, false) => {
|
(Some(since), _, false) => {
|
||||||
if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) {
|
if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) {
|
||||||
if *prev_since != since {
|
if *prev_since != since {
|
||||||
self.span_feature_error(
|
self.tcx.sess.emit_err(FeatureStableTwice {
|
||||||
span,
|
span,
|
||||||
&format!(
|
feature,
|
||||||
"feature `{}` is declared stable since {}, \
|
since,
|
||||||
but was previously declared stable since {}",
|
prev_since: *prev_since,
|
||||||
feature, since, prev_since,
|
});
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,22 +109,17 @@ impl<'tcx> LibFeatureCollector<'tcx> {
|
||||||
self.lib_features.unstable.insert(feature, span);
|
self.lib_features.unstable.insert(feature, span);
|
||||||
}
|
}
|
||||||
(Some(_), _, true) | (None, true, _) => {
|
(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,
|
span,
|
||||||
&format!(
|
feature,
|
||||||
"feature `{}` is declared {}, but was previously declared {}",
|
declared,
|
||||||
feature,
|
prev_declared,
|
||||||
if since.is_some() { "stable" } else { "unstable" },
|
});
|
||||||
if since.is_none() { "stable" } else { "unstable" },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use Context::*;
|
use Context::*;
|
||||||
|
|
||||||
use rustc_errors::{struct_span_err, Applicability};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
|
@ -13,6 +12,11 @@ use rustc_session::Session;
|
||||||
use rustc_span::hygiene::DesugaringKind;
|
use rustc_span::hygiene::DesugaringKind;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
use crate::errors::{
|
||||||
|
BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
|
||||||
|
UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
enum Context {
|
enum Context {
|
||||||
Normal,
|
Normal,
|
||||||
|
@ -90,7 +94,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||||
Ok(loop_id) => Some(loop_id),
|
Ok(loop_id) => Some(loop_id),
|
||||||
Err(hir::LoopIdError::OutsideLoopScope) => None,
|
Err(hir::LoopIdError::OutsideLoopScope) => None,
|
||||||
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
|
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
|
None
|
||||||
}
|
}
|
||||||
Err(hir::LoopIdError::UnresolvedLabel) => None,
|
Err(hir::LoopIdError::UnresolvedLabel) => None,
|
||||||
|
@ -116,69 +123,22 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||||
match loop_kind {
|
match loop_kind {
|
||||||
None | Some(hir::LoopSource::Loop) => (),
|
None | Some(hir::LoopSource::Loop) => (),
|
||||||
Some(kind) => {
|
Some(kind) => {
|
||||||
let mut err = struct_span_err!(
|
let suggestion = format!(
|
||||||
self.sess,
|
"break{}",
|
||||||
e.span,
|
break_label
|
||||||
E0571,
|
.label
|
||||||
"`break` with value from a `{}` loop",
|
.map_or_else(String::new, |l| format!(" {}", l.ident))
|
||||||
kind.name()
|
|
||||||
);
|
);
|
||||||
err.span_label(
|
self.sess.emit_err(BreakNonLoop {
|
||||||
e.span,
|
span: e.span,
|
||||||
"can only break with a value inside `loop` or breakable block",
|
head,
|
||||||
);
|
kind: kind.name(),
|
||||||
if let Some(head) = head {
|
suggestion,
|
||||||
err.span_label(
|
loop_label,
|
||||||
head,
|
break_label: break_label.label,
|
||||||
&format!(
|
break_expr_kind: &break_expr.kind,
|
||||||
"you can't `break` with a value in a `{}` loop",
|
break_expr_span: break_expr.span,
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,19 +151,17 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||||
match destination.target_id {
|
match destination.target_id {
|
||||||
Ok(loop_id) => {
|
Ok(loop_id) => {
|
||||||
if let Node::Block(block) = self.hir_map.find(loop_id).unwrap() {
|
if let Node::Block(block) = self.hir_map.find(loop_id).unwrap() {
|
||||||
struct_span_err!(
|
self.sess.emit_err(ContinueLabeledBlock {
|
||||||
self.sess,
|
span: e.span,
|
||||||
e.span,
|
block_span: block.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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
|
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(_) => {}
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
|
@ -226,21 +184,16 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_break_cx(&self, name: &str, span: Span) {
|
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 {
|
match self.cx {
|
||||||
LabeledBlock | Loop(_) => {}
|
LabeledBlock | Loop(_) => {}
|
||||||
Closure(closure_span) => err_inside_of("a", "closure", closure_span),
|
Closure(closure_span) => {
|
||||||
AsyncClosure(closure_span) => err_inside_of("an", "`async` block", 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 => {
|
Normal | AnonConst => {
|
||||||
struct_span_err!(self.sess, span, E0268, "`{}` outside of a loop", name)
|
self.sess.emit_err(OutsideLoop { span, name });
|
||||||
.span_label(span, format!("cannot `{}` outside of a loop", name))
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,37 +204,13 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
||||||
label: &Destination,
|
label: &Destination,
|
||||||
cf_type: &str,
|
cf_type: &str,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if !span.is_desugaring(DesugaringKind::QuestionMark) && self.cx == LabeledBlock {
|
if !span.is_desugaring(DesugaringKind::QuestionMark)
|
||||||
if label.label.is_none() {
|
&& self.cx == LabeledBlock
|
||||||
struct_span_err!(
|
&& label.label.is_none()
|
||||||
self.sess,
|
{
|
||||||
span,
|
self.sess.emit_err(UnlabeledInLabeledBlock { span, cf_type });
|
||||||
E0695,
|
return true;
|
||||||
"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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
false
|
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.
|
//! Checks validity of naked functions.
|
||||||
|
|
||||||
use rustc_ast::InlineAsmOptions;
|
use rustc_ast::InlineAsmOptions;
|
||||||
use rustc_errors::{struct_span_err, Applicability};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
|
@ -14,6 +13,12 @@ use rustc_span::symbol::sym;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
|
use crate::errors::{
|
||||||
|
CannotInlineNakedFunction, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions,
|
||||||
|
NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed,
|
||||||
|
UndefinedNakedFunctionAbi,
|
||||||
|
};
|
||||||
|
|
||||||
pub(crate) fn provide(providers: &mut Providers) {
|
pub(crate) fn provide(providers: &mut Providers) {
|
||||||
*providers = Providers { check_mod_naked_functions, ..*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) {
|
fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline);
|
let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline);
|
||||||
for attr in attrs {
|
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 {
|
if abi == Abi::Rust {
|
||||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||||
let span = tcx.def_span(def_id);
|
let span = tcx.def_span(def_id);
|
||||||
tcx.struct_span_lint_hir(
|
tcx.emit_spanned_lint(
|
||||||
UNDEFINED_NAKED_FUNCTION_ABI,
|
UNDEFINED_NAKED_FUNCTION_ABI,
|
||||||
hir_id,
|
hir_id,
|
||||||
span,
|
span,
|
||||||
"Rust ABI is unsupported in naked functions",
|
UndefinedNakedFunctionAbi,
|
||||||
|lint| lint,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,12 +86,7 @@ fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
|
||||||
hir::PatKind::Wild
|
hir::PatKind::Wild
|
||||||
| hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, _, None) => {}
|
| hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, _, None) => {}
|
||||||
_ => {
|
_ => {
|
||||||
tcx.sess
|
tcx.sess.emit_err(NoPatterns { span: param.pat.span });
|
||||||
.struct_span_err(
|
|
||||||
param.pat.span,
|
|
||||||
"patterns not allowed in naked function parameters",
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,14 +116,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
|
||||||
)) = expr.kind
|
)) = expr.kind
|
||||||
{
|
{
|
||||||
if self.params.contains(var_hir_id) {
|
if self.params.contains(var_hir_id) {
|
||||||
self.tcx
|
self.tcx.sess.emit_err(ParamsNotAllowed { span: expr.span });
|
||||||
.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();
|
|
||||||
return;
|
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[..] {
|
if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
|
||||||
// Ok.
|
// Ok.
|
||||||
} else {
|
} 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 must_show_error = false;
|
||||||
let mut has_asm = false;
|
let mut has_asm = false;
|
||||||
let mut has_err = false;
|
let mut has_err = false;
|
||||||
|
let mut multiple_asms = vec![];
|
||||||
|
let mut non_asms = vec![];
|
||||||
for &(kind, span) in &this.items {
|
for &(kind, span) in &this.items {
|
||||||
match kind {
|
match kind {
|
||||||
ItemKind::Asm if has_asm => {
|
ItemKind::Asm if has_asm => {
|
||||||
must_show_error = true;
|
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::Asm => has_asm = true,
|
||||||
ItemKind::NonAsm => {
|
ItemKind::NonAsm => {
|
||||||
must_show_error = true;
|
must_show_error = true;
|
||||||
diag.span_label(span, "non-asm is unsupported in naked functions");
|
non_asms.push(span);
|
||||||
}
|
}
|
||||||
ItemKind::Err => has_err = true,
|
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
|
// errors, then don't show an additional error. This allows for appending/prepending
|
||||||
// `compile_error!("...")` statements and reduces error noise.
|
// `compile_error!("...")` statements and reduces error noise.
|
||||||
if must_show_error || !has_err {
|
if must_show_error || !has_err {
|
||||||
diag.emit();
|
tcx.sess.emit_err(NakedFunctionsAsmBlock {
|
||||||
} else {
|
span: tcx.def_span(def_id),
|
||||||
diag.cancel();
|
multiple_asms,
|
||||||
|
non_asms,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,13 +240,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
if !unsupported_operands.is_empty() {
|
if !unsupported_operands.is_empty() {
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(NakedFunctionsOperands { unsupported_operands });
|
||||||
self.tcx.sess,
|
|
||||||
unsupported_operands,
|
|
||||||
E0787,
|
|
||||||
"only `const` and `sym` operands are supported in naked functions",
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let unsupported_options: Vec<&'static str> = [
|
let unsupported_options: Vec<&'static str> = [
|
||||||
|
@ -273,14 +256,10 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if !unsupported_options.is_empty() {
|
if !unsupported_options.is_empty() {
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(NakedFunctionsAsmOptions {
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
span,
|
||||||
E0787,
|
unsupported_options: unsupported_options.join(", "),
|
||||||
"asm options unsupported in naked functions: {}",
|
});
|
||||||
unsupported_options.join(", ")
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !asm.options.contains(InlineAsmOptions::NORETURN) {
|
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)
|
.map_or_else(|| asm.template_strs.last().unwrap().2, |op| op.1)
|
||||||
.shrink_to_hi();
|
.shrink_to_hi();
|
||||||
|
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(NakedFunctionsMustUseNoreturn { span, last_span });
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
//! A pass that annotates every item and method with its stability level,
|
//! A pass that annotates every item and method with its stability level,
|
||||||
//! propagating default levels lexically from parent to children ast nodes.
|
//! 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::{
|
use rustc_attr::{
|
||||||
self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable,
|
self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable,
|
||||||
UnstableReason, VERSION_PLACEHOLDER,
|
UnstableReason, VERSION_PLACEHOLDER,
|
||||||
};
|
};
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
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 as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
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_middle::ty::{query::Providers, TyCtxt};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
|
use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
|
||||||
use rustc_session::Session;
|
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
@ -179,7 +183,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||||
if !self.in_trait_impl
|
if !self.in_trait_impl
|
||||||
|| (self.in_trait_impl && !self.tcx.is_const_fn_raw(def_id.to_def_id()))
|
|| (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 let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr {
|
||||||
if stab.is_none() {
|
if stab.is_none() {
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(DeprecatedAttribute { span: *span });
|
||||||
self.tcx.sess,
|
|
||||||
*span,
|
|
||||||
E0549,
|
|
||||||
"deprecated attribute must be paired with \
|
|
||||||
either stable or unstable attribute"
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,10 +219,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||||
if kind == AnnotationKind::Prohibited
|
if kind == AnnotationKind::Prohibited
|
||||||
|| (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
|
|| (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
|
||||||
{
|
{
|
||||||
self.tcx.sess.struct_span_err(span,"this stability annotation is useless")
|
self.tcx.sess.emit_err(UselessStability { span, item_sp });
|
||||||
.span_label(span, "useless stability annotation")
|
|
||||||
.span_label(item_sp, "the stability attribute annotates this item")
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("annotate: found {:?}", stab);
|
debug!("annotate: found {:?}", stab);
|
||||||
|
@ -239,19 +235,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
match stab_v.parse::<u64>() {
|
match stab_v.parse::<u64>() {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
self.tcx.sess.struct_span_err(span, "invalid stability version found")
|
self.tcx.sess.emit_err(InvalidStability { span, item_sp });
|
||||||
.span_label(span, "invalid stability version")
|
|
||||||
.span_label(item_sp, "the stability attribute annotates this item")
|
|
||||||
.emit();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(stab_vp) => match dep_v.parse::<u64>() {
|
Ok(stab_vp) => match dep_v.parse::<u64>() {
|
||||||
Ok(dep_vp) => match dep_vp.cmp(&stab_vp) {
|
Ok(dep_vp) => match dep_vp.cmp(&stab_vp) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
self.tcx.sess.struct_span_err(span, "an API can't be stabilized after it is deprecated")
|
self.tcx
|
||||||
.span_label(span, "invalid version")
|
.sess
|
||||||
.span_label(item_sp, "the stability attribute annotates this item")
|
.emit_err(CannotStabilizeDeprecated { span, item_sp });
|
||||||
.emit();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ordering::Equal => continue,
|
Ordering::Equal => continue,
|
||||||
|
@ -259,10 +251,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||||
},
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
if dep_v != "TBD" {
|
if dep_v != "TBD" {
|
||||||
self.tcx.sess.struct_span_err(span, "invalid deprecation version found")
|
self.tcx
|
||||||
.span_label(span, "invalid deprecation version")
|
.sess
|
||||||
.span_label(item_sp, "the stability attribute annotates this item")
|
.emit_err(InvalidDeprecationVersion { span, item_sp });
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
break;
|
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);
|
self.index.implications.insert(implied_by, feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,7 +524,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
|
||||||
let stab = self.tcx.stability().local_stability(def_id);
|
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) {
|
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());
|
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 {
|
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());
|
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
|
&& *constness == hir::Constness::Const
|
||||||
&& const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
|
&& const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
|
||||||
{
|
{
|
||||||
self.tcx
|
self.tcx.sess.emit_err(TraitImplConstStable { span: item.span });
|
||||||
.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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -929,7 +918,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
|
||||||
}
|
}
|
||||||
if !lang_features.insert(feature) {
|
if !lang_features.insert(feature) {
|
||||||
// Warn if the user enables a lang feature multiple times.
|
// 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();
|
let mut remaining_lib_features = FxIndexMap::default();
|
||||||
for (feature, span) in declared_lib_features {
|
for (feature, span) in declared_lib_features {
|
||||||
if !tcx.sess.opts.unstable_features.is_nightly_build() {
|
if !tcx.sess.opts.unstable_features.is_nightly_build() {
|
||||||
struct_span_err!(
|
tcx.sess.emit_err(FeatureOnlyOnNightly {
|
||||||
tcx.sess,
|
span: *span,
|
||||||
*span,
|
release_channel: env!("CFG_RELEASE_CHANNEL"),
|
||||||
E0554,
|
});
|
||||||
"`#![feature]` may not be used on the {} release channel",
|
|
||||||
env!("CFG_RELEASE_CHANNEL")
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
if remaining_lib_features.contains_key(&feature) {
|
if remaining_lib_features.contains_key(&feature) {
|
||||||
// Warn if the user enables a lib feature multiple times.
|
// 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);
|
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 {
|
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 {
|
for (implied_by, feature) in remaining_implications {
|
||||||
let local_defined_features = tcx.lib_features(());
|
let local_defined_features = tcx.lib_features(());
|
||||||
let span = local_defined_features
|
let span = *local_defined_features
|
||||||
.stable
|
.stable
|
||||||
.get(&feature)
|
.get(&feature)
|
||||||
.map(|(_, span)| span)
|
.map(|(_, span)| span)
|
||||||
.or_else(|| local_defined_features.unstable.get(&feature))
|
.or_else(|| local_defined_features.unstable.get(&feature))
|
||||||
.expect("feature that implied another does not exist");
|
.expect("feature that implied another does not exist");
|
||||||
tcx.sess
|
tcx.sess.emit_err(ImpliedFeatureNotExist { span, feature, implied_by });
|
||||||
.struct_span_err(
|
|
||||||
*span,
|
|
||||||
format!("feature `{implied_by}` implying `{feature}` does not exist"),
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(#44232): the `used_features` table no longer exists, so we
|
// 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}`"
|
by the feature `{implies}`"
|
||||||
),
|
),
|
||||||
|lint| {
|
|lint| {
|
||||||
lint
|
lint.span_suggestion(
|
||||||
.span_suggestion(
|
span,
|
||||||
span,
|
&format!(
|
||||||
&format!(
|
|
||||||
"if you are using features which are still unstable, change to using `{implies}`"
|
"if you are using features which are still unstable, change to using `{implies}`"
|
||||||
),
|
),
|
||||||
implies,
|
implies,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
)
|
)
|
||||||
.span_suggestion(
|
.span_suggestion(
|
||||||
tcx.sess.source_map().span_extend_to_line(span),
|
tcx.sess.source_map().span_extend_to_line(span),
|
||||||
"if you are using features which are now stable, remove this line",
|
"if you are using features which are now stable, remove this line",
|
||||||
"",
|
"",
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1120,20 +1099,3 @@ fn unnecessary_stable_feature_lint(
|
||||||
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
|
//! Validity checking for weak lang items
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::struct_span_err;
|
|
||||||
use rustc_hir::lang_items::{self, LangItem};
|
use rustc_hir::lang_items::{self, LangItem};
|
||||||
use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
|
use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
|
||||||
use rustc_middle::middle::lang_items::required;
|
use rustc_middle::middle::lang_items::required;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::config::CrateType;
|
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
|
/// 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.
|
/// language items required by this crate, but not defined yet.
|
||||||
pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItems) {
|
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 {
|
} else {
|
||||||
let span = tcx.def_span(id.def_id);
|
let span = tcx.def_span(id.def_id);
|
||||||
struct_span_err!(
|
tcx.sess.emit_err(UnknownExternLangItem { span, lang_item });
|
||||||
tcx.sess,
|
|
||||||
span,
|
|
||||||
E0264,
|
|
||||||
"unknown external lang item: `{}`",
|
|
||||||
lang_item
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,20 +68,14 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
|
||||||
for (name, &item) in WEAK_ITEMS_REFS.iter() {
|
for (name, &item) in WEAK_ITEMS_REFS.iter() {
|
||||||
if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() {
|
if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() {
|
||||||
if item == LangItem::PanicImpl {
|
if item == LangItem::PanicImpl {
|
||||||
tcx.sess.err("`#[panic_handler]` function required, but not found");
|
tcx.sess.emit_err(MissingPanicHandler);
|
||||||
} else if item == LangItem::Oom {
|
} else if item == LangItem::Oom {
|
||||||
if !tcx.features().default_alloc_error_handler {
|
if !tcx.features().default_alloc_error_handler {
|
||||||
tcx.sess.err("`#[alloc_error_handler]` function required, but not found");
|
tcx.sess.emit_err(AllocFuncRequired);
|
||||||
tcx.sess.note_without_error("use `#![feature(default_alloc_error_handler)]` for a default error handler");
|
tcx.sess.emit_note(MissingAllocErrorHandler);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tcx
|
tcx.sess.emit_err(MissingLangItem { name: *name });
|
||||||
.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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,8 +139,7 @@ impl<'a> Resolver<'a> {
|
||||||
&candidates,
|
&candidates,
|
||||||
if instead { Instead::Yes } else { Instead::No },
|
if instead { Instead::Yes } else { Instead::No },
|
||||||
found_use,
|
found_use,
|
||||||
IsPattern::No,
|
DiagnosticMode::Normal,
|
||||||
IsImport::No,
|
|
||||||
path,
|
path,
|
||||||
);
|
);
|
||||||
err.emit();
|
err.emit();
|
||||||
|
@ -699,8 +698,7 @@ impl<'a> Resolver<'a> {
|
||||||
&import_suggestions,
|
&import_suggestions,
|
||||||
Instead::No,
|
Instead::No,
|
||||||
FoundUse::Yes,
|
FoundUse::Yes,
|
||||||
IsPattern::Yes,
|
DiagnosticMode::Pattern,
|
||||||
IsImport::No,
|
|
||||||
vec![],
|
vec![],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1496,8 +1494,7 @@ impl<'a> Resolver<'a> {
|
||||||
&import_suggestions,
|
&import_suggestions,
|
||||||
Instead::No,
|
Instead::No,
|
||||||
FoundUse::Yes,
|
FoundUse::Yes,
|
||||||
IsPattern::No,
|
DiagnosticMode::Normal,
|
||||||
IsImport::No,
|
|
||||||
vec![],
|
vec![],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2458,18 +2455,13 @@ enum FoundUse {
|
||||||
No,
|
No,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether a binding is part of a pattern or an expression. Used for diagnostics.
|
/// Whether a binding is part of a pattern or a use statement. Used for diagnostics.
|
||||||
enum IsPattern {
|
enum DiagnosticMode {
|
||||||
|
Normal,
|
||||||
/// The binding is part of a pattern
|
/// The binding is part of a pattern
|
||||||
Yes,
|
Pattern,
|
||||||
/// The binding is part of an expression
|
/// The binding is part of a use statement
|
||||||
No,
|
Import,
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether a binding is part of a use statement. Used for diagnostics.
|
|
||||||
enum IsImport {
|
|
||||||
Yes,
|
|
||||||
No,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn import_candidates(
|
pub(crate) fn import_candidates(
|
||||||
|
@ -2488,8 +2480,7 @@ pub(crate) fn import_candidates(
|
||||||
candidates,
|
candidates,
|
||||||
Instead::Yes,
|
Instead::Yes,
|
||||||
FoundUse::Yes,
|
FoundUse::Yes,
|
||||||
IsPattern::No,
|
DiagnosticMode::Import,
|
||||||
IsImport::Yes,
|
|
||||||
vec![],
|
vec![],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2506,8 +2497,7 @@ fn show_candidates(
|
||||||
candidates: &[ImportSuggestion],
|
candidates: &[ImportSuggestion],
|
||||||
instead: Instead,
|
instead: Instead,
|
||||||
found_use: FoundUse,
|
found_use: FoundUse,
|
||||||
is_pattern: IsPattern,
|
mode: DiagnosticMode,
|
||||||
is_import: IsImport,
|
|
||||||
path: Vec<Segment>,
|
path: Vec<Segment>,
|
||||||
) {
|
) {
|
||||||
if candidates.is_empty() {
|
if candidates.is_empty() {
|
||||||
|
@ -2542,7 +2532,7 @@ fn show_candidates(
|
||||||
};
|
};
|
||||||
|
|
||||||
let instead = if let Instead::Yes = instead { " instead" } else { "" };
|
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!(
|
format!(
|
||||||
"if you meant to match on {}{}{}, use the full path in the pattern",
|
"if you meant to match on {}{}{}, use the full path in the pattern",
|
||||||
kind, instead, name
|
kind, instead, name
|
||||||
|
@ -2555,19 +2545,24 @@ fn show_candidates(
|
||||||
err.note(note);
|
err.note(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let (IsPattern::Yes, Some(span)) = (is_pattern, use_placement_span) {
|
if let Some(span) = use_placement_span {
|
||||||
err.span_suggestions(
|
let add_use = match mode {
|
||||||
span,
|
DiagnosticMode::Pattern => {
|
||||||
&msg,
|
err.span_suggestions(
|
||||||
accessible_path_strings.into_iter().map(|a| a.0),
|
span,
|
||||||
Applicability::MaybeIncorrect,
|
&msg,
|
||||||
);
|
accessible_path_strings.into_iter().map(|a| a.0),
|
||||||
} else if let Some(span) = use_placement_span {
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DiagnosticMode::Import => "",
|
||||||
|
DiagnosticMode::Normal => "use ",
|
||||||
|
};
|
||||||
for candidate in &mut accessible_path_strings {
|
for candidate in &mut accessible_path_strings {
|
||||||
// produce an additional newline to separate the new use statement
|
// produce an additional newline to separate the new use statement
|
||||||
// from the directly following item.
|
// from the directly following item.
|
||||||
let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" };
|
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);
|
candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2598,11 +2593,14 @@ fn show_candidates(
|
||||||
|
|
||||||
err.note(&msg);
|
err.note(&msg);
|
||||||
}
|
}
|
||||||
} else if matches!(is_import, IsImport::No) {
|
} else if !matches!(mode, DiagnosticMode::Import) {
|
||||||
assert!(!inaccessible_path_strings.is_empty());
|
assert!(!inaccessible_path_strings.is_empty());
|
||||||
|
|
||||||
let prefix =
|
let prefix = if let DiagnosticMode::Pattern = mode {
|
||||||
if let IsPattern::Yes = is_pattern { "you might have meant to match on " } else { "" };
|
"you might have meant to match on "
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
if inaccessible_path_strings.len() == 1 {
|
if inaccessible_path_strings.len() == 1 {
|
||||||
let (name, descr, def_id, note) = &inaccessible_path_strings[0];
|
let (name, descr, def_id, note) = &inaccessible_path_strings[0];
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
|
@ -2610,7 +2608,7 @@ fn show_candidates(
|
||||||
prefix,
|
prefix,
|
||||||
descr,
|
descr,
|
||||||
name,
|
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()) {
|
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::{emitter::SilentEmitter, ColorConfig, Handler};
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
|
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_feature::{find_feature_issue, GateIssue, UnstableFeatures};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
|
@ -354,6 +354,17 @@ impl ParseSess {
|
||||||
self.create_warning(warning).emit()
|
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>(
|
pub fn create_fatal<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
fatal: impl IntoDiagnostic<'a, !>,
|
fatal: impl IntoDiagnostic<'a, !>,
|
||||||
|
|
|
@ -28,7 +28,7 @@ use rustc_errors::json::JsonEmitter;
|
||||||
use rustc_errors::registry::Registry;
|
use rustc_errors::registry::Registry;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
|
error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
|
||||||
ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan,
|
ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
|
||||||
};
|
};
|
||||||
use rustc_macros::HashStable_Generic;
|
use rustc_macros::HashStable_Generic;
|
||||||
pub use rustc_span::def_id::StableCrateId;
|
pub use rustc_span::def_id::StableCrateId;
|
||||||
|
@ -489,6 +489,15 @@ impl Session {
|
||||||
pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
|
pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
|
||||||
self.parse_sess.emit_warning(warning)
|
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>(
|
pub fn create_fatal<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
fatal: impl IntoDiagnostic<'a, !>,
|
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 type parameter or projection whose Sizedness can't be known
|
||||||
/// - a tuple of type parameters or projections, if there are multiple
|
/// - a tuple of type parameters or projections, if there are multiple
|
||||||
/// such.
|
/// such.
|
||||||
/// - an Error, if a type contained itself. The representability
|
/// - an Error, if a type is infinitely sized
|
||||||
/// check should catch this case.
|
fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {
|
||||||
fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstraint<'_> {
|
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 def = tcx.adt_def(def_id);
|
||||||
|
|
||||||
let result = tcx.mk_type_list(
|
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);
|
debug!("adt_sized_constraint: {:?} => {:?}", def, result);
|
||||||
|
|
||||||
ty::AdtSizedConstraint(result)
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See `ParamEnv` struct definition for details.
|
/// See `ParamEnv` struct definition for details.
|
||||||
|
|
|
@ -2279,9 +2279,8 @@ macro_rules! int_impl {
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When the number is negative, zero, or if the base is not at least 2; it
|
/// This function will panic if `self` is less than or equal to zero,
|
||||||
/// panics in debug mode and the return value is 0 in release
|
/// or if `base` is less then 2.
|
||||||
/// mode.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -2294,27 +2293,16 @@ macro_rules! int_impl {
|
||||||
without modifying the original"]
|
without modifying the original"]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
#[rustc_inherit_overflow_checks]
|
|
||||||
#[allow(arithmetic_overflow)]
|
|
||||||
pub const fn ilog(self, base: Self) -> u32 {
|
pub const fn ilog(self, base: Self) -> u32 {
|
||||||
match self.checked_ilog(base) {
|
assert!(base >= 2, "base of integer logarithm must be at least 2");
|
||||||
Some(n) => n,
|
self.checked_ilog(base).expect("argument of integer logarithm must be positive")
|
||||||
None => {
|
|
||||||
// In debug builds, trigger a panic on None.
|
|
||||||
// This should optimize completely out in release builds.
|
|
||||||
let _ = Self::MAX + 1;
|
|
||||||
|
|
||||||
0
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the base 2 logarithm of the number, rounded down.
|
/// Returns the base 2 logarithm of the number, rounded down.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When the number is negative or zero it panics in debug mode and the return value
|
/// This function will panic if `self` is less than or equal to zero.
|
||||||
/// is 0 in release mode.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -2327,27 +2315,15 @@ macro_rules! int_impl {
|
||||||
without modifying the original"]
|
without modifying the original"]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
#[rustc_inherit_overflow_checks]
|
|
||||||
#[allow(arithmetic_overflow)]
|
|
||||||
pub const fn ilog2(self) -> u32 {
|
pub const fn ilog2(self) -> u32 {
|
||||||
match self.checked_ilog2() {
|
self.checked_ilog2().expect("argument of integer logarithm must be positive")
|
||||||
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
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the base 10 logarithm of the number, rounded down.
|
/// Returns the base 10 logarithm of the number, rounded down.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When the number is negative or zero it panics in debug mode and the return value
|
/// This function will panic if `self` is less than or equal to zero.
|
||||||
/// is 0 in release mode.
|
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
|
@ -2360,19 +2336,8 @@ macro_rules! int_impl {
|
||||||
without modifying the original"]
|
without modifying the original"]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
#[rustc_inherit_overflow_checks]
|
|
||||||
#[allow(arithmetic_overflow)]
|
|
||||||
pub const fn ilog10(self) -> u32 {
|
pub const fn ilog10(self) -> u32 {
|
||||||
match self.checked_ilog10() {
|
self.checked_ilog10().expect("argument of integer logarithm must be positive")
|
||||||
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
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the logarithm of the number with respect to an arbitrary base,
|
/// Returns the logarithm of the number with respect to an arbitrary base,
|
||||||
|
|
|
@ -692,8 +692,7 @@ macro_rules! uint_impl {
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When the number is zero, or if the base is not at least 2;
|
/// This function will panic if `self` is zero, or if `base` is less then 2.
|
||||||
/// it panics in debug mode and the return value is 0 in release mode.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -706,27 +705,16 @@ macro_rules! uint_impl {
|
||||||
without modifying the original"]
|
without modifying the original"]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
#[rustc_inherit_overflow_checks]
|
|
||||||
#[allow(arithmetic_overflow)]
|
|
||||||
pub const fn ilog(self, base: Self) -> u32 {
|
pub const fn ilog(self, base: Self) -> u32 {
|
||||||
match self.checked_ilog(base) {
|
assert!(base >= 2, "base of integer logarithm must be at least 2");
|
||||||
Some(n) => n,
|
self.checked_ilog(base).expect("argument of integer logarithm must be positive")
|
||||||
None => {
|
|
||||||
// In debug builds, trigger a panic on None.
|
|
||||||
// This should optimize completely out in release builds.
|
|
||||||
let _ = Self::MAX + 1;
|
|
||||||
|
|
||||||
0
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the base 2 logarithm of the number, rounded down.
|
/// Returns the base 2 logarithm of the number, rounded down.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When the number is zero it panics in debug mode and
|
/// This function will panic if `self` is zero.
|
||||||
/// the return value is 0 in release mode.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -739,27 +727,15 @@ macro_rules! uint_impl {
|
||||||
without modifying the original"]
|
without modifying the original"]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
#[rustc_inherit_overflow_checks]
|
|
||||||
#[allow(arithmetic_overflow)]
|
|
||||||
pub const fn ilog2(self) -> u32 {
|
pub const fn ilog2(self) -> u32 {
|
||||||
match self.checked_ilog2() {
|
self.checked_ilog2().expect("argument of integer logarithm must be positive")
|
||||||
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
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the base 10 logarithm of the number, rounded down.
|
/// Returns the base 10 logarithm of the number, rounded down.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When the number is zero it panics in debug mode and the
|
/// This function will panic if `self` is zero.
|
||||||
/// return value is 0 in release mode.
|
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
|
@ -772,19 +748,8 @@ macro_rules! uint_impl {
|
||||||
without modifying the original"]
|
without modifying the original"]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
#[rustc_inherit_overflow_checks]
|
|
||||||
#[allow(arithmetic_overflow)]
|
|
||||||
pub const fn ilog10(self) -> u32 {
|
pub const fn ilog10(self) -> u32 {
|
||||||
match self.checked_ilog10() {
|
self.checked_ilog10().expect("argument of integer logarithm must be positive")
|
||||||
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
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the logarithm of the number with respect to an arbitrary base,
|
/// Returns the logarithm of the number with respect to an arbitrary base,
|
||||||
|
|
|
@ -164,3 +164,33 @@ fn ilog10_u64() {
|
||||||
fn ilog10_u128() {
|
fn ilog10_u128() {
|
||||||
ilog10_loop! { u128, 38 }
|
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)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use crate::cmp;
|
|
||||||
use crate::fmt::{self, Debug, Formatter};
|
use crate::fmt::{self, Debug, Formatter};
|
||||||
use crate::io::{Result, Write};
|
use crate::io::{Result, Write};
|
||||||
use crate::mem::{self, MaybeUninit};
|
use crate::mem::{self, MaybeUninit};
|
||||||
|
use crate::{cmp, ptr};
|
||||||
|
|
||||||
/// A borrowed byte buffer which is incrementally filled and initialized.
|
/// A borrowed byte buffer which is incrementally filled and initialized.
|
||||||
///
|
///
|
||||||
|
@ -250,8 +250,11 @@ impl<'a> BorrowedCursor<'a> {
|
||||||
/// Initializes all bytes in the cursor.
|
/// Initializes all bytes in the cursor.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ensure_init(&mut self) -> &mut Self {
|
pub fn ensure_init(&mut self) -> &mut Self {
|
||||||
for byte in self.uninit_mut() {
|
let uninit = self.uninit_mut();
|
||||||
byte.write(0);
|
// 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();
|
self.buf.init = self.buf.capacity();
|
||||||
|
|
||||||
|
|
|
@ -704,6 +704,7 @@ impl<'a> Builder<'a> {
|
||||||
doc::Miri,
|
doc::Miri,
|
||||||
doc::EmbeddedBook,
|
doc::EmbeddedBook,
|
||||||
doc::EditionGuide,
|
doc::EditionGuide,
|
||||||
|
doc::StyleGuide,
|
||||||
),
|
),
|
||||||
Kind::Dist => describe!(
|
Kind::Dist => describe!(
|
||||||
dist::Docs,
|
dist::Docs,
|
||||||
|
|
|
@ -82,6 +82,7 @@ book!(
|
||||||
Reference, "src/doc/reference", "reference", submodule;
|
Reference, "src/doc/reference", "reference", submodule;
|
||||||
RustByExample, "src/doc/rust-by-example", "rust-by-example", submodule;
|
RustByExample, "src/doc/rust-by-example", "rust-by-example", submodule;
|
||||||
RustdocBook, "src/doc/rustdoc", "rustdoc";
|
RustdocBook, "src/doc/rustdoc", "rustdoc";
|
||||||
|
StyleGuide, "src/doc/style-guide", "style-guide";
|
||||||
);
|
);
|
||||||
|
|
||||||
fn open(builder: &Builder<'_>, path: impl AsRef<Path>) {
|
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
|
[The Reference](reference/index.html) is not a formal spec, but is more detailed and
|
||||||
comprehensive than the book.
|
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
|
||||||
|
|
||||||
[The Rustonomicon](nomicon/index.html) is your guidebook to the dark arts of unsafe
|
[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 h2 a,
|
||||||
.sidebar h3 a,
|
.sidebar h3 a,
|
||||||
.mobile-topbar h2 a,
|
.mobile-topbar h2 a,
|
||||||
h1.fqn a,
|
h1 a,
|
||||||
.search-results a,
|
.search-results a,
|
||||||
.module-item .stab,
|
.module-item .stab,
|
||||||
.import-item .stab,
|
.import-item .stab,
|
||||||
.result-name .primitive > i, .result-name .keyword > i,
|
.result-name .primitive > i, .result-name .keyword > i,
|
||||||
.content .method .where,
|
.method .where,
|
||||||
.content .fn .where,
|
.fn .where,
|
||||||
.content .where.fmt-newline {
|
.where.fmt-newline {
|
||||||
color: var(--main-color);
|
color: var(--main-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content span.enum, .content a.enum,
|
span.enum, a.enum,
|
||||||
.content span.struct, .content a.struct,
|
span.struct, a.struct,
|
||||||
.content span.union, .content a.union,
|
span.union, a.union,
|
||||||
.content span.primitive, .content a.primitive,
|
span.primitive, a.primitive,
|
||||||
.content span.type, .content a.type,
|
span.type, a.type,
|
||||||
.content span.foreigntype, .content a.foreigntype {
|
span.foreigntype, a.foreigntype {
|
||||||
color: var(--type-link-color);
|
color: var(--type-link-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content span.trait, .content a.trait,
|
span.trait, a.trait,
|
||||||
.content span.traitalias, .content a.traitalias {
|
span.traitalias, a.traitalias {
|
||||||
color: var(--trait-link-color);
|
color: var(--trait-link-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content span.associatedtype, .content a.associatedtype,
|
span.associatedtype, a.associatedtype,
|
||||||
.content span.constant, .content a.constant,
|
span.constant, a.constant,
|
||||||
.content span.static, .content a.static {
|
span.static, a.static {
|
||||||
color: var(--assoc-item-link-color);
|
color: var(--assoc-item-link-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content span.fn, .content a.fn,
|
span.fn, a.fn,
|
||||||
.content .fnname,
|
.fnname,
|
||||||
.content span.method, .content a.method,
|
span.method, a.method,
|
||||||
.content span.tymethod, .content a.tymethod {
|
span.tymethod, a.tymethod {
|
||||||
color: var(--function-link-color);
|
color: var(--function-link-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content span.attr, .content a.attr,
|
span.attr, a.attr,
|
||||||
.content span.derive, .content a.derive,
|
span.derive, a.derive,
|
||||||
.content span.macro, .content a.macro {
|
span.macro, a.macro {
|
||||||
color: var(--macro-link-color);
|
color: var(--macro-link-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content span.mod, .content a.mod, .block a.current.mod {
|
span.mod, a.mod {
|
||||||
color: var(--mod-link-color);
|
color: var(--mod-link-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content span.keyword, .content a.keyword {
|
span.keyword, a.keyword {
|
||||||
color: var(--keyword-link-color);
|
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 */
|
/* Shift "where ..." part of method or fn definition down a line */
|
||||||
.content .method .where,
|
.method .where,
|
||||||
.content .fn .where,
|
.fn .where,
|
||||||
.content .where.fmt-newline {
|
.where.fmt-newline {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ input:focus + .slider {
|
||||||
h1, h2, h3, h4 {
|
h1, h2, h3, h4 {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
h1.fqn a {
|
h1 a {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
h4 {
|
h4 {
|
||||||
|
|
|
@ -451,7 +451,6 @@ function loadCss(cssFileName) {
|
||||||
const name = item[0];
|
const name = item[0];
|
||||||
const desc = item[1]; // can be null
|
const desc = item[1]; // can be null
|
||||||
|
|
||||||
let klass = shortty;
|
|
||||||
let path;
|
let path;
|
||||||
if (shortty === "mod") {
|
if (shortty === "mod") {
|
||||||
path = name + "/index.html";
|
path = name + "/index.html";
|
||||||
|
@ -459,13 +458,12 @@ function loadCss(cssFileName) {
|
||||||
path = shortty + "." + name + ".html";
|
path = shortty + "." + name + ".html";
|
||||||
}
|
}
|
||||||
const current_page = document.location.href.split("/").pop();
|
const current_page = document.location.href.split("/").pop();
|
||||||
if (path === current_page) {
|
|
||||||
klass += " current";
|
|
||||||
}
|
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
link.href = path;
|
link.href = path;
|
||||||
link.title = desc;
|
link.title = desc;
|
||||||
link.className = klass;
|
if (path === current_page) {
|
||||||
|
link.className = "current";
|
||||||
|
}
|
||||||
link.textContent = name;
|
link.textContent = name;
|
||||||
const li = document.createElement("li");
|
const li = document.createElement("li");
|
||||||
li.appendChild(link);
|
li.appendChild(link);
|
||||||
|
|
|
@ -13,72 +13,72 @@ reload:
|
||||||
|
|
||||||
// Struct
|
// Struct
|
||||||
assert-css: (
|
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)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.struct:hover",
|
".sidebar .block.struct a:hover",
|
||||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||||
)
|
)
|
||||||
// Enum
|
// Enum
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.enum",
|
".sidebar .block.enum a",
|
||||||
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.enum:hover",
|
".sidebar .block.enum a:hover",
|
||||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||||
)
|
)
|
||||||
// Union
|
// Union
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.union",
|
".sidebar .block.union a",
|
||||||
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.union:hover",
|
".sidebar .block.union a:hover",
|
||||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||||
)
|
)
|
||||||
// Trait
|
// Trait
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.trait",
|
".sidebar .block.trait a",
|
||||||
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.trait:hover",
|
".sidebar .block.trait a:hover",
|
||||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||||
)
|
)
|
||||||
// Function
|
// Function
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.fn",
|
".sidebar .block.fn a",
|
||||||
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.fn:hover",
|
".sidebar .block.fn a:hover",
|
||||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||||
)
|
)
|
||||||
// Type definition
|
// Type definition
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.type",
|
".sidebar .block.type a",
|
||||||
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.type:hover",
|
".sidebar .block.type a:hover",
|
||||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||||
)
|
)
|
||||||
// Keyword
|
// Keyword
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.keyword",
|
".sidebar .block.keyword a",
|
||||||
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.keyword:hover",
|
".sidebar .block.keyword a:hover",
|
||||||
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -88,72 +88,72 @@ reload:
|
||||||
|
|
||||||
// Struct
|
// Struct
|
||||||
assert-css: (
|
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)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.struct:hover",
|
".sidebar .block.struct a:hover",
|
||||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||||
)
|
)
|
||||||
// Enum
|
// Enum
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.enum",
|
".sidebar .block.enum a",
|
||||||
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.enum:hover",
|
".sidebar .block.enum a:hover",
|
||||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||||
)
|
)
|
||||||
// Union
|
// Union
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.union",
|
".sidebar .block.union a",
|
||||||
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.union:hover",
|
".sidebar .block.union a:hover",
|
||||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||||
)
|
)
|
||||||
// Trait
|
// Trait
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.trait",
|
".sidebar .block.trait a",
|
||||||
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.trait:hover",
|
".sidebar .block.trait a:hover",
|
||||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||||
)
|
)
|
||||||
// Function
|
// Function
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.fn",
|
".sidebar .block.fn a",
|
||||||
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.fn:hover",
|
".sidebar .block.fn a:hover",
|
||||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||||
)
|
)
|
||||||
// Type definition
|
// Type definition
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.type",
|
".sidebar .block.type a",
|
||||||
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.type:hover",
|
".sidebar .block.type a:hover",
|
||||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||||
)
|
)
|
||||||
// Keyword
|
// Keyword
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.keyword",
|
".sidebar .block.keyword a",
|
||||||
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.keyword:hover",
|
".sidebar .block.keyword a:hover",
|
||||||
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -163,71 +163,71 @@ reload:
|
||||||
|
|
||||||
// Struct
|
// Struct
|
||||||
assert-css: (
|
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)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.struct:hover",
|
".sidebar .block.struct a:hover",
|
||||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
||||||
)
|
)
|
||||||
// Enum
|
// Enum
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.enum",
|
".sidebar .block.enum a",
|
||||||
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.enum:hover",
|
".sidebar .block.enum a:hover",
|
||||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
||||||
)
|
)
|
||||||
// Union
|
// Union
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.union",
|
".sidebar .block.union a",
|
||||||
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.union:hover",
|
".sidebar .block.union a:hover",
|
||||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
||||||
)
|
)
|
||||||
// Trait
|
// Trait
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.trait",
|
".sidebar .block.trait a",
|
||||||
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.trait:hover",
|
".sidebar .block.trait a:hover",
|
||||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
||||||
)
|
)
|
||||||
// Function
|
// Function
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.fn",
|
".sidebar .block.fn a",
|
||||||
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.fn:hover",
|
".sidebar .block.fn a:hover",
|
||||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
||||||
)
|
)
|
||||||
// Type definition
|
// Type definition
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.type",
|
".sidebar .block.type a",
|
||||||
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.type:hover",
|
".sidebar .block.type a:hover",
|
||||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
||||||
)
|
)
|
||||||
// Keyword
|
// Keyword
|
||||||
assert-css: (
|
assert-css: (
|
||||||
".sidebar a.keyword",
|
".sidebar .block.keyword a",
|
||||||
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
|
{"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: (
|
assert-css: (
|
||||||
".sidebar a.keyword:hover",
|
".sidebar .block.keyword a:hover",
|
||||||
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
|
{"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
|
// This test ensures that the reexport of a macro doesn't make the original macro
|
||||||
// displayed twice in the sidebar.
|
// displayed twice in the sidebar.
|
||||||
goto: "file://" + |DOC_PATH| + "/test_docs/macro.repro.html"
|
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)
|
assert-count: ("//*[@class='sidebar-elems']//*[@class='block macro']//a[text()='repro']", 1)
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
|
// check-pass
|
||||||
// normalize-stderr-test: "`.*`" -> "`DEF_ID`"
|
// normalize-stderr-test: "`.*`" -> "`DEF_ID`"
|
||||||
// normalize-stdout-test: "`.*`" -> "`DEF_ID`"
|
// normalize-stdout-test: "`.*`" -> "`DEF_ID`"
|
||||||
// edition:2018
|
// edition:2018
|
||||||
|
|
||||||
pub async fn f() -> impl std::fmt::Debug {
|
pub async fn f() -> impl std::fmt::Debug {
|
||||||
|
// rustdoc doesn't care that this is infinitely sized
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum E {
|
enum E {
|
||||||
//~^ ERROR recursive type `f::{closure#0}::E` has infinite size
|
|
||||||
This(E),
|
This(E),
|
||||||
Unit,
|
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 {
|
fn f() -> impl Sized {
|
||||||
|
// rustdoc doesn't care that this is infinitely sized
|
||||||
enum E {
|
enum E {
|
||||||
//~^ ERROR recursive type `f::E` has infinite size
|
|
||||||
V(E),
|
V(E),
|
||||||
}
|
}
|
||||||
unimplemented!()
|
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)]
|
#[rustc_layout(debug)]
|
||||||
type Edges<'a, E> = Cow<'a, [E]>;
|
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() {}
|
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
|
--> $DIR/issue-85103.rs:6:1
|
||||||
|
|
|
|
||||||
LL | type Edges<'a, E> = Cow<'a, [E]>;
|
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)]
|
#[derive(Hash)]
|
||||||
pub enum ElemDerived {
|
pub enum ElemDerived {
|
||||||
//~^ ERROR recursive type `ElemDerived` has infinite size
|
//~^ ERROR recursive type `ElemDerived` has infinite size
|
||||||
//~| ERROR cycle detected when computing drop-check constraints for `ElemDerived`
|
|
||||||
A(ElemDerived)
|
A(ElemDerived)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ error[E0072]: recursive type `ElemDerived` has infinite size
|
||||||
|
|
|
|
||||||
LL | pub enum ElemDerived {
|
LL | pub enum ElemDerived {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
...
|
LL |
|
||||||
LL | A(ElemDerived)
|
LL | A(ElemDerived)
|
||||||
| ----------- recursive without indirection
|
| ----------- 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>)
|
LL | A(Box<ElemDerived>)
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived`
|
error: aborting due to previous error
|
||||||
--> $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 2 previous errors
|
For more information about this error, try `rustc --explain E0072`.
|
||||||
|
|
||||||
Some errors have detailed explanations: E0072, E0391.
|
|
||||||
For more information about an error, try `rustc --explain E0072`.
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Test that disallow lifetime parameters that are unused.
|
// Test that disallow lifetime parameters that are unused.
|
||||||
|
|
||||||
enum Foo<'a> { //~ ERROR parameter `'a` is never used
|
enum Foo<'a> { //~ ERROR parameter `'a` is never used
|
||||||
|
//~^ ERROR recursive types `Foo` and `Bar` have infinite size
|
||||||
Foo1(Bar<'a>)
|
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
|
error[E0392]: parameter `'a` is never used
|
||||||
--> $DIR/variance-regions-unused-indirect.rs:3:10
|
--> $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`
|
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
|
||||||
|
|
||||||
error[E0392]: parameter `'a` is never used
|
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> {
|
LL | enum Bar<'a> {
|
||||||
| ^^ unused parameter
|
| ^^ unused parameter
|
||||||
|
|
|
|
||||||
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
|
= 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",
|
"src/tools/bump-stage0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[autolabel."T-style"]
|
||||||
|
trigger_files = [
|
||||||
|
"src/doc/style-guide",
|
||||||
|
]
|
||||||
|
|
||||||
[autolabel."A-translation"]
|
[autolabel."A-translation"]
|
||||||
trigger_files = [
|
trigger_files = [
|
||||||
"compiler/rustc_error_messages",
|
"compiler/rustc_error_messages",
|
||||||
|
|
Loading…
Add table
Reference in a new issue