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:
bors 2022-10-12 06:57:24 +00:00
commit e6ce5627a9
66 changed files with 4106 additions and 1067 deletions

View File

@ -584,6 +584,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
// modify their locations.
let all_facts = &mut None;
let mut constraints = Default::default();
let mut type_tests = Default::default();
let mut closure_bounds = Default::default();
let mut liveness_constraints =
LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body)));
@ -595,6 +596,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
&mut this.cx.borrowck_context.constraints.outlives_constraints,
&mut constraints,
);
mem::swap(&mut this.cx.borrowck_context.constraints.type_tests, &mut type_tests);
mem::swap(
&mut this.cx.borrowck_context.constraints.closure_bounds_mapping,
&mut closure_bounds,
@ -619,6 +621,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
swap_constraints(self);
let locations = location.to_locations();
// Use location of promoted const in collected constraints
for type_test in type_tests.iter() {
let mut type_test = type_test.clone();
type_test.locations = locations;
self.cx.borrowck_context.constraints.type_tests.push(type_test)
}
for constraint in constraints.outlives().iter() {
let mut constraint = constraint.clone();
constraint.locations = locations;

View File

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

View File

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

View File

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

View File

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

View File

@ -380,7 +380,6 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
let _ = tcx.representability(def_id);
if def.repr().simd() {
check_simd(tcx, span, def_id);
@ -394,7 +393,6 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
let _ = tcx.representability(def_id);
check_transparent(tcx, span, def);
check_union_fields(tcx, span, def_id);
check_packed(tcx, span, def);
@ -1489,7 +1487,6 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
let _ = tcx.representability(def_id);
check_transparent(tcx, sp, def);
}

View File

@ -1041,6 +1041,8 @@ fn check_type_defn<'tcx, F>(
) where
F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>,
{
let _ = tcx.representability(item.def_id.def_id);
enter_wf_checking_ctxt(tcx, item.span, item.def_id.def_id, |wfcx| {
let variants = lookup_fields(wfcx);
let packed = tcx.adt_def(item.def_id).repr().packed();

View File

@ -613,16 +613,8 @@ rustc_queries! {
separate_provide_extern
}
// The cycle error here should be reported as an error by `check_representable`.
// We consider the type as Sized in the meanwhile to avoid
// further errors (done in impl Value for AdtSizedConstraint).
// Use `cycle_delay_bug` to delay the cycle error here to be emitted later
// in case we accidentally otherwise don't emit an error.
query adt_sized_constraint(
key: DefId
) -> AdtSizedConstraint<'tcx> {
query adt_sized_constraint(key: DefId) -> &'tcx [Ty<'tcx>] {
desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) }
cycle_delay_bug
}
query adt_dtorck_constraint(

View File

@ -26,9 +26,6 @@ use super::{
Destructor, FieldDef, GenericPredicates, ReprOptions, Ty, TyCtxt, VariantDef, VariantDiscr,
};
#[derive(Copy, Clone, HashStable, Debug)]
pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]);
bitflags! {
#[derive(HashStable, TyEncodable, TyDecodable)]
pub struct AdtFlags: u32 {
@ -563,7 +560,7 @@ impl<'tcx> AdtDef<'tcx> {
/// Due to normalization being eager, this applies even if
/// the associated type is behind a pointer (e.g., issue #31299).
pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> {
ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0)
ty::EarlyBinder(tcx.adt_sized_constraint(self.did()))
}
}

View File

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

View File

@ -32,7 +32,7 @@ use crate::ty::layout::TyAndLayout;
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::util::AlwaysRequiresDrop;
use crate::ty::GeneratorDiagnosticData;
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use rustc_ast as ast;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_attr as attr;

View File

@ -3,7 +3,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_middle::ty::Representability;
use rustc_middle::ty::{self, AdtSizedConstraint, DefIdTree, Ty, TyCtxt};
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
use rustc_query_system::query::QueryInfo;
use rustc_query_system::Value;
use rustc_span::def_id::LocalDefId;
@ -31,18 +31,6 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
}
}
impl<'tcx> Value<TyCtxt<'tcx>> for AdtSizedConstraint<'_> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
// SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`.
// FIXME: Represent the above fact in the trait system somehow.
unsafe {
std::mem::transmute::<AdtSizedConstraint<'tcx>, AdtSizedConstraint<'_>>(
AdtSizedConstraint(tcx.intern_type_list(&[tcx.ty_error()])),
)
}
}
}
impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
let err = tcx.ty_error();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -139,8 +139,7 @@ impl<'a> Resolver<'a> {
&candidates,
if instead { Instead::Yes } else { Instead::No },
found_use,
IsPattern::No,
IsImport::No,
DiagnosticMode::Normal,
path,
);
err.emit();
@ -699,8 +698,7 @@ impl<'a> Resolver<'a> {
&import_suggestions,
Instead::No,
FoundUse::Yes,
IsPattern::Yes,
IsImport::No,
DiagnosticMode::Pattern,
vec![],
);
}
@ -1496,8 +1494,7 @@ impl<'a> Resolver<'a> {
&import_suggestions,
Instead::No,
FoundUse::Yes,
IsPattern::No,
IsImport::No,
DiagnosticMode::Normal,
vec![],
);
@ -2458,18 +2455,13 @@ enum FoundUse {
No,
}
/// Whether a binding is part of a pattern or an expression. Used for diagnostics.
enum IsPattern {
/// Whether a binding is part of a pattern or a use statement. Used for diagnostics.
enum DiagnosticMode {
Normal,
/// The binding is part of a pattern
Yes,
/// The binding is part of an expression
No,
}
/// Whether a binding is part of a use statement. Used for diagnostics.
enum IsImport {
Yes,
No,
Pattern,
/// The binding is part of a use statement
Import,
}
pub(crate) fn import_candidates(
@ -2488,8 +2480,7 @@ pub(crate) fn import_candidates(
candidates,
Instead::Yes,
FoundUse::Yes,
IsPattern::No,
IsImport::Yes,
DiagnosticMode::Import,
vec![],
);
}
@ -2506,8 +2497,7 @@ fn show_candidates(
candidates: &[ImportSuggestion],
instead: Instead,
found_use: FoundUse,
is_pattern: IsPattern,
is_import: IsImport,
mode: DiagnosticMode,
path: Vec<Segment>,
) {
if candidates.is_empty() {
@ -2542,7 +2532,7 @@ fn show_candidates(
};
let instead = if let Instead::Yes = instead { " instead" } else { "" };
let mut msg = if let IsPattern::Yes = is_pattern {
let mut msg = if let DiagnosticMode::Pattern = mode {
format!(
"if you meant to match on {}{}{}, use the full path in the pattern",
kind, instead, name
@ -2555,19 +2545,24 @@ fn show_candidates(
err.note(note);
}
if let (IsPattern::Yes, Some(span)) = (is_pattern, use_placement_span) {
err.span_suggestions(
span,
&msg,
accessible_path_strings.into_iter().map(|a| a.0),
Applicability::MaybeIncorrect,
);
} else if let Some(span) = use_placement_span {
if let Some(span) = use_placement_span {
let add_use = match mode {
DiagnosticMode::Pattern => {
err.span_suggestions(
span,
&msg,
accessible_path_strings.into_iter().map(|a| a.0),
Applicability::MaybeIncorrect,
);
return;
}
DiagnosticMode::Import => "",
DiagnosticMode::Normal => "use ",
};
for candidate in &mut accessible_path_strings {
// produce an additional newline to separate the new use statement
// from the directly following item.
let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" };
let add_use = if let IsImport::Yes = is_import { "" } else { "use " };
candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline);
}
@ -2598,11 +2593,14 @@ fn show_candidates(
err.note(&msg);
}
} else if matches!(is_import, IsImport::No) {
} else if !matches!(mode, DiagnosticMode::Import) {
assert!(!inaccessible_path_strings.is_empty());
let prefix =
if let IsPattern::Yes = is_pattern { "you might have meant to match on " } else { "" };
let prefix = if let DiagnosticMode::Pattern = mode {
"you might have meant to match on "
} else {
""
};
if inaccessible_path_strings.len() == 1 {
let (name, descr, def_id, note) = &inaccessible_path_strings[0];
let msg = format!(
@ -2610,7 +2608,7 @@ fn show_candidates(
prefix,
descr,
name,
if let IsPattern::Yes = is_pattern { ", which" } else { "" }
if let DiagnosticMode::Pattern = mode { ", which" } else { "" }
);
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {

View File

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

View File

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

View File

@ -85,9 +85,13 @@ fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
/// - a type parameter or projection whose Sizedness can't be known
/// - a tuple of type parameters or projections, if there are multiple
/// such.
/// - an Error, if a type contained itself. The representability
/// check should catch this case.
fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstraint<'_> {
/// - an Error, if a type is infinitely sized
fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {
if let Some(def_id) = def_id.as_local() {
if matches!(tcx.representability(def_id), ty::Representability::Infinite) {
return tcx.intern_type_list(&[tcx.ty_error()]);
}
}
let def = tcx.adt_def(def_id);
let result = tcx.mk_type_list(
@ -99,7 +103,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain
debug!("adt_sized_constraint: {:?} => {:?}", def, result);
ty::AdtSizedConstraint(result)
result
}
/// See `ParamEnv` struct definition for details.

View File

@ -2279,9 +2279,8 @@ macro_rules! int_impl {
///
/// # Panics
///
/// When the number is negative, zero, or if the base is not at least 2; it
/// panics in debug mode and the return value is 0 in release
/// mode.
/// This function will panic if `self` is less than or equal to zero,
/// or if `base` is less then 2.
///
/// # Examples
///
@ -2294,27 +2293,16 @@ macro_rules! int_impl {
without modifying the original"]
#[inline]
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
pub const fn ilog(self, base: Self) -> u32 {
match self.checked_ilog(base) {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
// This should optimize completely out in release builds.
let _ = Self::MAX + 1;
0
},
}
assert!(base >= 2, "base of integer logarithm must be at least 2");
self.checked_ilog(base).expect("argument of integer logarithm must be positive")
}
/// Returns the base 2 logarithm of the number, rounded down.
///
/// # Panics
///
/// When the number is negative or zero it panics in debug mode and the return value
/// is 0 in release mode.
/// This function will panic if `self` is less than or equal to zero.
///
/// # Examples
///
@ -2327,27 +2315,15 @@ macro_rules! int_impl {
without modifying the original"]
#[inline]
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
pub const fn ilog2(self) -> u32 {
match self.checked_ilog2() {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
// This should optimize completely out in release builds.
let _ = Self::MAX + 1;
0
},
}
self.checked_ilog2().expect("argument of integer logarithm must be positive")
}
/// Returns the base 10 logarithm of the number, rounded down.
///
/// # Panics
///
/// When the number is negative or zero it panics in debug mode and the return value
/// is 0 in release mode.
/// This function will panic if `self` is less than or equal to zero.
///
/// # Example
///
@ -2360,19 +2336,8 @@ macro_rules! int_impl {
without modifying the original"]
#[inline]
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
pub const fn ilog10(self) -> u32 {
match self.checked_ilog10() {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
// This should optimize completely out in release builds.
let _ = Self::MAX + 1;
0
},
}
self.checked_ilog10().expect("argument of integer logarithm must be positive")
}
/// Returns the logarithm of the number with respect to an arbitrary base,

View File

@ -692,8 +692,7 @@ macro_rules! uint_impl {
///
/// # Panics
///
/// When the number is zero, or if the base is not at least 2;
/// it panics in debug mode and the return value is 0 in release mode.
/// This function will panic if `self` is zero, or if `base` is less then 2.
///
/// # Examples
///
@ -706,27 +705,16 @@ macro_rules! uint_impl {
without modifying the original"]
#[inline]
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
pub const fn ilog(self, base: Self) -> u32 {
match self.checked_ilog(base) {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
// This should optimize completely out in release builds.
let _ = Self::MAX + 1;
0
},
}
assert!(base >= 2, "base of integer logarithm must be at least 2");
self.checked_ilog(base).expect("argument of integer logarithm must be positive")
}
/// Returns the base 2 logarithm of the number, rounded down.
///
/// # Panics
///
/// When the number is zero it panics in debug mode and
/// the return value is 0 in release mode.
/// This function will panic if `self` is zero.
///
/// # Examples
///
@ -739,27 +727,15 @@ macro_rules! uint_impl {
without modifying the original"]
#[inline]
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
pub const fn ilog2(self) -> u32 {
match self.checked_ilog2() {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
// This should optimize completely out in release builds.
let _ = Self::MAX + 1;
0
},
}
self.checked_ilog2().expect("argument of integer logarithm must be positive")
}
/// Returns the base 10 logarithm of the number, rounded down.
///
/// # Panics
///
/// When the number is zero it panics in debug mode and the
/// return value is 0 in release mode.
/// This function will panic if `self` is zero.
///
/// # Example
///
@ -772,19 +748,8 @@ macro_rules! uint_impl {
without modifying the original"]
#[inline]
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
pub const fn ilog10(self) -> u32 {
match self.checked_ilog10() {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
// This should optimize completely out in release builds.
let _ = Self::MAX + 1;
0
},
}
self.checked_ilog10().expect("argument of integer logarithm must be positive")
}
/// Returns the logarithm of the number with respect to an arbitrary base,

View File

@ -164,3 +164,33 @@ fn ilog10_u64() {
fn ilog10_u128() {
ilog10_loop! { u128, 38 }
}
#[test]
#[should_panic(expected = "argument of integer logarithm must be positive")]
fn ilog2_of_0_panic() {
let _ = 0u32.ilog2();
}
#[test]
#[should_panic(expected = "argument of integer logarithm must be positive")]
fn ilog10_of_0_panic() {
let _ = 0u32.ilog10();
}
#[test]
#[should_panic(expected = "argument of integer logarithm must be positive")]
fn ilog3_of_0_panic() {
let _ = 0u32.ilog(3);
}
#[test]
#[should_panic(expected = "base of integer logarithm must be at least 2")]
fn ilog0_of_1_panic() {
let _ = 1u32.ilog(0);
}
#[test]
#[should_panic(expected = "base of integer logarithm must be at least 2")]
fn ilog1_of_1_panic() {
let _ = 1u32.ilog(1);
}

View File

@ -3,10 +3,10 @@
#[cfg(test)]
mod tests;
use crate::cmp;
use crate::fmt::{self, Debug, Formatter};
use crate::io::{Result, Write};
use crate::mem::{self, MaybeUninit};
use crate::{cmp, ptr};
/// A borrowed byte buffer which is incrementally filled and initialized.
///
@ -250,8 +250,11 @@ impl<'a> BorrowedCursor<'a> {
/// Initializes all bytes in the cursor.
#[inline]
pub fn ensure_init(&mut self) -> &mut Self {
for byte in self.uninit_mut() {
byte.write(0);
let uninit = self.uninit_mut();
// SAFETY: 0 is a valid value for MaybeUninit<u8> and the length matches the allocation
// since it is comes from a slice reference.
unsafe {
ptr::write_bytes(uninit.as_mut_ptr(), 0, uninit.len());
}
self.buf.init = self.buf.capacity();

View File

@ -704,6 +704,7 @@ impl<'a> Builder<'a> {
doc::Miri,
doc::EmbeddedBook,
doc::EditionGuide,
doc::StyleGuide,
),
Kind::Dist => describe!(
dist::Docs,

View File

@ -82,6 +82,7 @@ book!(
Reference, "src/doc/reference", "reference", submodule;
RustByExample, "src/doc/rust-by-example", "rust-by-example", submodule;
RustdocBook, "src/doc/rustdoc", "rustdoc";
StyleGuide, "src/doc/style-guide", "style-guide";
);
fn open(builder: &Builder<'_>, path: impl AsRef<Path>) {

View File

@ -113,6 +113,12 @@ resources useful.
[The Reference](reference/index.html) is not a formal spec, but is more detailed and
comprehensive than the book.
## The Style Guide
[The Rust Style Guide](style-guide/index.html) describes the standard formatting of Rust
code. Most developers use rustfmt to format their code, and rustfmt's default
formatting matches this style guide.
## The Rustonomicon
[The Rustonomicon](nomicon/index.html) is your guidebook to the dark arts of unsafe

View 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/"

View 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)

View 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)

View 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.

View 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.

View 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.

View 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.

View 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.

View 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();
}
```

View 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
>
```

View File

@ -218,55 +218,55 @@ pre.rust a,
.sidebar h2 a,
.sidebar h3 a,
.mobile-topbar h2 a,
h1.fqn a,
h1 a,
.search-results a,
.module-item .stab,
.import-item .stab,
.result-name .primitive > i, .result-name .keyword > i,
.content .method .where,
.content .fn .where,
.content .where.fmt-newline {
.method .where,
.fn .where,
.where.fmt-newline {
color: var(--main-color);
}
.content span.enum, .content a.enum,
.content span.struct, .content a.struct,
.content span.union, .content a.union,
.content span.primitive, .content a.primitive,
.content span.type, .content a.type,
.content span.foreigntype, .content a.foreigntype {
span.enum, a.enum,
span.struct, a.struct,
span.union, a.union,
span.primitive, a.primitive,
span.type, a.type,
span.foreigntype, a.foreigntype {
color: var(--type-link-color);
}
.content span.trait, .content a.trait,
.content span.traitalias, .content a.traitalias {
span.trait, a.trait,
span.traitalias, a.traitalias {
color: var(--trait-link-color);
}
.content span.associatedtype, .content a.associatedtype,
.content span.constant, .content a.constant,
.content span.static, .content a.static {
span.associatedtype, a.associatedtype,
span.constant, a.constant,
span.static, a.static {
color: var(--assoc-item-link-color);
}
.content span.fn, .content a.fn,
.content .fnname,
.content span.method, .content a.method,
.content span.tymethod, .content a.tymethod {
span.fn, a.fn,
.fnname,
span.method, a.method,
span.tymethod, a.tymethod {
color: var(--function-link-color);
}
.content span.attr, .content a.attr,
.content span.derive, .content a.derive,
.content span.macro, .content a.macro {
span.attr, a.attr,
span.derive, a.derive,
span.macro, a.macro {
color: var(--macro-link-color);
}
.content span.mod, .content a.mod, .block a.current.mod {
span.mod, a.mod {
color: var(--mod-link-color);
}
.content span.keyword, .content a.keyword {
span.keyword, a.keyword {
color: var(--keyword-link-color);
}
@ -685,9 +685,9 @@ pre, .rustdoc.source .example-wrap {
}
/* Shift "where ..." part of method or fn definition down a line */
.content .method .where,
.content .fn .where,
.content .where.fmt-newline {
.method .where,
.fn .where,
.where.fmt-newline {
display: block;
font-size: 0.875rem;
}

View File

@ -56,7 +56,7 @@ input:focus + .slider {
h1, h2, h3, h4 {
color: white;
}
h1.fqn a {
h1 a {
color: #fff;
}
h4 {

View File

@ -451,7 +451,6 @@ function loadCss(cssFileName) {
const name = item[0];
const desc = item[1]; // can be null
let klass = shortty;
let path;
if (shortty === "mod") {
path = name + "/index.html";
@ -459,13 +458,12 @@ function loadCss(cssFileName) {
path = shortty + "." + name + ".html";
}
const current_page = document.location.href.split("/").pop();
if (path === current_page) {
klass += " current";
}
const link = document.createElement("a");
link.href = path;
link.title = desc;
link.className = klass;
if (path === current_page) {
link.className = "current";
}
link.textContent = name;
const li = document.createElement("li");
li.appendChild(link);

View File

@ -13,72 +13,72 @@ reload:
// Struct
assert-css: (
".sidebar a.struct:not(.current)",
".sidebar .block.struct a:not(.current)",
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.struct:not(.current)"
move-cursor-to: ".sidebar .block.struct a:not(.current)"
assert-css: (
".sidebar a.struct:hover",
".sidebar .block.struct a:hover",
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
)
// Enum
assert-css: (
".sidebar a.enum",
".sidebar .block.enum a",
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.enum"
move-cursor-to: ".sidebar .block.enum a"
assert-css: (
".sidebar a.enum:hover",
".sidebar .block.enum a:hover",
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
)
// Union
assert-css: (
".sidebar a.union",
".sidebar .block.union a",
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.union"
move-cursor-to: ".sidebar .block.union a"
assert-css: (
".sidebar a.union:hover",
".sidebar .block.union a:hover",
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
)
// Trait
assert-css: (
".sidebar a.trait",
".sidebar .block.trait a",
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.trait"
move-cursor-to: ".sidebar .block.trait a"
assert-css: (
".sidebar a.trait:hover",
".sidebar .block.trait a:hover",
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
)
// Function
assert-css: (
".sidebar a.fn",
".sidebar .block.fn a",
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.fn"
move-cursor-to: ".sidebar .block.fn a"
assert-css: (
".sidebar a.fn:hover",
".sidebar .block.fn a:hover",
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
)
// Type definition
assert-css: (
".sidebar a.type",
".sidebar .block.type a",
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.type"
move-cursor-to: ".sidebar .block.type a"
assert-css: (
".sidebar a.type:hover",
".sidebar .block.type a:hover",
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
)
// Keyword
assert-css: (
".sidebar a.keyword",
".sidebar .block.keyword a",
{"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.keyword"
move-cursor-to: ".sidebar .block.keyword a"
assert-css: (
".sidebar a.keyword:hover",
".sidebar .block.keyword a:hover",
{"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
)
@ -88,72 +88,72 @@ reload:
// Struct
assert-css: (
".sidebar a.struct:not(.current)",
".sidebar .block.struct a:not(.current)",
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.struct:not(.current)"
move-cursor-to: ".sidebar .block.struct a:not(.current)"
assert-css: (
".sidebar a.struct:hover",
".sidebar .block.struct a:hover",
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
)
// Enum
assert-css: (
".sidebar a.enum",
".sidebar .block.enum a",
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.enum"
move-cursor-to: ".sidebar .block.enum a"
assert-css: (
".sidebar a.enum:hover",
".sidebar .block.enum a:hover",
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
)
// Union
assert-css: (
".sidebar a.union",
".sidebar .block.union a",
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.union"
move-cursor-to: ".sidebar .block.union a"
assert-css: (
".sidebar a.union:hover",
".sidebar .block.union a:hover",
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
)
// Trait
assert-css: (
".sidebar a.trait",
".sidebar .block.trait a",
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.trait"
move-cursor-to: ".sidebar .block.trait a"
assert-css: (
".sidebar a.trait:hover",
".sidebar .block.trait a:hover",
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
)
// Function
assert-css: (
".sidebar a.fn",
".sidebar .block.fn a",
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.fn"
move-cursor-to: ".sidebar .block.fn a"
assert-css: (
".sidebar a.fn:hover",
".sidebar .block.fn a:hover",
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
)
// Type definition
assert-css: (
".sidebar a.type",
".sidebar .block.type a",
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.type"
move-cursor-to: ".sidebar .block.type a"
assert-css: (
".sidebar a.type:hover",
".sidebar .block.type a:hover",
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
)
// Keyword
assert-css: (
".sidebar a.keyword",
".sidebar .block.keyword a",
{"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.keyword"
move-cursor-to: ".sidebar .block.keyword a"
assert-css: (
".sidebar a.keyword:hover",
".sidebar .block.keyword a:hover",
{"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
)
@ -163,71 +163,71 @@ reload:
// Struct
assert-css: (
".sidebar a.struct:not(.current)",
".sidebar .block.struct a:not(.current)",
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.struct:not(.current)"
move-cursor-to: ".sidebar .block.struct a:not(.current)"
assert-css: (
".sidebar a.struct:hover",
".sidebar .block.struct a:hover",
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
)
// Enum
assert-css: (
".sidebar a.enum",
".sidebar .block.enum a",
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.enum"
move-cursor-to: ".sidebar .block.enum a"
assert-css: (
".sidebar a.enum:hover",
".sidebar .block.enum a:hover",
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
)
// Union
assert-css: (
".sidebar a.union",
".sidebar .block.union a",
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.union"
move-cursor-to: ".sidebar .block.union a"
assert-css: (
".sidebar a.union:hover",
".sidebar .block.union a:hover",
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
)
// Trait
assert-css: (
".sidebar a.trait",
".sidebar .block.trait a",
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.trait"
move-cursor-to: ".sidebar .block.trait a"
assert-css: (
".sidebar a.trait:hover",
".sidebar .block.trait a:hover",
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
)
// Function
assert-css: (
".sidebar a.fn",
".sidebar .block.fn a",
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.fn"
move-cursor-to: ".sidebar .block.fn a"
assert-css: (
".sidebar a.fn:hover",
".sidebar .block.fn a:hover",
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
)
// Type definition
assert-css: (
".sidebar a.type",
".sidebar .block.type a",
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.type"
move-cursor-to: ".sidebar .block.type a"
assert-css: (
".sidebar a.type:hover",
".sidebar .block.type a:hover",
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
)
// Keyword
assert-css: (
".sidebar a.keyword",
".sidebar .block.keyword a",
{"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
)
move-cursor-to: ".sidebar a.keyword"
move-cursor-to: ".sidebar .block.keyword a"
assert-css: (
".sidebar a.keyword:hover",
".sidebar .block.keyword a:hover",
{"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
)

View File

@ -1,5 +1,5 @@
// This test ensures that the reexport of a macro doesn't make the original macro
// displayed twice in the sidebar.
goto: "file://" + |DOC_PATH| + "/test_docs/macro.repro.html"
wait-for: ".sidebar-elems .macro .macro"
wait-for: ".sidebar-elems .block.macro a"
assert-count: ("//*[@class='sidebar-elems']//*[@class='block macro']//a[text()='repro']", 1)

View File

@ -1,11 +1,12 @@
// check-pass
// normalize-stderr-test: "`.*`" -> "`DEF_ID`"
// normalize-stdout-test: "`.*`" -> "`DEF_ID`"
// edition:2018
pub async fn f() -> impl std::fmt::Debug {
// rustdoc doesn't care that this is infinitely sized
#[derive(Debug)]
enum E {
//~^ ERROR recursive type `f::{closure#0}::E` has infinite size
This(E),
Unit,
}

View File

@ -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`.

View File

@ -1,6 +1,8 @@
// check-pass
fn f() -> impl Sized {
// rustdoc doesn't care that this is infinitely sized
enum E {
//~^ ERROR recursive type `f::E` has infinite size
V(E),
}
unimplemented!()

View File

@ -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`.

View File

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

View File

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

View 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() {}

View 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`.

View File

@ -3,7 +3,6 @@ use std::collections::BTreeSet;
#[derive(Hash)]
pub enum ElemDerived {
//~^ ERROR recursive type `ElemDerived` has infinite size
//~| ERROR cycle detected when computing drop-check constraints for `ElemDerived`
A(ElemDerived)
}

View File

@ -3,7 +3,7 @@ error[E0072]: recursive type `ElemDerived` has infinite size
|
LL | pub enum ElemDerived {
| ^^^^^^^^^^^^^^^^^^^^
...
LL |
LL | A(ElemDerived)
| ----------- recursive without indirection
|
@ -12,20 +12,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
LL | A(Box<ElemDerived>)
| ++++ +
error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived`
--> $DIR/issue-72554.rs:4:1
|
LL | pub enum ElemDerived {
| ^^^^^^^^^^^^^^^^^^^^
|
= note: ...which immediately requires computing drop-check constraints for `ElemDerived` again
note: cycle used when computing drop-check constraints for `Elem`
--> $DIR/issue-72554.rs:11:1
|
LL | pub enum Elem {
| ^^^^^^^^^^^^^
error: aborting due to previous error
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0072, E0391.
For more information about an error, try `rustc --explain E0072`.
For more information about this error, try `rustc --explain E0072`.

View File

@ -1,6 +1,7 @@
// Test that disallow lifetime parameters that are unused.
enum Foo<'a> { //~ ERROR parameter `'a` is never used
//~^ ERROR recursive types `Foo` and `Bar` have infinite size
Foo1(Bar<'a>)
}

View File

@ -1,3 +1,26 @@
error[E0072]: recursive types `Foo` and `Bar` have infinite size
--> $DIR/variance-regions-unused-indirect.rs:3:1
|
LL | enum Foo<'a> {
| ^^^^^^^^^^^^
LL |
LL | Foo1(Bar<'a>)
| ------- recursive without indirection
...
LL | enum Bar<'a> {
| ^^^^^^^^^^^^
LL | Bar1(Foo<'a>)
| ------- recursive without indirection
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
LL ~ Foo1(Box<Bar<'a>>)
LL | }
LL |
LL | enum Bar<'a> {
LL ~ Bar1(Box<Foo<'a>>)
|
error[E0392]: parameter `'a` is never used
--> $DIR/variance-regions-unused-indirect.rs:3:10
|
@ -7,13 +30,14 @@ LL | enum Foo<'a> {
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
error[E0392]: parameter `'a` is never used
--> $DIR/variance-regions-unused-indirect.rs:7:10
--> $DIR/variance-regions-unused-indirect.rs:8:10
|
LL | enum Bar<'a> {
| ^^ unused parameter
|
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
error: aborting due to 2 previous errors
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0392`.
Some errors have detailed explanations: E0072, E0392.
For more information about an error, try `rustc --explain E0072`.

View File

@ -189,6 +189,11 @@ trigger_files = [
"src/tools/bump-stage0",
]
[autolabel."T-style"]
trigger_files = [
"src/doc/style-guide",
]
[autolabel."A-translation"]
trigger_files = [
"compiler/rustc_error_messages",