summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_parse
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_parse
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_parse')
-rw-r--r--compiler/rustc_parse/Cargo.toml1
-rw-r--r--compiler/rustc_parse/messages.ftl1097
-rw-r--r--compiler/rustc_parse/src/errors.rs399
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs77
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs3
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs33
-rw-r--r--compiler/rustc_parse/src/lexer/unicode_chars.rs2
-rw-r--r--compiler/rustc_parse/src/lib.rs25
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs6
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs2
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs178
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs197
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs46
-rw-r--r--compiler/rustc_parse/src/parser/item.rs222
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs39
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs10
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs37
-rw-r--r--compiler/rustc_parse/src/parser/path.rs113
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs137
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs204
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs33
21 files changed, 1695 insertions, 1166 deletions
diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml
index 3eb158c81..1bd9f6629 100644
--- a/compiler/rustc_parse/Cargo.toml
+++ b/compiler/rustc_parse/Cargo.toml
@@ -12,6 +12,7 @@ rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_macros = { path = "../rustc_macros" }
rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index f11d0ed0f..926339450 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -1,230 +1,298 @@
-parse_struct_literal_body_without_path =
- struct literal body without path
- .suggestion = you might have forgotten to add the struct literal inside the block
+parse_add_paren = try adding parentheses
-parse_struct_literal_needing_parens =
- invalid struct literal
- .suggestion = you might need to surround the struct literal in parentheses
+parse_ambiguous_missing_keyword_for_item_definition = missing `fn` or `struct` for function or struct definition
+ .suggestion = if you meant to call a macro, try
+ .help = if you meant to call a macro, remove the `pub` and add a trailing `!` after the identifier
-parse_maybe_report_ambiguous_plus =
- ambiguous `+` in a type
- .suggestion = use parentheses to disambiguate
+parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation
+ .suggestion = add parentheses to clarify the precedence
-parse_maybe_recover_from_bad_type_plus =
- expected a path on the left-hand side of `+`, not `{$ty}`
+parse_array_brackets_instead_of_braces = this is a block expression, not an array
+ .suggestion = to make an array, use square brackets instead of curly braces
-parse_add_paren = try adding parentheses
+parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed
-parse_forgot_paren = perhaps you forgot parentheses?
+parse_assoc_lifetime = associated lifetimes are not supported
+ .label = the lifetime is given here
+ .help = if you meant to specify a trait object, write `dyn Trait + 'lifetime`
-parse_expect_path = expected a path
+parse_associated_static_item_not_allowed = associated `static` items are not allowed
-parse_maybe_recover_from_bad_qpath_stage_2 =
- missing angle brackets in associated item path
- .suggestion = try: `{$ty}`
+parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later
-parse_incorrect_semicolon =
- expected item, found `;`
- .suggestion = remove this semicolon
- .help = {$name} declarations are not followed by a semicolon
+parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
+ .label = to use `async fn`, switch to Rust 2018 or later
-parse_incorrect_use_of_await =
- incorrect use of `await`
- .parentheses_suggestion = `await` is not a method call, remove the parentheses
- .postfix_suggestion = `await` is a postfix operation
+parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
+ .suggestion = try switching the order
-parse_in_in_typo =
- expected iterable, found keyword `in`
- .suggestion = remove the duplicated `in`
+parse_attr_after_generic = trailing attribute after generic parameter
+ .label = attributes must go before parameters
-parse_invalid_variable_declaration =
- invalid variable declaration
+parse_attr_without_generics = attribute without generic parameters
+ .label = attributes are only permitted when preceding parameters
-parse_switch_mut_let_order =
- switch the order of `mut` and `let`
-parse_missing_let_before_mut = missing keyword
-parse_use_let_not_auto = write `let` instead of `auto` to introduce a new variable
-parse_use_let_not_var = write `let` instead of `var` to introduce a new variable
+parse_attribute_on_param_type = attributes cannot be applied to a function parameter's type
+ .label = attributes are not allowed here
-parse_invalid_comparison_operator = invalid comparison operator `{$invalid}`
- .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}`
- .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering`
+parse_bad_assoc_type_bounds = bounds on associated types do not belong here
+ .label = belongs in `where` clause
-parse_invalid_logical_operator = `{$incorrect}` is not a logical operator
- .note = unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
- .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction
- .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction
+parse_bad_item_kind = {$descr} is not supported in {$ctx}
+ .help = consider moving the {$descr} out to a nearby module scope
-parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
- .suggestion = use `!` to perform bitwise not
+parse_bad_return_type_notation_dotdot =
+ return type notation uses `()` instead of `(..)` for elided arguments
+ .suggestion = remove the `..`
-parse_unexpected_if_with_if = unexpected `if` in the condition expression
- .suggestion = remove the `if`
+parse_bad_return_type_notation_output =
+ return type not allowed with return type notation
+ .suggestion = remove the return type
-parse_unexpected_token_after_not = unexpected {$negated_desc} after identifier
-parse_unexpected_token_after_not_bitwise = use `!` to perform bitwise not
-parse_unexpected_token_after_not_logical = use `!` to perform logical negation
-parse_unexpected_token_after_not_default = use `!` to perform logical negation or bitwise not
+parse_bare_cr = {$double_quotes ->
+ [true] bare CR not allowed in string, use `\r` instead
+ *[false] character constant must be escaped: `\r`
+ }
+ .escape = escape the character
-parse_malformed_loop_label = malformed loop label
- .suggestion = use the correct loop label format
+parse_bare_cr_in_raw_string = bare CR not allowed in raw string
-parse_lifetime_in_borrow_expression = borrow expressions cannot be annotated with lifetimes
- .suggestion = remove the lifetime annotation
- .label = annotated with lifetime here
+parse_binary_float_literal_not_supported = binary float literal is not supported
+parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases
-parse_field_expression_with_generic = field expressions cannot have generic arguments
+parse_box_not_pat = expected pattern, found {$descr}
+ .note = `box` is a reserved keyword
+ .suggestion = escape `box` to use it as an identifier
-parse_macro_invocation_with_qualified_path = macros cannot use qualified paths
+parse_box_syntax_removed = `box_syntax` has been removed
+ .suggestion = use `Box::new()` instead
-parse_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label
- .suggestion_remove_label = consider removing the label
- .suggestion_enclose_in_block = consider enclosing expression in a block
+parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier
-parse_require_colon_after_labeled_expression = labeled expression must be followed by `:`
- .note = labels are used before loops and blocks, allowing e.g., `break 'label` to them
- .label = the label
- .suggestion = add `:` after the label
+parse_catch_after_try = keyword `catch` cannot follow a `try` block
+ .help = try using `match` on the result of the `try` block instead
+
+parse_cfg_attr_bad_delim = wrong `cfg_attr` delimiters
+parse_colon_as_semi = statements are terminated with a semicolon
+ .suggestion = use a semicolon instead
+
+parse_comma_after_base_struct = cannot use a comma after the base struct
+ .note = the base struct must always be the last field
+ .suggestion = remove this comma
+
+parse_comparison_interpreted_as_generic =
+ `<` is interpreted as a start of generic arguments for `{$type}`, not a comparison
+ .label_args = interpreted as generic arguments
+ .label_comparison = not interpreted as comparison
+ .suggestion = try comparing the cast value
+
+parse_comparison_operators_cannot_be_chained = comparison operators cannot be chained
+ .sugg_parentheses_for_function_args = or use `(...)` if you meant to specify fn arguments
+ .sugg_split_comparison = split the comparison into two
+ .sugg_parenthesize = parenthesize the comparison
+parse_compound_assignment_expression_in_let = can't reassign to an uninitialized variable
+ .suggestion = initialize the variable
+ .help = if you meant to overwrite, remove the `let` binding
+
+parse_const_bounds_missing_tilde = const bounds must start with `~`
+ .suggestion = add `~`
+
+parse_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments
+ .suggestion = enclose the `const` expression in braces
+
+parse_const_global_cannot_be_mutable = const globals cannot be mutable
+ .label = cannot be mutable
+ .suggestion = you might want to declare a static instead
+
+parse_const_let_mutually_exclusive = `const` and `let` are mutually exclusive
+ .suggestion = remove `let`
+
+parse_cr_doc_comment = bare CR not allowed in {$block ->
+ [true] block doc-comment
+ *[false] doc-comment
+}
+
+parse_default_not_followed_by_item = `default` is not followed by an item
+ .label = the `default` qualifier
+ .note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
parse_do_catch_syntax_removed = found removed `do catch` syntax
.note = following RFC #2388, the new non-placeholder syntax is `try`
.suggestion = replace with the new syntax
-parse_float_literal_requires_integer_part = float literals must have an integer part
- .suggestion = must have an integer part
+parse_doc_comment_does_not_document_anything = found a documentation comment that doesn't document anything
+ .help = doc comments must come before what they document, if a comment was intended use `//`
+ .suggestion = missing comma here
-parse_invalid_int_literal_width = invalid width `{$width}` for integer literal
- .help = valid widths are 8, 16, 32, 64 and 128
+parse_doc_comment_on_param_type = documentation comments cannot be applied to a function parameter's type
+ .label = doc comments are not allowed here
-parse_invalid_num_literal_base_prefix = invalid base prefix for number literal
- .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase
- .suggestion = try making the prefix lowercase
+parse_dot_dot_dot_for_remaining_fields = expected field pattern, found `{$token_str}`
+ .suggestion = to omit remaining fields, use `..`
-parse_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal
- .label = invalid suffix `{$suffix}`
- .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+parse_dot_dot_dot_range_to_pattern_not_allowed = range-to patterns with `...` are not allowed
+ .suggestion = use `..=` instead
-parse_invalid_float_literal_width = invalid width `{$width}` for float literal
- .help = valid widths are 32 and 64
+parse_dotdotdot = unexpected token: `...`
+ .suggest_exclusive_range = use `..` for an exclusive range
+ .suggest_inclusive_range = or `..=` for an inclusive range
-parse_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
- .label = invalid suffix `{$suffix}`
- .help = valid suffixes are `f32` and `f64`
+parse_dotdotdot_rest_pattern = unexpected `...`
+ .label = not a valid pattern
+ .suggestion = for a rest pattern, use `..` instead of `...`
-parse_int_literal_too_large = integer literal is too large
+parse_double_colon_in_bound = expected `:` followed by trait or lifetime
+ .suggestion = use single colon
-parse_missing_semicolon_before_array = expected `;`, found `[`
- .suggestion = consider adding `;` here
+parse_dyn_after_mut = `mut` must precede `dyn`
+ .suggestion = place `mut` before `dyn`
-parse_invalid_block_macro_segment = cannot use a `block` macro fragment here
- .label = the `block` fragment is within this context
+parse_empty_exponent_float = expected at least one digit in exponent
-parse_expect_dotdot_not_dotdotdot = expected `..`, found `...`
- .suggestion = use `..` to fill in the rest of the fields
+parse_empty_unicode_escape = empty unicode escape
+ .label = this escape must have at least 1 hex digit
-parse_if_expression_missing_then_block = this `if` expression is missing a block after the condition
- .add_then_block = add a block here
- .condition_possibly_unfinished = this binary operation is possibly unfinished
+parse_enum_pattern_instead_of_identifier = expected identifier, found enum pattern
-parse_if_expression_missing_condition = missing condition for `if` expression
- .condition_label = expected condition here
- .block_label = if this block is the condition of the `if` expression, then it must be followed by another block
+parse_enum_struct_mutually_exclusive = `enum` and `struct` are mutually exclusive
+ .suggestion = replace `enum struct` with
-parse_expected_expression_found_let = expected expression, found `let` statement
+parse_eq_field_init = expected `:`, found `=`
+ .suggestion = replace equals symbol with a colon
+
+parse_equals_struct_default = default values on `struct` fields aren't supported
+ .suggestion = remove this unsupported default value
+
+parse_escape_only_char = {$byte ->
+ [true] byte
+ *[false] character
+ } constant must be escaped: `{$escaped_msg}`
+ .escape = escape the character
+
+parse_expect_dotdot_not_dotdotdot = expected `..`, found `...`
+ .suggestion = use `..` to fill in the rest of the fields
parse_expect_eq_instead_of_eqeq = expected `=`, found `==`
.suggestion = consider using `=` here
+parse_expect_label_found_ident = expected a label, found an identifier
+ .suggestion = labels start with a tick
+
+parse_expect_path = expected a path
+
+parse_expected_binding_left_of_at = left-hand side of `@` must be a binding
+ .label_lhs = interpreted as a pattern, not a binding
+ .label_rhs = also a pattern
+ .note = bindings are `x`, `mut x`, `ref x`, and `ref mut x`
+
+parse_expected_builtin_ident = expected identifier after `builtin #`
+
+parse_expected_comma_after_pattern_field = expected `,`
+
parse_expected_else_block = expected `{"{"}`, found {$first_tok}
.label = expected an `if` or a block after this `else`
.suggestion = add an `if` if this is the condition of a chained `else if` statement
-parse_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches
- .branch_label = the attributes are attached to this branch
- .ctx_label = the branch belongs to this `{$ctx}`
- .suggestion = remove the attributes
+parse_expected_expression_found_let = expected expression, found `let` statement
-parse_missing_in_in_for_loop = missing `in` in `for` loop
- .use_in_not_of = try using `in` here instead
- .add_in = try adding `in` here
+parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn`
+ .suggestion = use `Fn` to refer to the trait
-parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop
- .suggestion = try adding an expression to the `for` loop
+parse_expected_identifier = expected identifier
-parse_loop_else = `{$loop_kind}...else` loops are not supported
- .note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
- .loop_keyword = `else` is attached to this loop
+parse_expected_identifier_found_doc_comment = expected identifier, found doc comment
+parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}`
+parse_expected_identifier_found_keyword = expected identifier, found keyword
+parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}`
+parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
+parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}`
+parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
+parse_expected_identifier_found_reserved_keyword_str = expected identifier, found reserved keyword `{$token}`
+parse_expected_identifier_found_str = expected identifier, found `{$token}`
-parse_missing_comma_after_match_arm = expected `,` following `match` arm
- .suggestion = missing a comma here to end this `match` arm
+parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyword in raw pointer type
+ .suggestion = add `mut` or `const` here
-parse_catch_after_try = keyword `catch` cannot follow a `try` block
- .help = try using `match` on the result of the `try` block instead
+parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}`
+parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}`
+parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}`
+parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}`
+parse_expected_semi_found_str = expected `;`, found `{$token}`
-parse_comma_after_base_struct = cannot use a comma after the base struct
- .note = the base struct must always be the last field
- .suggestion = remove this comma
+parse_expected_statement_after_outer_attr = expected statement after outer attribute
-parse_eq_field_init = expected `:`, found `=`
- .suggestion = replace equals symbol with a colon
+parse_expected_trait_in_trait_impl_found_type = expected a trait, found type
-parse_dotdotdot = unexpected token: `...`
- .suggest_exclusive_range = use `..` for an exclusive range
- .suggest_inclusive_range = or `..=` for an inclusive range
+parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements
+ .label = dash-separated idents are not valid
+ .suggestion = if the original crate name uses dashes you need to use underscores in the code
-parse_left_arrow_operator = unexpected token: `<-`
- .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-`
+parse_extern_item_cannot_be_const = extern items cannot be `const`
+ .suggestion = try using a static value
+ .note = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
-parse_remove_let = expected pattern, found `let`
- .suggestion = remove the unnecessary `let` keyword
+parse_extra_if_in_let_else = remove the `if` if you meant to write a `let...else` statement
-parse_use_eq_instead = unexpected `==`
- .suggestion = try using `=` instead
+parse_extra_impl_keyword_in_trait_impl = unexpected `impl` keyword
+ .suggestion = remove the extra `impl`
+ .note = this is parsed as an `impl Trait` type, but a trait is expected at this position
-parse_use_empty_block_not_semi = expected { "`{}`" }, found `;`
- .suggestion = try using { "`{}`" } instead
-parse_comparison_interpreted_as_generic =
- `<` is interpreted as a start of generic arguments for `{$type}`, not a comparison
- .label_args = interpreted as generic arguments
- .label_comparison = not interpreted as comparison
- .suggestion = try comparing the cast value
+parse_field_expression_with_generic = field expressions cannot have generic arguments
-parse_shift_interpreted_as_generic =
- `<<` is interpreted as a start of generic arguments for `{$type}`, not a shift
- .label_args = interpreted as generic arguments
- .label_comparison = not interpreted as shift
- .suggestion = try shifting the cast value
+parse_float_literal_requires_integer_part = float literals must have an integer part
+ .suggestion = must have an integer part
+
+parse_float_literal_unsupported_base = {$base} float literal is not supported
+
+parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async`
+ .label = `async` because of this
+ .suggestion = remove the `async` qualifier
+
+parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const`
+ .label = `const` because of this
+ .suggestion = remove the `const` qualifier
+
+parse_fn_ptr_with_generics = function pointer types may not have generic parameters
+ .suggestion = consider moving the lifetime {$arity ->
+ [one] parameter
+ *[other] parameters
+ } to {$for_param_list_exists ->
+ [true] the
+ *[false] a
+ } `for` parameter list
+
+parse_forgot_paren = perhaps you forgot parentheses?
parse_found_expr_would_be_stmt = expected expression, found `{$token}`
.label = expected expression
-parse_leading_plus_not_supported = leading `+` is not supported
- .label = unexpected `+`
- .suggestion_remove_plus = try removing the `+`
+parse_function_body_equals_expr = function body cannot be `= expression;`
+ .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`
-parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call arguments
- .suggestion_braces_for_struct = if `{$type}` is a struct, use braces as delimiters
- .suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly
+parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets
+ .suggestion = surround the type parameters with angle brackets
-parse_labeled_loop_in_break = parentheses are required around this expression to avoid confusion with a labeled break expression
+parse_generics_in_path = unexpected generic arguments in path
-parse_sugg_wrap_expression_in_parentheses = wrap the expression in parentheses
+parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
+parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
+parse_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
+parse_if_expression_missing_condition = missing condition for `if` expression
+ .condition_label = expected condition here
+ .block_label = if this block is the condition of the `if` expression, then it must be followed by another block
-parse_array_brackets_instead_of_braces = this is a block expression, not an array
- .suggestion = to make an array, use square brackets instead of curly braces
+parse_if_expression_missing_then_block = this `if` expression is missing a block after the condition
+ .add_then_block = add a block here
+ .condition_possibly_unfinished = this binary operation is possibly unfinished
-parse_match_arm_body_without_braces = `match` arm body without braces
- .label_statements = {$num_statements ->
- [one] this statement is not surrounded by a body
- *[other] these statements are not surrounded by a body
- }
- .label_arrow = while parsing the `match` arm starting here
- .suggestion_add_braces = surround the {$num_statements ->
- [one] statement
- *[other] statements
- } with a body
- .suggestion_use_comma_not_semicolon = replace `;` with `,` to end a `match` arm expression
+parse_in_in_typo =
+ expected iterable, found keyword `in`
+ .suggestion = remove the duplicated `in`
+
+parse_inappropriate_default = {$article} {$descr} cannot be `default`
+ .label = `default` because of this
+ .note = only associated `fn`, `const`, and `type` items can be `default`
parse_inclusive_range_extra_equals = unexpected `=` after inclusive range
.suggestion_remove_eq = use `..=` instead
@@ -238,32 +306,18 @@ parse_inclusive_range_no_end = inclusive range with no end
.suggestion_open_range = use `..` instead
.note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
-parse_struct_literal_not_allowed_here = struct literals are not allowed here
- .suggestion = surround the struct literal with parentheses
-
-parse_invalid_interpolated_expression = invalid interpolated expression
-
-parse_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
-parse_octal_float_literal_not_supported = octal float literal is not supported
-parse_binary_float_literal_not_supported = binary float literal is not supported
-parse_not_supported = not supported
+parse_incorrect_braces_trait_bounds = incorrect braces around trait bounds
+ .suggestion = remove the parentheses
-parse_invalid_literal_suffix = suffixes on {$kind} literals are invalid
- .label = invalid suffix `{$suffix}`
-
-parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
- .label = invalid suffix `{$suffix}`
- .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
- .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access
- .tuple_exception_line_3 = see issue #60210 <https://github.com/rust-lang/rust/issues/60210> for more information
-
-parse_non_string_abi_literal = non-string ABI literal
- .suggestion = specify the ABI with a string literal
+parse_incorrect_semicolon =
+ expected item, found `;`
+ .suggestion = remove this semicolon
+ .help = {$name} declarations are not followed by a semicolon
-parse_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}`
- .label_unmatched = mismatched closing delimiter
- .label_opening_candidate = closing delimiter possibly meant for this
- .label_unclosed = unclosed delimiter
+parse_incorrect_use_of_await =
+ incorrect use of `await`
+ .parentheses_suggestion = `await` is not a method call, remove the parentheses
+ .postfix_suggestion = `await` is a postfix operation
parse_incorrect_visibility_restriction = incorrect visibility restriction
.help = some possible visibility restrictions are:
@@ -272,36 +326,8 @@ parse_incorrect_visibility_restriction = incorrect visibility restriction
`pub(in path::to::module)`: visible only on the specified path
.suggestion = make this visible only to module `{$inner_str}` with `in`
-parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed
-
-parse_expected_statement_after_outer_attr = expected statement after outer attribute
-
-parse_doc_comment_does_not_document_anything = found a documentation comment that doesn't document anything
- .help = doc comments must come before what they document, if a comment was intended use `//`
- .suggestion = missing comma here
-
-parse_const_let_mutually_exclusive = `const` and `let` are mutually exclusive
- .suggestion = remove `let`
-
-parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
-parse_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed
-parse_extra_if_in_let_else = remove the `if` if you meant to write a `let...else` statement
-
-parse_compound_assignment_expression_in_let = can't reassign to an uninitialized variable
- .suggestion = initialize the variable
- .help = if you meant to overwrite, remove the `let` binding
-
-parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
- .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
-
-parse_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item}
-parse_sugg_change_inner_attr_to_outer = to annotate the {$item}, change the attribute from inner to outer style
-
-parse_inner_attr_not_permitted_after_outer_doc_comment = an inner attribute is not permitted following an outer doc comment
- .label_attr = not permitted following an outer doc comment
- .label_prev_doc_comment = previous doc comment
+parse_inner_attr_explanation = inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
+parse_inner_attr_not_permitted = an inner attribute is not permitted in this context
.label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this}
.sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer}
@@ -311,139 +337,189 @@ parse_inner_attr_not_permitted_after_outer_attr = an inner attribute is not perm
.label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this}
.sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer}
-parse_inner_attr_not_permitted = an inner attribute is not permitted in this context
+parse_inner_attr_not_permitted_after_outer_doc_comment = an inner attribute is not permitted following an outer doc comment
+ .label_attr = not permitted following an outer doc comment
+ .label_prev_doc_comment = previous doc comment
.label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this}
.sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer}
-parse_inner_attr_explanation = inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
-parse_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them
-
parse_inner_doc_comment_not_permitted = expected outer doc comment
.note = inner doc comments like this (starting with `//!` or `/*!`) can only appear before items
.suggestion = you might have meant to write a regular comment
.label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item}
.sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style
-parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}`
-parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}`
-parse_expected_identifier_found_reserved_keyword_str = expected identifier, found reserved keyword `{$token}`
-parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}`
-parse_expected_identifier_found_str = expected identifier, found `{$token}`
+parse_int_literal_too_large = integer literal is too large
-parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
-parse_expected_identifier_found_keyword = expected identifier, found keyword
-parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
-parse_expected_identifier_found_doc_comment = expected identifier, found doc comment
-parse_expected_identifier = expected identifier
+parse_invalid_block_macro_segment = cannot use a `block` macro fragment here
+ .label = the `block` fragment is within this context
-parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier
+parse_invalid_char_in_escape = {parse_invalid_char_in_escape_msg}: `{$ch}`
+ .label = {parse_invalid_char_in_escape_msg}
-parse_sugg_remove_comma = remove this comma
+parse_invalid_char_in_escape_msg = invalid character in {$is_hex ->
+ [true] numeric character
+ *[false] unicode
+ } escape
-parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}`
-parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}`
-parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}`
-parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}`
-parse_expected_semi_found_str = expected `;`, found `{$token}`
+parse_invalid_comparison_operator = invalid comparison operator `{$invalid}`
+ .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}`
+ .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering`
-parse_sugg_change_this_to_semi = change this to `;`
-parse_sugg_add_semi = add `;` here
-parse_label_unexpected_token = unexpected token
+parse_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed
+parse_invalid_digit_literal = invalid digit for a base {$base} literal
-parse_unmatched_angle_brackets = {$num_extra_brackets ->
- [one] unmatched angle bracket
- *[other] unmatched angle brackets
+parse_invalid_dyn_keyword = invalid `dyn` keyword
+ .help = `dyn` is only needed at the start of a trait `+`-separated list
+ .suggestion = remove this keyword
+
+parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
+parse_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
+ .label = invalid suffix `{$suffix}`
+ .help = valid suffixes are `f32` and `f64`
+
+parse_invalid_float_literal_width = invalid width `{$width}` for float literal
+ .help = valid widths are 32 and 64
+
+parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
+
+parse_invalid_int_literal_width = invalid width `{$width}` for integer literal
+ .help = valid widths are 8, 16, 32, 64 and 128
+
+parse_invalid_interpolated_expression = invalid interpolated expression
+
+parse_invalid_literal_suffix = suffixes on {$kind} literals are invalid
+ .label = invalid suffix `{$suffix}`
+
+parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
+ .label = invalid suffix `{$suffix}`
+ .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
+ .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access
+ .tuple_exception_line_3 = see issue #60210 <https://github.com/rust-lang/rust/issues/60210> for more information
+
+parse_invalid_logical_operator = `{$incorrect}` is not a logical operator
+ .note = unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+ .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction
+ .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction
+
+parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
+
+parse_invalid_num_literal_base_prefix = invalid base prefix for number literal
+ .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase
+ .suggestion = try making the prefix lowercase
+
+parse_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal
+ .label = invalid suffix `{$suffix}`
+ .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+parse_invalid_unicode_escape = invalid unicode character escape
+ .label = invalid escape
+ .help = unicode escape must {$surrogate ->
+ [true] not be a surrogate
+ *[false] be at most 10FFFF
}
- .suggestion = {$num_extra_brackets ->
- [one] remove extra angle bracket
- *[other] remove extra angle brackets
- }
-parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets
- .suggestion = surround the type parameters with angle brackets
+parse_invalid_variable_declaration =
+ invalid variable declaration
-parse_comparison_operators_cannot_be_chained = comparison operators cannot be chained
- .sugg_parentheses_for_function_args = or use `(...)` if you meant to specify fn arguments
- .sugg_split_comparison = split the comparison into two
- .sugg_parenthesize = parenthesize the comparison
-parse_sugg_turbofish_syntax = use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+parse_kw_bad_case = keyword `{$kw}` is written in the wrong case
+ .suggestion = write it in the correct case
-parse_question_mark_in_type = invalid `?` in type
- .label = `?` is only allowed on expressions, not types
- .suggestion = if you meant to express that the type might not contain a value, use the `Option` wrapper type
+parse_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item}
+parse_label_unexpected_token = unexpected token
-parse_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head
- .suggestion = remove parentheses in `for` loop
+parse_label_while_parsing_or_pattern_here = while parsing this or-pattern starting here
-parse_doc_comment_on_param_type = documentation comments cannot be applied to a function parameter's type
- .label = doc comments are not allowed here
+parse_labeled_loop_in_break = parentheses are required around this expression to avoid confusion with a labeled break expression
-parse_attribute_on_param_type = attributes cannot be applied to a function parameter's type
- .label = attributes are not allowed here
+parse_leading_plus_not_supported = leading `+` is not supported
+ .label = unexpected `+`
+ .suggestion_remove_plus = try removing the `+`
-parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies
- .suggestion = give this argument a name or use an underscore to ignore it
+parse_leading_underscore_unicode_escape = {parse_leading_underscore_unicode_escape_label}: `_`
+parse_leading_underscore_unicode_escape_label = invalid start of unicode escape
-parse_self_param_not_first = unexpected `self` parameter in function
- .label = must be the first parameter of an associated function
+parse_left_arrow_operator = unexpected token: `<-`
+ .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-`
-parse_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments
- .suggestion = enclose the `const` expression in braces
+parse_lifetime_after_mut = lifetime must precede `mut`
+ .suggestion = place the lifetime before `mut`
-parse_unexpected_const_param_declaration = unexpected `const` parameter declaration
- .label = expected a `const` expression, not a parameter declaration
- .suggestion = `const` parameters must be declared for the `impl`
+parse_lifetime_in_borrow_expression = borrow expressions cannot be annotated with lifetimes
+ .suggestion = remove the lifetime annotation
+ .label = annotated with lifetime here
-parse_unexpected_const_in_generic_param = expected lifetime, type, or constant, found keyword `const`
- .suggestion = the `const` keyword is only needed in the definition of the type
+parse_lone_slash = invalid trailing slash in literal
+ .label = {parse_lone_slash}
-parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
- .suggestion = try switching the order
+parse_loop_else = `{$loop_kind}...else` loops are not supported
+ .note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
+ .loop_keyword = `else` is attached to this loop
-parse_double_colon_in_bound = expected `:` followed by trait or lifetime
- .suggestion = use single colon
+parse_macro_invocation_visibility = can't qualify macro invocation with `pub`
+ .suggestion = remove the visibility
+ .help = try adjusting the macro to put `{$vis}` inside the invocation
-parse_fn_ptr_with_generics = function pointer types may not have generic parameters
- .suggestion = consider moving the lifetime {$arity ->
- [one] parameter
- *[other] parameters
- } to {$for_param_list_exists ->
- [true] the
- *[false] a
- } `for` parameter list
+parse_macro_invocation_with_qualified_path = macros cannot use qualified paths
-parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
+parse_macro_name_remove_bang = macro names aren't followed by a `!`
+ .suggestion = remove the `!`
+
+parse_macro_rules_missing_bang = expected `!` after `macro_rules`
+ .suggestion = add a `!`
+
+parse_macro_rules_visibility = can't qualify macro_rules invocation with `{$vis}`
+ .suggestion = try exporting the macro
+
+parse_malformed_cfg_attr = malformed `cfg_attr` attribute input
+ .suggestion = missing condition and attribute
+ .note = for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+parse_malformed_loop_label = malformed loop label
+ .suggestion = use the correct loop label format
+
+parse_match_arm_body_without_braces = `match` arm body without braces
+ .label_statements = {$num_statements ->
+ [one] this statement is not surrounded by a body
+ *[other] these statements are not surrounded by a body
+ }
+ .label_arrow = while parsing the `match` arm starting here
+ .suggestion_add_braces = surround the {$num_statements ->
+ [one] statement
+ *[other] statements
+ } with a body
+ .suggestion_use_comma_not_semicolon = replace `;` with `,` to end a `match` arm expression
parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn`
.suggestion = replace `fn` with `impl` here
-parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn`
- .suggestion = use `Fn` to refer to the trait
+parse_maybe_recover_from_bad_qpath_stage_2 =
+ missing angle brackets in associated item path
+ .suggestion = try: `{$ty}`
-parse_where_clause_before_tuple_struct_body = where clauses are not allowed before tuple struct bodies
- .label = unexpected where clause
- .name_label = while parsing this tuple struct
- .body_label = the struct body
- .suggestion = move the body before the where clause
+parse_maybe_recover_from_bad_type_plus =
+ expected a path on the left-hand side of `+`, not `{$ty}`
-parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
- .label = to use `async fn`, switch to Rust 2018 or later
+parse_maybe_report_ambiguous_plus =
+ ambiguous `+` in a type
+ .suggestion = use parentheses to disambiguate
-parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later
+parse_meta_bad_delim = wrong meta list delimiters
+parse_meta_bad_delim_suggestion = the delimiters should be `(` and `)`
-parse_self_argument_pointer = cannot pass `self` by raw pointer
- .label = cannot pass `self` by raw pointer
+parse_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}`
+ .label_unmatched = mismatched closing delimiter
+ .label_opening_candidate = closing delimiter possibly meant for this
+ .label_unclosed = unclosed delimiter
-parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by an item
- .label = the visibility
- .help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}`
+parse_missing_comma_after_match_arm = expected `,` following `match` arm
+ .suggestion = missing a comma here to end this `match` arm
-parse_default_not_followed_by_item = `default` is not followed by an item
- .label = the `default` qualifier
- .note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
+parse_missing_const_type = missing type for `{$kind}` item
+ .suggestion = provide a type for the item
-parse_missing_struct_for_struct_definition = missing `struct` for struct definition
- .suggestion = add `struct` here to parse `{$ident}` as a public struct
+parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop
+ .suggestion = try adding an expression to the `for` loop
parse_missing_fn_for_function_definition = missing `fn` for function definition
.suggestion = add `fn` here to parse `{$ident}` as a public function
@@ -451,269 +527,275 @@ parse_missing_fn_for_function_definition = missing `fn` for function definition
parse_missing_fn_for_method_definition = missing `fn` for method definition
.suggestion = add `fn` here to parse `{$ident}` as a public method
-parse_ambiguous_missing_keyword_for_item_definition = missing `fn` or `struct` for function or struct definition
- .suggestion = if you meant to call a macro, try
- .help = if you meant to call a macro, remove the `pub` and add a trailing `!` after the identifier
+parse_missing_for_in_trait_impl = missing `for` in a trait impl
+ .suggestion = add `for` here
+
+parse_missing_in_in_for_loop = missing `in` in `for` loop
+ .use_in_not_of = try using `in` here instead
+ .add_in = try adding `in` here
+
+parse_missing_let_before_mut = missing keyword
+parse_missing_plus_in_bounds = expected `+` between lifetime and {$sym}
+ .suggestion = add `+`
+
+parse_missing_semicolon_before_array = expected `;`, found `[`
+ .suggestion = consider adding `;` here
+
+parse_missing_struct_for_struct_definition = missing `struct` for struct definition
+ .suggestion = add `struct` here to parse `{$ident}` as a public struct
parse_missing_trait_in_trait_impl = missing trait in a trait impl
.suggestion_add_trait = add a trait here
.suggestion_remove_for = for an inherent impl, drop this `for`
-parse_missing_for_in_trait_impl = missing `for` in a trait impl
- .suggestion = add `for` here
+parse_modifier_lifetime = `{$sigil}` may only modify trait bounds, not lifetime bounds
+ .suggestion = remove the `{$sigil}`
-parse_expected_trait_in_trait_impl_found_type = expected a trait, found type
+parse_more_than_one_char = character literal may only contain one codepoint
+ .followed_by = this `{$chr}` is followed by the combining {$len ->
+ [one] mark
+ *[other] marks
+ } `{$escaped_marks}`
+ .non_printing = there are non-printing characters, the full sequence is `{$escaped}`
+ .consider_normalized = consider using the normalized form `{$ch}` of this character
+ .remove_non = consider removing the non-printing characters
+ .use_double_quotes = if you meant to write a {$is_byte ->
+ [true] byte string
+ *[false] `str`
+ } literal, use double quotes
-parse_non_item_in_item_list = non-item in item list
- .suggestion_use_const_not_let = consider using `const` instead of `let` for associated const
- .label_list_start = item list starts here
- .label_non_item = non-item starts here
- .label_list_end = item list ends here
- .suggestion_remove_semicolon = consider removing this semicolon
+parse_multiple_skipped_lines = multiple lines skipped by escaped newline
+ .label = skipping everything up to and including this point
-parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases
+parse_multiple_where_clauses = cannot define duplicate `where` clauses on an item
+ .label = previous `where` clause starts here
+ .suggestion = consider joining the two `where` clauses into one
-parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto`
-parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe`
+parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual binding
+ .suggestion = add `mut` to each binding
+parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding
+ .suggestion = remove the `mut` prefix
+parse_need_plus_after_trait_object_lifetime = lifetime in trait object type must be followed by `+`
-parse_associated_static_item_not_allowed = associated `static` items are not allowed
+parse_nested_adt = `{$kw_str}` definition cannot be nested inside `{$keyword}`
+ .suggestion = consider creating a new `{$kw_str}` definition instead of nesting
-parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements
- .label = dash-separated idents are not valid
- .suggestion = if the original crate name uses dashes you need to use underscores in the code
+parse_nested_c_variadic_type = C-variadic type `...` may not be nested inside another type
-parse_extern_item_cannot_be_const = extern items cannot be `const`
- .suggestion = try using a static value
- .note = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+parse_no_brace_unicode_escape = incorrect unicode escape sequence
+ .label = {parse_no_brace_unicode_escape}
+ .use_braces = format of unicode escape sequences uses braces
+ .format_of_unicode = format of unicode escape sequences is `\u{"{...}"}`
-parse_const_global_cannot_be_mutable = const globals cannot be mutable
- .label = cannot be mutable
- .suggestion = you might want to declare a static instead
+parse_no_digits_literal = no valid digits found for number
-parse_missing_const_type = missing type for `{$kind}` item
- .suggestion = provide a type for the item
+parse_non_item_in_item_list = non-item in item list
+ .suggestion_use_const_not_let = consider using `const` instead of `let` for associated const
+ .label_list_start = item list starts here
+ .label_non_item = non-item starts here
+ .label_list_end = item list ends here
+ .suggestion_remove_semicolon = consider removing this semicolon
-parse_enum_struct_mutually_exclusive = `enum` and `struct` are mutually exclusive
- .suggestion = replace `enum struct` with
+parse_non_string_abi_literal = non-string ABI literal
+ .suggestion = specify the ABI with a string literal
-parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name
-parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}`
-parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}`
-parse_unexpected_token_after_struct_name_found_reserved_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved keyword `{$token}`
-parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}`
-parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}`
+parse_nonterminal_expected_ident = expected ident, found `{$token}`
+parse_nonterminal_expected_item_keyword = expected an item keyword
+parse_nonterminal_expected_lifetime = expected a lifetime, found `{$token}`
-parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters
- .note = you cannot use `Self` as a generic parameter because it is reserved for associated items
+parse_nonterminal_expected_statement = expected a statement
+parse_not_supported = not supported
-parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter
- .label = lifetime parameters cannot have default values
+parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
-parse_multiple_where_clauses = cannot define duplicate `where` clauses on an item
- .label = previous `where` clause starts here
- .suggestion = consider joining the two `where` clauses into one
+parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable @ pattern`
-parse_nonterminal_expected_item_keyword = expected an item keyword
-parse_nonterminal_expected_statement = expected a statement
-parse_nonterminal_expected_ident = expected ident, found `{$token}`
-parse_nonterminal_expected_lifetime = expected a lifetime, found `{$token}`
+parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
-parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
+parse_octal_float_literal_not_supported = octal float literal is not supported
parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
-parse_sugg_remove_leading_vert_in_pattern = remove the `|`
-parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses
+parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
+parse_out_of_range_hex_escape = out of range hex escape
+ .label = must be a character in the range [\x00-\x7f]
-parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
+parse_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them
-parse_unexpected_vert_vert_before_function_parameter = unexpected `||` before function parameter
- .suggestion = remove the `||`
+parse_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches
+ .branch_label = the attributes are attached to this branch
+ .ctx_label = the branch belongs to this `{$ctx}`
+ .suggestion = remove the attributes
-parse_label_while_parsing_or_pattern_here = while parsing this or-pattern starting here
+parse_overlong_unicode_escape = overlong unicode escape
+ .label = must have at most 6 hex digits
-parse_unexpected_vert_vert_in_pattern = unexpected token `||` in pattern
- .suggestion = use a single `|` to separate multiple alternative patterns
+parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call arguments
+ .suggestion_braces_for_struct = if `{$type}` is a struct, use braces as delimiters
+ .suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly
-parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern
- .suggestion = remove the `{$token}`
+parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported
+ .suggestion = remove the parentheses
-parse_dotdotdot_rest_pattern = unexpected `...`
- .label = not a valid pattern
- .suggestion = for a rest pattern, use `..` instead of `...`
+parse_path_single_colon = path separator must be a double colon
+ .suggestion = use a double colon instead
+
+parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies
+ .suggestion = give this argument a name or use an underscore to ignore it
parse_pattern_on_wrong_side_of_at = pattern on wrong side of `@`
.label_pattern = pattern on the left, should be on the right
.label_binding = binding on the right, should be on the left
.suggestion = switch the order
-parse_expected_binding_left_of_at = left-hand side of `@` must be a binding
- .label_lhs = interpreted as a pattern, not a binding
- .label_rhs = also a pattern
- .note = bindings are `x`, `mut x`, `ref x`, and `ref mut x`
-
-parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation
- .suggestion = add parentheses to clarify the precedence
+parse_question_mark_in_type = invalid `?` in type
+ .label = `?` is only allowed on expressions, not types
+ .suggestion = if you meant to express that the type might not contain a value, use the `Option` wrapper type
-parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in pattern
- .suggestion = remove the lifetime
+parse_recover_import_as_use = expected item, found {$token_name}
+ .suggestion = items are imported using the `use` keyword
parse_ref_mut_order_incorrect = the order of `mut` and `ref` is incorrect
.suggestion = try switching the order
-parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual binding
- .suggestion = add `mut` to each binding
-parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding
- .suggestion = remove the `mut` prefix
-parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable @ pattern`
+parse_remove_let = expected pattern, found `let`
+ .suggestion = remove the unnecessary `let` keyword
parse_repeated_mut_in_pattern = `mut` on a binding may not be repeated
.suggestion = remove the additional `mut`s
-parse_dot_dot_dot_range_to_pattern_not_allowed = range-to patterns with `...` are not allowed
- .suggestion = use `..=` instead
+parse_require_colon_after_labeled_expression = labeled expression must be followed by `:`
+ .note = labels are used before loops and blocks, allowing e.g., `break 'label` to them
+ .label = the label
+ .suggestion = add `:` after the label
-parse_enum_pattern_instead_of_identifier = expected identifier, found enum pattern
+parse_return_types_use_thin_arrow = return types are denoted using `->`
+ .suggestion = use `->` instead
-parse_dot_dot_dot_for_remaining_fields = expected field pattern, found `{$token_str}`
- .suggestion = to omit remaining fields, use `..`
+parse_self_argument_pointer = cannot pass `self` by raw pointer
+ .label = cannot pass `self` by raw pointer
-parse_expected_comma_after_pattern_field = expected `,`
+parse_self_param_not_first = unexpected `self` parameter in function
+ .label = must be the first parameter of an associated function
-parse_return_types_use_thin_arrow = return types are denoted using `->`
- .suggestion = use `->` instead
+parse_shift_interpreted_as_generic =
+ `<<` is interpreted as a start of generic arguments for `{$type}`, not a shift
+ .label_args = interpreted as generic arguments
+ .label_comparison = not interpreted as shift
+ .suggestion = try shifting the cast value
-parse_need_plus_after_trait_object_lifetime = lifetime in trait object type must be followed by `+`
+parse_single_colon_import_path = expected `::`, found `:`
+ .suggestion = use double colon
+ .note = import paths are delimited using `::`
-parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyword in raw pointer type
- .suggestion = add `mut` or `const` here
+parse_single_colon_struct_type = found single colon in a struct field type path
+ .suggestion = write a path separator here
-parse_lifetime_after_mut = lifetime must precede `mut`
- .suggestion = place the lifetime before `mut`
+parse_struct_literal_body_without_path =
+ struct literal body without path
+ .suggestion = you might have forgotten to add the struct literal inside the block
-parse_dyn_after_mut = `mut` must precede `dyn`
- .suggestion = place `mut` before `dyn`
+parse_struct_literal_needing_parens =
+ invalid struct literal
+ .suggestion = you might need to surround the struct literal in parentheses
-parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const`
- .label = `const` because of this
- .suggestion = remove the `const` qualifier
+parse_struct_literal_not_allowed_here = struct literals are not allowed here
+ .suggestion = surround the struct literal with parentheses
-parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async`
- .label = `async` because of this
- .suggestion = remove the `async` qualifier
+parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
+ .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-parse_nested_c_variadic_type = C-variadic type `...` may not be nested inside another type
+parse_sugg_add_let_for_stmt = you might have meant to introduce a new binding
-parse_invalid_dyn_keyword = invalid `dyn` keyword
- .help = `dyn` is only needed at the start of a trait `+`-separated list
- .suggestion = remove this keyword
+parse_sugg_add_semi = add `;` here
+parse_sugg_change_inner_attr_to_outer = to annotate the {$item}, change the attribute from inner to outer style
-parse_negative_bounds_not_supported = negative bounds are not supported
- .label = negative bounds are not supported
- .suggestion = {$num_bounds ->
- [one] remove the bound
- *[other] remove the bounds
- }
+parse_sugg_change_this_to_semi = change this to `;`
+parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier
-parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
-parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
-parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
+parse_sugg_remove_comma = remove this comma
+parse_sugg_remove_leading_vert_in_pattern = remove the `|`
+parse_sugg_turbofish_syntax = use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
-parse_unexpected_token_after_dot = unexpected token: `{$actual}`
+parse_sugg_wrap_expression_in_parentheses = wrap the expression in parentheses
-parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier
+parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses
-parse_cr_doc_comment = bare CR not allowed in {$block ->
- [true] block doc-comment
- *[false] doc-comment
-}
+parse_switch_mut_let_order =
+ switch the order of `mut` and `let`
+parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds
-parse_no_digits_literal = no valid digits found for number
+parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
+ .suggestion = use `!` to perform bitwise not
-parse_invalid_digit_literal = invalid digit for a base {$base} literal
+parse_too_many_hashes = too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found {$num}
-parse_empty_exponent_float = expected at least one digit in exponent
+parse_too_short_hex_escape = numeric character escape is too short
-parse_float_literal_unsupported_base = {$base} float literal is not supported
+parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern
+ .suggestion = remove the `{$token}`
-parse_more_than_one_char = character literal may only contain one codepoint
- .followed_by = this `{$chr}` is followed by the combining {$len ->
- [one] mark
- *[other] marks
- } `{$escaped_marks}`
- .non_printing = there are non-printing characters, the full sequence is `{$escaped}`
- .consider_normalized = consider using the normalized form `{$ch}` of this character
- .remove_non = consider removing the non-printing characters
- .use_double_quotes = if you meant to write a {$is_byte ->
- [true] byte string
- *[false] `str`
- } literal, use double quotes
+parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto`
+parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe`
-parse_no_brace_unicode_escape = incorrect unicode escape sequence
- .label = {parse_no_brace_unicode_escape}
- .use_braces = format of unicode escape sequences uses braces
- .format_of_unicode = format of unicode escape sequences is `\u{"{...}"}`
+parse_type_ascription_removed =
+ if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
-parse_invalid_unicode_escape = invalid unicode character escape
- .label = invalid escape
- .help = unicode escape must {$surrogate ->
- [true] not be a surrogate
- *[false] be at most 10FFFF
- }
+parse_unclosed_unicode_escape = unterminated unicode escape
+ .label = missing a closing `{"}"}`
+ .terminate = terminate the unicode escape
-parse_escape_only_char = {$byte ->
- [true] byte
- *[false] character
- } constant must be escaped: `{$escaped_msg}`
- .escape = escape the character
+parse_underscore_literal_suffix = underscore literal suffix is not allowed
-parse_bare_cr = {$double_quotes ->
- [true] bare CR not allowed in string, use `\r` instead
- *[false] character constant must be escaped: `\r`
- }
- .escape = escape the character
+parse_unexpected_const_in_generic_param = expected lifetime, type, or constant, found keyword `const`
+ .suggestion = the `const` keyword is only needed in the definition of the type
-parse_bare_cr_in_raw_string = bare CR not allowed in raw string
+parse_unexpected_const_param_declaration = unexpected `const` parameter declaration
+ .label = expected a `const` expression, not a parameter declaration
+ .suggestion = `const` parameters must be declared for the `impl`
-parse_too_short_hex_escape = numeric character escape is too short
+parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter
+ .label = lifetime parameters cannot have default values
-parse_invalid_char_in_escape = {parse_invalid_char_in_escape_msg}: `{$ch}`
- .label = {parse_invalid_char_in_escape_msg}
+parse_unexpected_if_with_if = unexpected `if` in the condition expression
+ .suggestion = remove the `if`
-parse_invalid_char_in_escape_msg = invalid character in {$is_hex ->
- [true] numeric character
- *[false] unicode
- } escape
+parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in pattern
+ .suggestion = remove the lifetime
-parse_out_of_range_hex_escape = out of range hex escape
- .label = must be a character in the range [\x00-\x7f]
+parse_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head
+ .suggestion = remove parentheses in `for` loop
-parse_leading_underscore_unicode_escape = {parse_leading_underscore_unicode_escape_label}: `_`
-parse_leading_underscore_unicode_escape_label = invalid start of unicode escape
+parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters
+ .note = you cannot use `Self` as a generic parameter because it is reserved for associated items
-parse_overlong_unicode_escape = overlong unicode escape
- .label = must have at most 6 hex digits
+parse_unexpected_token_after_dot = unexpected token: `{$actual}`
-parse_unclosed_unicode_escape = unterminated unicode escape
- .label = missing a closing `{"}"}`
- .terminate = terminate the unicode escape
+parse_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label
+ .suggestion_remove_label = consider removing the label
+ .suggestion_enclose_in_block = consider enclosing expression in a block
-parse_unicode_escape_in_byte = unicode escape in byte string
- .label = {parse_unicode_escape_in_byte}
- .help = unicode escape sequences cannot be used as a byte or in a byte string
+parse_unexpected_token_after_not = unexpected {$negated_desc} after identifier
+parse_unexpected_token_after_not_bitwise = use `!` to perform bitwise not
+parse_unexpected_token_after_not_default = use `!` to perform logical negation or bitwise not
-parse_empty_unicode_escape = empty unicode escape
- .label = this escape must have at least 1 hex digit
+parse_unexpected_token_after_not_logical = use `!` to perform logical negation
+parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name
+parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}`
+parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}`
+parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}`
-parse_zero_chars = empty character literal
- .label = {parse_zero_chars}
+parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}`
+parse_unexpected_token_after_struct_name_found_reserved_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved keyword `{$token}`
+parse_unexpected_vert_vert_before_function_parameter = unexpected `||` before function parameter
+ .suggestion = remove the `||`
-parse_lone_slash = invalid trailing slash in literal
- .label = {parse_lone_slash}
+parse_unexpected_vert_vert_in_pattern = unexpected token `||` in pattern
+ .suggestion = use a single `|` to separate multiple alternative patterns
-parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped
- .label = {parse_unskipped_whitespace}
+parse_unicode_escape_in_byte = unicode escape in byte string
+ .label = {parse_unicode_escape_in_byte}
+ .help = unicode escape sequences cannot be used as a byte or in a byte string
-parse_multiple_skipped_lines = multiple lines skipped by escaped newline
- .label = skipping everything up to and including this point
+parse_unknown_builtin_construct = unknown `builtin #` construct `{$name}`
parse_unknown_prefix = prefix `{$prefix}` is unknown
.label = unknown prefix
@@ -721,8 +803,6 @@ parse_unknown_prefix = prefix `{$prefix}` is unknown
.suggestion_br = use `br` for a raw byte string
.suggestion_whitespace = consider inserting whitespace here
-parse_too_many_hashes = too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found {$num}
-
parse_unknown_start_of_token = unknown start of token: {$escaped}
.sugg_quotes = Unicode characters '“' (Left Double Quotation Mark) and '”' (Right Double Quotation Mark) look like '{$ascii_str}' ({$ascii_name}), but are not
.sugg_other = Unicode character '{$ch}' ({$u_name}) looks like '{$ascii_str}' ({$ascii_name}), but it is not
@@ -732,13 +812,48 @@ parse_unknown_start_of_token = unknown start of token: {$escaped}
*[other] {$repeats} more times
}
-parse_box_syntax_removed = `box_syntax` has been removed
- .suggestion = use `Box::new()` instead
+parse_unmatched_angle = unmatched angle {$plural ->
+ [true] brackets
+ *[false] bracket
+ }
+ .suggestion = remove extra angle {$plural ->
+ [true] brackets
+ *[false] bracket
+ }
-parse_bad_return_type_notation_output =
- return type not allowed with return type notation
- .suggestion = remove the return type
+parse_unmatched_angle_brackets = {$num_extra_brackets ->
+ [one] unmatched angle bracket
+ *[other] unmatched angle brackets
+ }
+ .suggestion = {$num_extra_brackets ->
+ [one] remove extra angle bracket
+ *[other] remove extra angle brackets
+ }
-parse_bad_return_type_notation_dotdot =
- return type notation uses `()` instead of `(..)` for elided arguments
- .suggestion = remove the `..`
+parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped
+ .label = {parse_unskipped_whitespace}
+
+parse_use_empty_block_not_semi = expected { "`{}`" }, found `;`
+ .suggestion = try using { "`{}`" } instead
+
+parse_use_eq_instead = unexpected `==`
+ .suggestion = try using `=` instead
+
+parse_use_let_not_auto = write `let` instead of `auto` to introduce a new variable
+parse_use_let_not_var = write `let` instead of `var` to introduce a new variable
+
+parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by an item
+ .label = the visibility
+ .help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}`
+
+parse_where_clause_before_tuple_struct_body = where clauses are not allowed before tuple struct bodies
+ .label = unexpected where clause
+ .name_label = while parsing this tuple struct
+ .body_label = the struct body
+ .suggestion = move the body before the where clause
+
+parse_where_generics = generic parameters on `where` clauses are reserved for future use
+ .label = currently unsupported
+
+parse_zero_chars = empty character literal
+ .label = {parse_zero_chars}
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 069217165..84494eab8 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -907,6 +907,18 @@ pub(crate) struct SuggRemoveComma {
}
#[derive(Subdiagnostic)]
+#[suggestion(
+ parse_sugg_add_let_for_stmt,
+ style = "verbose",
+ applicability = "maybe-incorrect",
+ code = "let "
+)]
+pub(crate) struct SuggAddMissingLetStmt {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
pub(crate) enum ExpectedIdentifierFound {
#[label(parse_expected_identifier_found_reserved_identifier)]
ReservedIdentifier(#[primary_span] Span),
@@ -1341,6 +1353,28 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword {
}
#[derive(Diagnostic)]
+#[diag(parse_path_single_colon)]
+pub(crate) struct PathSingleColon {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = "::")]
+ pub span: Span,
+
+ #[note(parse_type_ascription_removed)]
+ pub type_ascription: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_colon_as_semi)]
+pub(crate) struct ColonAsSemi {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = ";")]
+ pub span: Span,
+
+ #[note(parse_type_ascription_removed)]
+ pub type_ascription: Option<()>,
+}
+
+#[derive(Diagnostic)]
#[diag(parse_where_clause_before_tuple_struct_body)]
pub(crate) struct WhereClauseBeforeTupleStructBody {
#[primary_span]
@@ -1486,6 +1520,16 @@ pub(crate) struct ExpectedTraitInTraitImplFoundType {
}
#[derive(Diagnostic)]
+#[diag(parse_extra_impl_keyword_in_trait_impl)]
+pub(crate) struct ExtraImplKeywordInTraitImpl {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "maybe-incorrect")]
+ pub extra_impl_kw: Span,
+ #[note]
+ pub impl_trait_span: Span,
+}
+
+#[derive(Diagnostic)]
#[diag(parse_bounds_not_allowed_on_trait_aliases)]
pub(crate) struct BoundsNotAllowedOnTraitAliases {
#[primary_span]
@@ -2258,31 +2302,6 @@ pub(crate) struct InvalidDynKeyword {
pub span: Span,
}
-#[derive(Diagnostic)]
-#[diag(parse_negative_bounds_not_supported)]
-pub(crate) struct NegativeBoundsNotSupported {
- #[primary_span]
- pub negative_bounds: Vec<Span>,
- #[label]
- pub last_span: Span,
- #[subdiagnostic]
- pub sub: Option<NegativeBoundsNotSupportedSugg>,
-}
-
-#[derive(Subdiagnostic)]
-#[suggestion(
- parse_suggestion,
- style = "tool-only",
- code = "{fixed}",
- applicability = "machine-applicable"
-)]
-pub(crate) struct NegativeBoundsNotSupportedSugg {
- #[primary_span]
- pub bound_list: Span,
- pub num_bounds: usize,
- pub fixed: String,
-}
-
#[derive(Subdiagnostic)]
pub enum HelpUseLatestEdition {
#[help(parse_help_set_edition_cargo)]
@@ -2332,3 +2351,333 @@ pub(crate) struct BadReturnTypeNotationDotDot {
#[suggestion(code = "", applicability = "maybe-incorrect")]
pub span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(parse_bad_assoc_type_bounds)]
+pub(crate) struct BadAssocTypeBounds {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_attr_after_generic)]
+pub(crate) struct AttrAfterGeneric {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_attr_without_generics)]
+pub(crate) struct AttrWithoutGenerics {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_where_generics)]
+pub(crate) struct WhereOnGenerics {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_generics_in_path)]
+pub(crate) struct GenericsInPath {
+ #[primary_span]
+ pub span: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_assoc_lifetime)]
+#[help]
+pub(crate) struct AssocLifetime {
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub lifetime: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_tilde_const_lifetime)]
+pub(crate) struct TildeConstLifetime {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_modifier_lifetime)]
+pub(crate) struct ModifierLifetime {
+ #[primary_span]
+ #[suggestion(style = "tool-only", applicability = "maybe-incorrect", code = "")]
+ pub span: Span,
+ pub sigil: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_parenthesized_lifetime)]
+pub(crate) struct ParenthesizedLifetime {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(style = "short", applicability = "machine-applicable", code = "{snippet}")]
+ pub sugg: Option<Span>,
+ pub snippet: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_const_bounds_missing_tilde)]
+pub(crate) struct ConstMissingTilde {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = "~", applicability = "machine-applicable")]
+ pub start: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_underscore_literal_suffix)]
+pub(crate) struct UnderscoreLiteralSuffix {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_expect_label_found_ident)]
+pub(crate) struct ExpectedLabelFoundIdent {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = "'", applicability = "machine-applicable", style = "short")]
+ pub start: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_inappropriate_default)]
+#[note]
+pub(crate) struct InappropriateDefault {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub article: &'static str,
+ pub descr: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_recover_import_as_use)]
+pub(crate) struct RecoverImportAsUse {
+ #[primary_span]
+ #[suggestion(code = "use", applicability = "machine-applicable", style = "short")]
+ pub span: Span,
+ pub token_name: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_single_colon_import_path)]
+#[note]
+pub(crate) struct SingleColonImportPath {
+ #[primary_span]
+ #[suggestion(code = "::", applicability = "machine-applicable", style = "short")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_bad_item_kind)]
+#[help]
+pub(crate) struct BadItemKind {
+ #[primary_span]
+ pub span: Span,
+ pub descr: &'static str,
+ pub ctx: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_single_colon_struct_type)]
+pub(crate) struct SingleColonStructType {
+ #[primary_span]
+ #[suggestion(code = "::", applicability = "maybe-incorrect", style = "verbose")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_equals_struct_default)]
+pub(crate) struct EqualsStructDefault {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "machine-applicable")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_macro_rules_missing_bang)]
+pub(crate) struct MacroRulesMissingBang {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = "!", applicability = "machine-applicable", style = "verbose")]
+ pub hi: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_macro_name_remove_bang)]
+pub(crate) struct MacroNameRemoveBang {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "machine-applicable")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_macro_rules_visibility)]
+pub(crate) struct MacroRulesVisibility<'a> {
+ #[primary_span]
+ #[suggestion(code = "#[macro_export]", applicability = "maybe-incorrect")]
+ pub span: Span,
+ pub vis: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_macro_invocation_visibility)]
+#[help]
+pub(crate) struct MacroInvocationVisibility<'a> {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "machine-applicable")]
+ pub span: Span,
+ pub vis: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_nested_adt)]
+pub(crate) struct NestedAdt<'a> {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = "", applicability = "maybe-incorrect")]
+ pub item: Span,
+ pub keyword: &'a str,
+ pub kw_str: Cow<'a, str>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_function_body_equals_expr)]
+pub(crate) struct FunctionBodyEqualsExpr {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: FunctionBodyEqualsExprSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
+pub(crate) struct FunctionBodyEqualsExprSugg {
+ #[suggestion_part(code = "{{")]
+ pub eq: Span,
+ #[suggestion_part(code = " }}")]
+ pub semi: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_box_not_pat)]
+pub(crate) struct BoxNotPat {
+ #[primary_span]
+ pub span: Span,
+ #[note]
+ pub kw: Span,
+ #[suggestion(code = "r#", applicability = "maybe-incorrect", style = "verbose")]
+ pub lo: Span,
+ pub descr: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_unmatched_angle)]
+pub(crate) struct UnmatchedAngle {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "machine-applicable")]
+ pub span: Span,
+ pub plural: bool,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_missing_plus_in_bounds)]
+pub(crate) struct MissingPlusBounds {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = " +", applicability = "maybe-incorrect", style = "verbose")]
+ pub hi: Span,
+ pub sym: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_incorrect_braces_trait_bounds)]
+pub(crate) struct IncorrectBracesTraitBounds {
+ #[primary_span]
+ pub span: Vec<Span>,
+ #[subdiagnostic]
+ pub sugg: IncorrectBracesTraitBoundsSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
+pub(crate) struct IncorrectBracesTraitBoundsSugg {
+ #[suggestion_part(code = " ")]
+ pub l: Span,
+ #[suggestion_part(code = "")]
+ pub r: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_kw_bad_case)]
+pub(crate) struct KwBadCase<'a> {
+ #[primary_span]
+ #[suggestion(code = "{kw}", applicability = "machine-applicable")]
+ pub span: Span,
+ pub kw: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_meta_bad_delim)]
+pub(crate) struct MetaBadDelim {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: MetaBadDelimSugg,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_cfg_attr_bad_delim)]
+pub(crate) struct CfgAttrBadDelim {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: MetaBadDelimSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parse_meta_bad_delim_suggestion, applicability = "machine-applicable")]
+pub(crate) struct MetaBadDelimSugg {
+ #[suggestion_part(code = "(")]
+ pub open: Span,
+ #[suggestion_part(code = ")")]
+ pub close: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_malformed_cfg_attr)]
+#[note]
+pub(crate) struct MalformedCfgAttr {
+ #[primary_span]
+ #[suggestion(code = "{sugg}")]
+ pub span: Span,
+ pub sugg: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_unknown_builtin_construct)]
+pub(crate) struct UnknownBuiltinConstruct {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_expected_builtin_ident)]
+pub(crate) struct ExpectedBuiltinIdent {
+ #[primary_span]
+ pub span: Span,
+}
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 9e856c9f2..c6e6b46e4 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -1,3 +1,5 @@
+use std::ops::Range;
+
use crate::errors;
use crate::lexer::unicode_chars::UNICODE_ARRAY;
use crate::make_unclosed_delims_error;
@@ -6,7 +8,7 @@ use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::util::unicode::contains_text_flow_control_chars;
use rustc_errors::{error_code, Applicability, Diagnostic, DiagnosticBuilder, StashKey};
-use rustc_lexer::unescape::{self, Mode};
+use rustc_lexer::unescape::{self, EscapeError, Mode};
use rustc_lexer::Cursor;
use rustc_lexer::{Base, DocStyle, RawStrError};
use rustc_session::lint::builtin::{
@@ -67,7 +69,7 @@ pub(crate) fn parse_token_trees<'a>(
match token_trees {
Ok(stream) if unmatched_delims.is_empty() => Ok(stream),
_ => {
- // Return error if there are unmatched delimiters or unclosng delimiters.
+ // Return error if there are unmatched delimiters or unclosed delimiters.
// We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch
// because the delimiter mismatch is more likely to be the root cause of error
@@ -204,16 +206,15 @@ impl<'a> StringReader<'a> {
rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
let suffix_start = start + BytePos(suffix_start);
let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
+ if let token::LitKind::CStr | token::LitKind::CStrRaw(_) = kind {
+ self.sess.gated_spans.gate(sym::c_str_literals, self.mk_sp(start, self.pos));
+ }
let suffix = if suffix_start < self.pos {
let string = self.str_from(suffix_start);
if string == "_" {
self.sess
.span_diagnostic
- .struct_span_err(
- self.mk_sp(suffix_start, self.pos),
- "underscore literal suffix is not allowed",
- )
- .emit();
+ .emit_err(errors::UnderscoreLiteralSuffix { span: self.mk_sp(suffix_start, self.pos) });
None
} else {
Some(Symbol::intern(string))
@@ -325,7 +326,7 @@ impl<'a> StringReader<'a> {
) -> DiagnosticBuilder<'a, !> {
self.sess
.span_diagnostic
- .struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
+ .struct_span_fatal(self.mk_sp(from_pos, to_pos), format!("{}: {}", m, escaped_char(c)))
}
/// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly
@@ -419,6 +420,16 @@ impl<'a> StringReader<'a> {
}
self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" "
}
+ rustc_lexer::LiteralKind::CStr { terminated } => {
+ if !terminated {
+ self.sess.span_diagnostic.span_fatal_with_code(
+ self.mk_sp(start + BytePos(1), end),
+ "unterminated C string",
+ error_code!(E0767),
+ )
+ }
+ self.cook_c_string(token::CStr, Mode::CStr, start, end, 2, 1) // c" "
+ }
rustc_lexer::LiteralKind::RawStr { n_hashes } => {
if let Some(n_hashes) = n_hashes {
let n = u32::from(n_hashes);
@@ -437,6 +448,15 @@ impl<'a> StringReader<'a> {
self.report_raw_str_error(start, 2);
}
}
+ rustc_lexer::LiteralKind::RawCStr { n_hashes } => {
+ if let Some(n_hashes) = n_hashes {
+ let n = u32::from(n_hashes);
+ let kind = token::CStrRaw(n_hashes);
+ self.cook_c_string(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) // cr##" "##
+ } else {
+ self.report_raw_str_error(start, 2);
+ }
+ }
rustc_lexer::LiteralKind::Int { base, empty_int } => {
if empty_int {
let span = self.mk_sp(start, end);
@@ -546,7 +566,7 @@ impl<'a> StringReader<'a> {
err.span_label(self.mk_sp(start, start), "unterminated raw string");
if n_hashes > 0 {
- err.note(&format!(
+ err.note(format!(
"this raw string should be terminated with `\"{}`",
"#".repeat(n_hashes as usize)
));
@@ -642,7 +662,7 @@ impl<'a> StringReader<'a> {
&RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
prefix_span,
ast::CRATE_NODE_ID,
- &format!("prefix `{prefix}` is unknown"),
+ format!("prefix `{prefix}` is unknown"),
BuiltinLintDiagnostics::ReservedPrefix(prefix_span),
);
}
@@ -652,7 +672,7 @@ impl<'a> StringReader<'a> {
self.sess.emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num });
}
- fn cook_quoted(
+ fn cook_common(
&self,
kind: token::LitKind,
mode: Mode,
@@ -660,12 +680,13 @@ impl<'a> StringReader<'a> {
end: BytePos,
prefix_len: u32,
postfix_len: u32,
+ unescape: fn(&str, Mode, &mut dyn FnMut(Range<usize>, Result<(), EscapeError>)),
) -> (token::LitKind, Symbol) {
let mut has_fatal_err = false;
let content_start = start + BytePos(prefix_len);
let content_end = end - BytePos(postfix_len);
let lit_content = self.str_from_to(content_start, content_end);
- unescape::unescape_literal(lit_content, mode, &mut |range, result| {
+ unescape(lit_content, mode, &mut |range, result| {
// Here we only check for errors. The actual unescaping is done later.
if let Err(err) = result {
let span_with_quotes = self.mk_sp(start, end);
@@ -696,6 +717,38 @@ impl<'a> StringReader<'a> {
(token::Err, self.symbol_from_to(start, end))
}
}
+
+ fn cook_quoted(
+ &self,
+ kind: token::LitKind,
+ mode: Mode,
+ start: BytePos,
+ end: BytePos,
+ prefix_len: u32,
+ postfix_len: u32,
+ ) -> (token::LitKind, Symbol) {
+ self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
+ unescape::unescape_literal(src, mode, &mut |span, result| {
+ callback(span, result.map(drop))
+ })
+ })
+ }
+
+ fn cook_c_string(
+ &self,
+ kind: token::LitKind,
+ mode: Mode,
+ start: BytePos,
+ end: BytePos,
+ prefix_len: u32,
+ postfix_len: u32,
+ ) -> (token::LitKind, Symbol) {
+ self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
+ unescape::unescape_c_string(src, mode, &mut |span, result| {
+ callback(span, result.map(drop))
+ })
+ })
+ }
}
pub fn nfc_normalize(string: &str) -> Symbol {
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index 7c2c08951..318a29985 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -199,8 +199,7 @@ impl<'a> TokenTreesReader<'a> {
// matching opening delimiter).
let token_str = token_to_string(&self.token);
let msg = format!("unexpected closing delimiter: `{}`", token_str);
- let mut err =
- self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg);
+ let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
report_suspicious_mismatch_block(
&mut err,
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 0d12ec608..eb9625f92 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -78,8 +78,7 @@ pub(crate) fn emit_unescape_error(
}
};
let sugg = sugg.unwrap_or_else(|| {
- let is_byte = mode.is_byte();
- let prefix = if is_byte { "b" } else { "" };
+ let prefix = mode.prefix_noraw();
let mut escaped = String::with_capacity(lit.len());
let mut chrs = lit.chars().peekable();
while let Some(first) = chrs.next() {
@@ -97,7 +96,11 @@ pub(crate) fn emit_unescape_error(
};
}
let sugg = format!("{prefix}\"{escaped}\"");
- MoreThanOneCharSugg::Quotes { span: span_with_quotes, is_byte, sugg }
+ MoreThanOneCharSugg::Quotes {
+ span: span_with_quotes,
+ is_byte: mode == Mode::Byte,
+ sugg,
+ }
});
handler.emit_err(UnescapeError::MoreThanOneChar {
span: span_with_quotes,
@@ -112,7 +115,7 @@ pub(crate) fn emit_unescape_error(
char_span,
escaped_sugg: c.escape_default().to_string(),
escaped_msg: escaped_char(c),
- byte: mode.is_byte(),
+ byte: mode == Mode::Byte,
});
}
EscapeError::BareCarriageReturn => {
@@ -126,12 +129,15 @@ pub(crate) fn emit_unescape_error(
EscapeError::InvalidEscape => {
let (c, span) = last_char();
- let label =
- if mode.is_byte() { "unknown byte escape" } else { "unknown character escape" };
+ let label = if mode == Mode::Byte || mode == Mode::ByteStr {
+ "unknown byte escape"
+ } else {
+ "unknown character escape"
+ };
let ec = escaped_char(c);
- let mut diag = handler.struct_span_err(span, &format!("{}: `{}`", label, ec));
+ let mut diag = handler.struct_span_err(span, format!("{}: `{}`", label, ec));
diag.span_label(span, label);
- if c == '{' || c == '}' && !mode.is_byte() {
+ if c == '{' || c == '}' && matches!(mode, Mode::Str | Mode::RawStr) {
diag.help(
"if used in a formatting string, curly braces are escaped with `{{` and `}}`",
);
@@ -141,7 +147,7 @@ pub(crate) fn emit_unescape_error(
version control settings",
);
} else {
- if !mode.is_byte() {
+ if mode == Mode::Str || mode == Mode::Char {
diag.span_suggestion(
span_with_quotes,
"if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal",
@@ -180,13 +186,13 @@ pub(crate) fn emit_unescape_error(
} else {
String::new()
};
- err.span_label(span, &format!("must be ASCII{}", postfix));
+ err.span_label(span, format!("must be ASCII{}", postfix));
// Note: the \\xHH suggestions are not given for raw byte string
// literals, because they are araw and so cannot use any escapes.
if (c as u32) <= 0xFF && mode != Mode::RawByteStr {
err.span_suggestion(
span,
- &format!(
+ format!(
"if you meant to use the unicode code point for {:?}, use a \\xHH escape",
c
),
@@ -200,10 +206,7 @@ pub(crate) fn emit_unescape_error(
utf8.push(c);
err.span_suggestion(
span,
- &format!(
- "if you meant to use the UTF-8 encoding of {:?}, use \\xHH escapes",
- c
- ),
+ format!("if you meant to use the UTF-8 encoding of {:?}, use \\xHH escapes", c),
utf8.as_bytes()
.iter()
.map(|b: &u8| format!("\\x{:X}", *b))
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index 1f027c08f..829d9693e 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -350,7 +350,7 @@ pub(super) fn check_for_substitution(
let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else {
let msg = format!("substitution character not found for '{}'", ch);
- reader.sess.span_diagnostic.span_bug_no_panic(span, &msg);
+ reader.sess.span_diagnostic.span_bug_no_panic(span, msg);
return (None, None);
};
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 17466cd0e..25de78085 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -18,9 +18,9 @@ use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AttrItem, Attribute, MetaItem};
use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult};
+use rustc_errors::{Diagnostic, FatalError, Level, PResult};
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
use rustc_session::parse::ParseSess;
use rustc_span::{FileName, SourceFile, Span};
@@ -153,7 +153,7 @@ fn try_file_to_source_file(
) -> Result<Lrc<SourceFile>, Diagnostic> {
sess.source_map().load_file(path).map_err(|e| {
let msg = format!("couldn't read {}: {}", path.display(), e);
- let mut diag = Diagnostic::new(Level::Fatal, &msg);
+ let mut diag = Diagnostic::new(Level::Fatal, msg);
if let Some(sp) = spanopt {
diag.set_span(sp);
}
@@ -190,7 +190,7 @@ pub fn maybe_file_to_stream(
override_span: Option<Span>,
) -> Result<TokenStream, Vec<Diagnostic>> {
let src = source_file.src.as_ref().unwrap_or_else(|| {
- sess.span_diagnostic.bug(&format!(
+ sess.span_diagnostic.bug(format!(
"cannot lex `source_file` without source: {}",
sess.source_map().filename_for_diagnostics(&source_file.name)
));
@@ -243,12 +243,11 @@ pub fn parse_cfg_attr(
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
if !tokens.is_empty() =>
{
- let msg = "wrong `cfg_attr` delimiters";
- crate::validate_attr::check_meta_bad_delim(parse_sess, dspan, delim, msg);
+ crate::validate_attr::check_cfg_attr_bad_delim(parse_sess, dspan, delim);
match parse_in(parse_sess, tokens.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
Ok(r) => return Some(r),
Err(mut e) => {
- e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
+ e.help(format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
.note(CFG_ATTR_NOTE_REF)
.emit();
}
@@ -265,15 +264,5 @@ const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
#the-cfg_attr-attribute>";
fn error_malformed_cfg_attr_missing(span: Span, parse_sess: &ParseSess) {
- parse_sess
- .span_diagnostic
- .struct_span_err(span, "malformed `cfg_attr` attribute input")
- .span_suggestion(
- span,
- "missing condition and attribute",
- CFG_ATTR_GRAMMAR_HELP,
- Applicability::HasPlaceholders,
- )
- .note(CFG_ATTR_NOTE_REF)
- .emit();
+ parse_sess.emit_err(errors::MalformedCfgAttr { span, sugg: CFG_ATTR_GRAMMAR_HELP });
}
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index e3e7c63e3..e1db19557 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -45,10 +45,10 @@ impl<'a> Parser<'a> {
Some(InnerAttrForbiddenReason::AfterOuterDocComment {
prev_doc_comment_span: prev_outer_attr_sp.unwrap(),
})
- } else if let Some(prev_outer_attr_sp) = prev_outer_attr_sp {
- Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp })
} else {
- None
+ prev_outer_attr_sp.map(|prev_outer_attr_sp| {
+ InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }
+ })
};
let inner_parse_policy = InnerAttrPolicy::Forbidden(inner_error_reason);
just_parsed_doc_comment = false;
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index b0ab0f106..1e6ac5496 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -72,7 +72,7 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool {
// Therefore, the absence of a literal `cfg` or `cfg_attr` guarantees that
// we don't need to do any eager expansion.
attrs.iter().any(|attr| {
- attr.ident().map_or(false, |ident| ident.name == sym::cfg || ident.name == sym::cfg_attr)
+ attr.ident().is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr)
})
}
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index e03ce5d71..c14540396 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -4,7 +4,7 @@ use super::{
TokenExpectType, TokenType,
};
use crate::errors::{
- AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub,
+ AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi,
ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything,
DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
@@ -13,7 +13,7 @@ use crate::errors::{
IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg,
PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst,
StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens,
- StructLiteralNeedingParensSugg, SuggEscapeIdentifier, SuggRemoveComma,
+ StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma,
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead,
};
@@ -32,8 +32,8 @@ use rustc_ast::{
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{
- pluralize, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed,
- FatalError, Handler, IntoDiagnostic, MultiSpan, PResult,
+ pluralize, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage,
+ ErrorGuaranteed, FatalError, Handler, IntoDiagnostic, MultiSpan, PResult,
};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::Spanned;
@@ -84,6 +84,7 @@ impl RecoverQPath for Ty {
}
impl RecoverQPath for Pat {
+ const PATH_STYLE: PathStyle = PathStyle::Pat;
fn to_ty(&self) -> Option<P<Ty>> {
self.to_ty()
}
@@ -206,11 +207,11 @@ struct MultiSugg {
impl MultiSugg {
fn emit(self, err: &mut Diagnostic) {
- err.multipart_suggestion(&self.msg, self.patches, self.applicability);
+ err.multipart_suggestion(self.msg, self.patches, self.applicability);
}
fn emit_verbose(self, err: &mut Diagnostic) {
- err.multipart_suggestion_verbose(&self.msg, self.patches, self.applicability);
+ err.multipart_suggestion_verbose(self.msg, self.patches, self.applicability);
}
}
@@ -237,6 +238,7 @@ impl<'a> DerefMut for SnapshotParser<'a> {
impl<'a> Parser<'a> {
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -570,15 +572,13 @@ impl<'a> Parser<'a> {
let expect = tokens_to_string(&expected);
let actual = super::token_descr(&self.token);
let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
+ let fmt = format!("expected one of {expect}, found {actual}");
let short_expect = if expected.len() > 6 {
format!("{} possible tokens", expected.len())
} else {
- expect.clone()
+ expect
};
- (
- format!("expected one of {expect}, found {actual}"),
- (self.prev_token.span.shrink_to_hi(), format!("expected one of {short_expect}")),
- )
+ (fmt, (self.prev_token.span.shrink_to_hi(), format!("expected one of {short_expect}")))
} else if expected.is_empty() {
(
format!("unexpected token: {actual}"),
@@ -592,13 +592,13 @@ impl<'a> Parser<'a> {
};
self.last_unexpected_token_span = Some(self.token.span);
// FIXME: translation requires list formatting (for `expect`)
- let mut err = self.struct_span_err(self.token.span, &msg_exp);
+ let mut err = self.struct_span_err(self.token.span, msg_exp);
if let TokenKind::Ident(symbol, _) = &self.prev_token.kind {
if ["def", "fun", "func", "function"].contains(&symbol.as_str()) {
err.span_suggestion_short(
self.prev_token.span,
- &format!("write `fn` instead of `{symbol}` to declare a function"),
+ format!("write `fn` instead of `{symbol}` to declare a function"),
"fn",
Applicability::MachineApplicable,
);
@@ -665,7 +665,6 @@ impl<'a> Parser<'a> {
err.span_label(sp, label_exp);
err.span_label(self.token.span, "unexpected token");
}
- self.maybe_annotate_with_ascription(&mut err, false);
Err(err)
}
@@ -697,13 +696,13 @@ impl<'a> Parser<'a> {
err.set_span(span);
err.span_suggestion(
span,
- &format!("remove the extra `#`{}", pluralize!(count)),
+ format!("remove the extra `#`{}", pluralize!(count)),
"",
Applicability::MachineApplicable,
);
err.span_label(
str_span,
- &format!("this raw string started with {n_hashes} `#`{}", pluralize!(n_hashes)),
+ format!("this raw string started with {n_hashes} `#`{}", pluralize!(n_hashes)),
);
true
}
@@ -790,59 +789,6 @@ impl<'a> Parser<'a> {
None
}
- pub fn maybe_annotate_with_ascription(
- &mut self,
- err: &mut Diagnostic,
- maybe_expected_semicolon: bool,
- ) {
- if let Some((sp, likely_path)) = self.last_type_ascription.take() {
- let sm = self.sess.source_map();
- let next_pos = sm.lookup_char_pos(self.token.span.lo());
- let op_pos = sm.lookup_char_pos(sp.hi());
-
- let allow_unstable = self.sess.unstable_features.is_nightly_build();
-
- if likely_path {
- err.span_suggestion(
- sp,
- "maybe write a path separator here",
- "::",
- if allow_unstable {
- Applicability::MaybeIncorrect
- } else {
- Applicability::MachineApplicable
- },
- );
- self.sess.type_ascription_path_suggestions.borrow_mut().insert(sp);
- } else if op_pos.line != next_pos.line && maybe_expected_semicolon {
- err.span_suggestion(
- sp,
- "try using a semicolon",
- ";",
- Applicability::MaybeIncorrect,
- );
- } else if allow_unstable {
- err.span_label(sp, "tried to parse a type due to this type ascription");
- } else {
- err.span_label(sp, "tried to parse a type due to this");
- }
- if allow_unstable {
- // Give extra information about type ascription only if it's a nightly compiler.
- err.note(
- "`#![feature(type_ascription)]` lets you annotate an expression with a type: \
- `<expr>: <type>`",
- );
- if !likely_path {
- // Avoid giving too much info when it was likely an unrelated typo.
- err.note(
- "see issue #23416 <https://github.com/rust-lang/rust/issues/23416> \
- for more information",
- );
- }
- }
- }
- }
-
/// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
/// passes through any errors encountered. Used for error recovery.
pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) {
@@ -899,7 +845,7 @@ impl<'a> Parser<'a> {
//
// `x.foo::<u32>>>(3)`
let parsed_angle_bracket_args =
- segment.args.as_ref().map_or(false, |args| args.is_angle_bracketed());
+ segment.args.as_ref().is_some_and(|args| args.is_angle_bracketed());
debug!(
"check_trailing_angle_brackets: parsed_angle_bracket_args={:?}",
@@ -1061,6 +1007,31 @@ impl<'a> Parser<'a> {
Err(e)
}
+ /// Suggest add the missing `let` before the identifier in stmt
+ /// `a: Ty = 1` -> `let a: Ty = 1`
+ pub(super) fn suggest_add_missing_let_for_stmt(
+ &mut self,
+ err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>,
+ ) {
+ if self.token == token::Colon {
+ let prev_span = self.prev_token.span.shrink_to_lo();
+ let snapshot = self.create_snapshot_for_diagnostic();
+ self.bump();
+ match self.parse_ty() {
+ Ok(_) => {
+ if self.token == token::Eq {
+ let sugg = SuggAddMissingLetStmt { span: prev_span };
+ sugg.add_to_diagnostic(err);
+ }
+ }
+ Err(e) => {
+ e.cancel();
+ }
+ }
+ self.restore_snapshot(snapshot);
+ }
+ }
+
/// Check to see if a pair of chained operators looks like an attempt at chained comparison,
/// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
/// parenthesising the leftmost comparison.
@@ -1339,7 +1310,7 @@ impl<'a> Parser<'a> {
}
self.bump(); // `+`
- let bounds = self.parse_generic_bounds(None)?;
+ let bounds = self.parse_generic_bounds()?;
let sum_span = ty.span.to(self.prev_token.span);
let sub = match &ty.kind {
@@ -1415,12 +1386,12 @@ impl<'a> Parser<'a> {
) -> PResult<'a, P<Expr>> {
let mut err = self.struct_span_err(
op_span,
- &format!("Rust has no {} {} operator", kind.fixity, kind.op.name()),
+ format!("Rust has no {} {} operator", kind.fixity, kind.op.name()),
);
- err.span_label(op_span, &format!("not a valid {} operator", kind.fixity));
+ err.span_label(op_span, format!("not a valid {} operator", kind.fixity));
let help_base_case = |mut err: DiagnosticBuilder<'_, _>, base| {
- err.help(&format!("use `{}= 1` instead", kind.op.chr()));
+ err.help(format!("use `{}= 1` instead", kind.op.chr()));
err.emit();
Ok(base)
};
@@ -1609,7 +1580,7 @@ impl<'a> Parser<'a> {
_ => this_token_str,
},
);
- let mut err = self.struct_span_err(sp, &msg);
+ let mut err = self.struct_span_err(sp, msg);
let label_exp = format!("expected `{token_str}`");
let sm = self.sess.source_map();
if !sm.is_multiline(prev_sp.until(sp)) {
@@ -1624,12 +1595,36 @@ impl<'a> Parser<'a> {
}
pub(super) fn expect_semi(&mut self) -> PResult<'a, ()> {
- if self.eat(&token::Semi) {
+ if self.eat(&token::Semi) || self.recover_colon_as_semi() {
return Ok(());
}
self.expect(&token::Semi).map(drop) // Error unconditionally
}
+ pub(super) fn recover_colon_as_semi(&mut self) -> bool {
+ let line_idx = |span: Span| {
+ self.sess
+ .source_map()
+ .span_to_lines(span)
+ .ok()
+ .and_then(|lines| Some(lines.lines.get(0)?.line_index))
+ };
+
+ if self.may_recover()
+ && self.token == token::Colon
+ && self.look_ahead(1, |next| line_idx(self.token.span) < line_idx(next.span))
+ {
+ self.sess.emit_err(ColonAsSemi {
+ span: self.token.span,
+ type_ascription: self.sess.unstable_features.is_nightly_build().then_some(()),
+ });
+ self.bump();
+ return true;
+ }
+
+ false
+ }
+
/// Consumes alternative await syntaxes like `await!(<expr>)`, `await <expr>`,
/// `await? <expr>`, `await(<expr>)`, and `await { <expr> }`.
pub(super) fn recover_incorrect_await_syntax(
@@ -1648,7 +1643,7 @@ impl<'a> Parser<'a> {
// Avoid knock-down errors as we don't know whether to interpret this as `foo().await?`
// or `foo()?.await` (the very reason we went with postfix syntax 😅).
ExprKind::Try(_) => ExprKind::Err,
- _ => ExprKind::Await(expr),
+ _ => ExprKind::Await(expr, await_sp),
};
let expr = self.mk_expr(lo.to(sp), kind);
self.maybe_recover_from_bad_qpath(expr)
@@ -1736,7 +1731,7 @@ impl<'a> Parser<'a> {
Applicability::MachineApplicable,
);
}
- err.span_suggestion(lo.shrink_to_lo(), &format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable);
+ err.span_suggestion(lo.shrink_to_lo(), format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable);
err.emit();
Ok(self.mk_expr_err(lo.to(hi)))
} else {
@@ -1792,24 +1787,6 @@ impl<'a> Parser<'a> {
}
}
- pub(super) fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
- (self.token == token::Lt && // `foo:<bar`, likely a typoed turbofish.
- self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()))
- || self.token.is_ident() &&
- matches!(node, ast::ExprKind::Path(..) | ast::ExprKind::Field(..)) &&
- !self.token.is_reserved_ident() && // v `foo:bar(baz)`
- self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Parenthesis))
- || self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace)) // `foo:bar {`
- || self.look_ahead(1, |t| t == &token::Colon) && // `foo:bar::<baz`
- self.look_ahead(2, |t| t == &token::Lt) &&
- self.look_ahead(3, |t| t.is_ident())
- || self.look_ahead(1, |t| t == &token::Colon) && // `foo:bar:baz`
- self.look_ahead(2, |t| t.is_ident())
- || self.look_ahead(1, |t| t == &token::ModSep)
- && (self.look_ahead(2, |t| t.is_ident()) || // `foo:bar::baz`
- self.look_ahead(2, |t| t == &token::Lt)) // `foo:bar::<baz>`
- }
-
pub(super) fn recover_seq_parse_error(
&mut self,
delim: Delimiter,
@@ -1904,7 +1881,6 @@ impl<'a> Parser<'a> {
&& brace_depth == 0
&& bracket_depth == 0 =>
{
- debug!("recover_stmt_ return - Semi");
break;
}
_ => self.bump(),
@@ -2110,7 +2086,7 @@ impl<'a> Parser<'a> {
format!("expected expression, found {}", super::token_descr(&self.token),),
),
};
- let mut err = self.struct_span_err(span, &msg);
+ let mut err = self.struct_span_err(span, msg);
let sp = self.sess.source_map().start_point(self.token.span);
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
@@ -2181,7 +2157,7 @@ impl<'a> Parser<'a> {
// arguments after a comma.
let mut err = self.struct_span_err(
self.token.span,
- &format!("expected one of `,` or `>`, found {}", super::token_descr(&self.token)),
+ format!("expected one of `,` or `>`, found {}", super::token_descr(&self.token)),
);
err.span_label(self.token.span, "expected one of `,` or `>`");
match self.recover_const_arg(arg.span(), err) {
@@ -2608,7 +2584,7 @@ impl<'a> Parser<'a> {
let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
err.multipart_suggestion(
- &format!(
+ format!(
"try adding parentheses to match on a tuple{}",
if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
),
@@ -2634,7 +2610,7 @@ impl<'a> Parser<'a> {
let TyKind::Path(qself, path) = &ty.kind else { return Ok(()) };
let qself_position = qself.as_ref().map(|qself| qself.position);
for (i, segments) in path.segments.windows(2).enumerate() {
- if qself_position.map(|pos| i < pos).unwrap_or(false) {
+ if qself_position.is_some_and(|pos| i < pos) {
continue;
}
if let [a, b] = segments {
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 03c82fbd3..1b28f3c97 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -174,10 +174,8 @@ impl<'a> Parser<'a> {
self.parse_expr_prefix(attrs)?
}
};
- let last_type_ascription_set = self.last_type_ascription.is_some();
if !self.should_continue_as_assoc_expr(&lhs) {
- self.last_type_ascription = None;
return Ok(lhs);
}
@@ -301,9 +299,6 @@ impl<'a> Parser<'a> {
if op == AssocOp::As {
lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?;
continue;
- } else if op == AssocOp::Colon {
- lhs = self.parse_assoc_op_ascribe(lhs, lhs_span)?;
- continue;
} else if op == AssocOp::DotDot || op == AssocOp::DotDotEq {
// If we didn't have to handle `x..`/`x..=`, it would be pretty easy to
// generalise it to the Fixity::None code.
@@ -364,7 +359,7 @@ impl<'a> Parser<'a> {
let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs);
self.mk_expr(span, aopexpr)
}
- AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotEq => {
+ AssocOp::As | AssocOp::DotDot | AssocOp::DotDotEq => {
self.span_bug(span, "AssocOp should have been handled by special case")
}
};
@@ -373,9 +368,7 @@ impl<'a> Parser<'a> {
break;
}
}
- if last_type_ascription_set {
- self.last_type_ascription = None;
- }
+
Ok(lhs)
}
@@ -743,7 +736,7 @@ impl<'a> Parser<'a> {
(
// `foo: `
ExprKind::Path(None, ast::Path { segments, .. }),
- TokenKind::Ident(kw::For | kw::Loop | kw::While, false),
+ token::Ident(kw::For | kw::Loop | kw::While, false),
) if segments.len() == 1 => {
let snapshot = self.create_snapshot_for_diagnostic();
let label = Label {
@@ -838,33 +831,31 @@ impl<'a> Parser<'a> {
&mut self,
cast_expr: P<Expr>,
) -> PResult<'a, P<Expr>> {
+ if let ExprKind::Type(_, _) = cast_expr.kind {
+ panic!("ExprKind::Type must not be parsed");
+ }
+
let span = cast_expr.span;
- let (cast_kind, maybe_ascription_span) =
- if let ExprKind::Type(ascripted_expr, _) = &cast_expr.kind {
- ("type ascription", Some(ascripted_expr.span.shrink_to_hi().with_hi(span.hi())))
- } else {
- ("cast", None)
- };
let with_postfix = self.parse_expr_dot_or_call_with_(cast_expr, span)?;
// Check if an illegal postfix operator has been added after the cast.
// If the resulting expression is not a cast, it is an illegal postfix operator.
- if !matches!(with_postfix.kind, ExprKind::Cast(_, _) | ExprKind::Type(_, _)) {
+ if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) {
let msg = format!(
- "{cast_kind} cannot be followed by {}",
+ "cast cannot be followed by {}",
match with_postfix.kind {
ExprKind::Index(_, _) => "indexing",
ExprKind::Try(_) => "`?`",
ExprKind::Field(_, _) => "a field access",
ExprKind::MethodCall(_) => "a method call",
ExprKind::Call(_, _) => "a function call",
- ExprKind::Await(_) => "`.await`",
+ ExprKind::Await(_, _) => "`.await`",
ExprKind::Err => return Ok(with_postfix),
_ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
}
);
- let mut err = self.struct_span_err(span, &msg);
+ let mut err = self.struct_span_err(span, msg);
let suggest_parens = |err: &mut Diagnostic| {
let suggestions = vec![
@@ -878,44 +869,13 @@ impl<'a> Parser<'a> {
);
};
- // If type ascription is "likely an error", the user will already be getting a useful
- // help message, and doesn't need a second.
- if self.last_type_ascription.map_or(false, |last_ascription| last_ascription.1) {
- self.maybe_annotate_with_ascription(&mut err, false);
- } else if let Some(ascription_span) = maybe_ascription_span {
- let is_nightly = self.sess.unstable_features.is_nightly_build();
- if is_nightly {
- suggest_parens(&mut err);
- }
- err.span_suggestion(
- ascription_span,
- &format!(
- "{}remove the type ascription",
- if is_nightly { "alternatively, " } else { "" }
- ),
- "",
- if is_nightly {
- Applicability::MaybeIncorrect
- } else {
- Applicability::MachineApplicable
- },
- );
- } else {
- suggest_parens(&mut err);
- }
+ suggest_parens(&mut err);
+
err.emit();
};
Ok(with_postfix)
}
- fn parse_assoc_op_ascribe(&mut self, lhs: P<Expr>, lhs_span: Span) -> PResult<'a, P<Expr>> {
- let maybe_path = self.could_ascription_be_path(&lhs.kind);
- self.last_type_ascription = Some((self.prev_token.span, maybe_path));
- let lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type)?;
- self.sess.gated_spans.gate(sym::type_ascription, lhs.span);
- Ok(lhs)
- }
-
/// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.
fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
self.expect_and()?;
@@ -1010,7 +970,7 @@ impl<'a> Parser<'a> {
};
if has_dot {
// expr.f
- e = self.parse_expr_dot_suffix(lo, e)?;
+ e = self.parse_dot_suffix_expr(lo, e)?;
continue;
}
if self.expr_is_complete(&e) {
@@ -1024,13 +984,7 @@ impl<'a> Parser<'a> {
}
}
- fn look_ahead_type_ascription_as_field(&mut self) -> bool {
- self.look_ahead(1, |t| t.is_ident())
- && self.look_ahead(2, |t| t == &token::Colon)
- && self.look_ahead(3, |t| t.can_begin_expr())
- }
-
- fn parse_expr_dot_suffix(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
+ fn parse_dot_suffix_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
match self.token.uninterpolate().kind {
token::Ident(..) => self.parse_dot_suffix(base, lo),
token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {
@@ -1183,9 +1137,7 @@ impl<'a> Parser<'a> {
/// Parse a function call expression, `expr(...)`.
fn parse_expr_fn_call(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> {
- let snapshot = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis)
- && self.look_ahead_type_ascription_as_field()
- {
+ let snapshot = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))
} else {
None
@@ -1216,7 +1168,6 @@ impl<'a> Parser<'a> {
if !self.may_recover() {
return None;
}
-
match (seq.as_mut(), snapshot) {
(Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
snapshot.bump(); // `(`
@@ -1229,11 +1180,15 @@ impl<'a> Parser<'a> {
self.restore_snapshot(snapshot);
let close_paren = self.prev_token.span;
let span = lo.to(close_paren);
+ // filter shorthand fields
+ let fields: Vec<_> =
+ fields.into_iter().filter(|field| !field.is_shorthand).collect();
+
if !fields.is_empty() &&
// `token.kind` should not be compared here.
// This is because the `snapshot.token.kind` is treated as the same as
// that of the open delim in `TokenTreesReader::parse_token_tree`, even if they are different.
- self.span_to_snippet(close_paren).map_or(false, |snippet| snippet == ")")
+ self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")")
{
let mut replacement_err = errors::ParenthesesWithStructFields {
span,
@@ -1260,9 +1215,7 @@ impl<'a> Parser<'a> {
return Some(self.mk_expr_err(span));
}
Ok(_) => {}
- Err(mut err) => {
- err.emit();
- }
+ Err(err) => err.cancel(),
}
}
_ => {}
@@ -1351,6 +1304,8 @@ impl<'a> Parser<'a> {
})
} else if self.check(&token::OpenDelim(Delimiter::Bracket)) {
self.parse_expr_array_or_repeat(Delimiter::Bracket)
+ } else if self.is_builtin() {
+ self.parse_expr_builtin()
} else if self.check_path() {
self.parse_expr_path_start()
} else if self.check_keyword(kw::Move)
@@ -1499,8 +1454,19 @@ impl<'a> Parser<'a> {
}
fn parse_expr_path_start(&mut self) -> PResult<'a, P<Expr>> {
+ let maybe_eq_tok = self.prev_token.clone();
let (qself, path) = if self.eat_lt() {
- let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+ let lt_span = self.prev_token.span;
+ let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {
+ // Suggests using '<=' if there is an error parsing qpath when the previous token
+ // is an '=' token. Only emits suggestion if the '<' token and '=' token are
+ // directly adjacent (i.e. '=<')
+ if maybe_eq_tok.kind == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
+ let eq_lt = maybe_eq_tok.span.to(lt_span);
+ err.span_suggestion(eq_lt, "did you mean", "<=", Applicability::Unspecified);
+ }
+ err
+ })?;
(Some(qself), path)
} else {
(None, self.parse_path(PathStyle::Expr)?)
@@ -1516,7 +1482,6 @@ impl<'a> Parser<'a> {
let mac = P(MacCall {
path,
args: self.parse_delim_args()?,
- prior_type_ascription: self.last_type_ascription,
});
(lo.to(self.prev_token.span), ExprKind::MacCall(mac))
} else if self.check(&token::OpenDelim(Delimiter::Brace))
@@ -1535,7 +1500,7 @@ impl<'a> Parser<'a> {
}
/// Parse `'label: $expr`. The label is already parsed.
- fn parse_expr_labeled(
+ pub(super) fn parse_expr_labeled(
&mut self,
label_: Label,
mut consume_colon: bool,
@@ -1807,6 +1772,61 @@ impl<'a> Parser<'a> {
self.maybe_recover_from_bad_qpath(expr)
}
+ /// Parse `builtin # ident(args,*)`.
+ fn parse_expr_builtin(&mut self) -> PResult<'a, P<Expr>> {
+ self.parse_builtin(|this, lo, ident| {
+ if ident.name == sym::offset_of {
+ return Ok(Some(this.parse_expr_offset_of(lo)?));
+ }
+
+ Ok(None)
+ })
+ }
+
+ pub(crate) fn parse_builtin<T>(
+ &mut self,
+ parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option<T>>,
+ ) -> PResult<'a, T> {
+ let lo = self.token.span;
+
+ self.bump(); // `builtin`
+ self.bump(); // `#`
+
+ let Some((ident, false)) = self.token.ident() else {
+ let err = errors::ExpectedBuiltinIdent { span: self.token.span }
+ .into_diagnostic(&self.sess.span_diagnostic);
+ return Err(err);
+ };
+ self.sess.gated_spans.gate(sym::builtin_syntax, ident.span);
+ self.bump();
+
+ self.expect(&TokenKind::OpenDelim(Delimiter::Parenthesis))?;
+ let ret = if let Some(res) = parse(self, lo, ident)? {
+ Ok(res)
+ } else {
+ let err = errors::UnknownBuiltinConstruct { span: lo.to(ident.span), name: ident.name }
+ .into_diagnostic(&self.sess.span_diagnostic);
+ return Err(err);
+ };
+ self.expect(&TokenKind::CloseDelim(Delimiter::Parenthesis))?;
+
+ ret
+ }
+
+ pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
+ let container = self.parse_ty()?;
+ self.expect(&TokenKind::Comma)?;
+
+ let seq_sep = SeqSep { sep: Some(token::Dot), trailing_sep_allowed: false };
+ let (fields, _trailing, _recovered) = self.parse_seq_to_before_end(
+ &TokenKind::CloseDelim(Delimiter::Parenthesis),
+ seq_sep,
+ Parser::parse_field_name,
+ )?;
+ let span = lo.to(self.token.span);
+ Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.to_vec().into())))
+ }
+
/// Returns a string literal if the next token is a string literal.
/// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
/// and returns `None` if the next token is not literal at all.
@@ -1855,7 +1875,7 @@ impl<'a> Parser<'a> {
let token = self.token.clone();
let err = |self_: &Self| {
let msg = format!("unexpected token: {}", super::token_descr(&token));
- self_.struct_span_err(token.span, &msg)
+ self_.struct_span_err(token.span, msg)
};
// On an error path, eagerly consider a lifetime to be an unclosed character lit
if self.token.is_lifetime() {
@@ -1922,6 +1942,7 @@ impl<'a> Parser<'a> {
let recovered = self.recover_after_dot();
let token = recovered.as_ref().unwrap_or(&self.token);
let span = token.span;
+
token::Lit::from_token(token).map(|token_lit| {
self.bump();
(token_lit, span)
@@ -2057,7 +2078,7 @@ impl<'a> Parser<'a> {
// Therefore, `token.kind` should not be compared here.
if snapshot
.span_to_snippet(snapshot.token.span)
- .map_or(false, |snippet| snippet == "]") =>
+ .is_ok_and(|snippet| snippet == "]") =>
{
return Err(errors::MissingSemicolonBeforeArray {
open_delim: open_delim_span,
@@ -2752,7 +2773,7 @@ impl<'a> Parser<'a> {
// We might have a `=>` -> `=` or `->` typo (issue #89396).
if TokenKind::FatArrow
.similar_tokens()
- .map_or(false, |similar_tokens| similar_tokens.contains(&this.token.kind))
+ .is_some_and(|similar_tokens| similar_tokens.contains(&this.token.kind))
{
err.span_suggestion(
this.token.span,
@@ -2875,6 +2896,10 @@ impl<'a> Parser<'a> {
})
}
+ pub(crate) fn is_builtin(&self) -> bool {
+ self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
+ }
+
/// Parses a `try {...}` expression (`try` token already eaten).
fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
let (attrs, body) = self.parse_inner_attrs_and_block()?;
@@ -3013,6 +3038,11 @@ impl<'a> Parser<'a> {
} else {
e.span_label(pth.span, "while parsing this struct");
}
+
+ if !recover {
+ return Err(e);
+ }
+
e.emit();
// If the next token is a comma, then try to parse
@@ -3024,11 +3054,12 @@ impl<'a> Parser<'a> {
break;
}
}
+
None
}
};
- let is_shorthand = parsed_field.as_ref().map_or(false, |f| f.is_shorthand);
+ let is_shorthand = parsed_field.as_ref().is_some_and(|f| f.is_shorthand);
// A shorthand field can be turned into a full field with `:`.
// We should point this out.
self.check_or_expected(!is_shorthand, TokenType::Token(token::Colon));
@@ -3151,14 +3182,10 @@ impl<'a> Parser<'a> {
let label = format!("'{}", ident.name);
let ident = Ident { name: Symbol::intern(&label), span: ident.span };
- self.struct_span_err(ident.span, "expected a label, found an identifier")
- .span_suggestion(
- ident.span,
- "labels start with a tick",
- label,
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::ExpectedLabelFoundIdent {
+ span: ident.span,
+ start: ident.span.shrink_to_lo(),
+ });
Label { ident }
}
@@ -3256,7 +3283,7 @@ impl<'a> Parser<'a> {
fn mk_await_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> {
let span = lo.to(self.prev_token.span);
- let await_expr = self.mk_expr(span, ExprKind::Await(self_arg));
+ let await_expr = self.mk_expr(span, ExprKind::Await(self_arg, self.prev_token.span));
self.recover_from_await_method_call();
await_expr
}
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index f8ef1307c..cd779b0b4 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -1,5 +1,5 @@
use crate::errors::{
- MultipleWhereClauses, UnexpectedDefaultValueForLifetimeInGenericParameters,
+ self, MultipleWhereClauses, UnexpectedDefaultValueForLifetimeInGenericParameters,
UnexpectedSelfInGenericParameters, WhereClauseBeforeTupleStructBody,
WhereClauseBeforeTupleStructBodySugg,
};
@@ -78,7 +78,7 @@ impl<'a> Parser<'a> {
}
self.restore_snapshot(snapshot);
}
- self.parse_generic_bounds(colon_span)?
+ self.parse_generic_bounds()?
} else {
Vec::new()
};
@@ -181,12 +181,9 @@ impl<'a> Parser<'a> {
let snapshot = this.create_snapshot_for_diagnostic();
match this.parse_ty_where_predicate() {
Ok(where_predicate) => {
- this.struct_span_err(
- where_predicate.span(),
- "bounds on associated types do not belong here",
- )
- .span_label(where_predicate.span(), "belongs in `where` clause")
- .emit();
+ this.sess.emit_err(errors::BadAssocTypeBounds {
+ span: where_predicate.span(),
+ });
// FIXME - try to continue parsing other generics?
return Ok((None, TrailingToken::None));
}
@@ -201,22 +198,11 @@ impl<'a> Parser<'a> {
// Check for trailing attributes and stop parsing.
if !attrs.is_empty() {
if !params.is_empty() {
- this.struct_span_err(
- attrs[0].span,
- "trailing attribute after generic parameter",
- )
- .span_label(attrs[0].span, "attributes must go before parameters")
- .emit();
+ this.sess
+ .emit_err(errors::AttrAfterGeneric { span: attrs[0].span });
} else {
- this.struct_span_err(
- attrs[0].span,
- "attribute without generic parameters",
- )
- .span_label(
- attrs[0].span,
- "attributes are only permitted when preceding parameters",
- )
- .emit();
+ this.sess
+ .emit_err(errors::AttrWithoutGenerics { span: attrs[0].span });
}
}
return Ok((None, TrailingToken::None));
@@ -304,12 +290,7 @@ impl<'a> Parser<'a> {
// change we parse those generics now, but report an error.
if self.choose_generics_over_qpath(0) {
let generics = self.parse_generics()?;
- self.struct_span_err(
- generics.span,
- "generic parameters on `where` clauses are reserved for future use",
- )
- .span_label(generics.span, "currently unsupported")
- .emit();
+ self.sess.emit_err(errors::WhereOnGenerics { span: generics.span });
}
loop {
@@ -438,7 +419,7 @@ impl<'a> Parser<'a> {
// or with mandatory equality sign and the second type.
let ty = self.parse_ty_for_where_clause()?;
if self.eat(&token::Colon) {
- let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
+ let bounds = self.parse_generic_bounds()?;
Ok(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
span: lo.to(self.prev_token.span),
bound_generic_params: lifetime_defs,
@@ -472,6 +453,8 @@ impl<'a> Parser<'a> {
// `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
// `<` (LIFETIME|IDENT) `=` - generic parameter with a default
// `<` const - generic const parameter
+ // `<` IDENT `?` - RECOVERY for `impl<T ?Bound` missing a `:`, meant to
+ // avoid the `T?` to `Option<T>` recovery for types.
// The only truly ambiguous case is
// `<` IDENT `>` `::` IDENT ...
// we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
@@ -482,6 +465,9 @@ impl<'a> Parser<'a> {
|| self.look_ahead(start + 1, |t| t.is_lifetime() || t.is_ident())
&& self.look_ahead(start + 2, |t| {
matches!(t.kind, token::Gt | token::Comma | token::Colon | token::Eq)
+ // Recovery-only branch -- this could be removed,
+ // since it only affects diagnostics currently.
+ || matches!(t.kind, token::Question)
})
|| self.is_keyword_ahead(start + 1, &[kw::Const]))
}
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 6422b8ac1..3783ec41b 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -71,7 +71,7 @@ impl<'a> Parser<'a> {
if !self.eat(term) {
let token_str = super::token_descr(&self.token);
if !self.maybe_consume_incorrect_semicolon(&items) {
- let msg = &format!("expected item, found {token_str}");
+ let msg = format!("expected item, found {token_str}");
let mut err = self.struct_span_err(self.token.span, msg);
let label = if self.is_kw_followed_by_ident(kw::Let) {
"consider using `const` or `static` instead of `let` for global variables"
@@ -181,11 +181,11 @@ impl<'a> Parser<'a> {
/// Error in-case `default` was parsed in an in-appropriate context.
fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {
if let Defaultness::Default(span) = def {
- let msg = format!("{} {} cannot be `default`", kind.article(), kind.descr());
- self.struct_span_err(span, &msg)
- .span_label(span, "`default` because of this")
- .note("only associated `fn`, `const`, and `type` items can be `default`")
- .emit();
+ self.sess.emit_err(errors::InappropriateDefault {
+ span,
+ article: kind.article(),
+ descr: kind.descr(),
+ });
}
}
@@ -265,6 +265,9 @@ impl<'a> Parser<'a> {
// UNION ITEM
self.bump(); // `union`
self.parse_item_union()?
+ } else if self.is_builtin() {
+ // BUILTIN# ITEM
+ return self.parse_item_builtin();
} else if self.eat_keyword(kw::Macro) {
// MACROS 2.0 ITEM
self.parse_item_decl_macro(lo)?
@@ -310,14 +313,7 @@ impl<'a> Parser<'a> {
self.bump();
match self.parse_use_item() {
Ok(u) => {
- self.struct_span_err(span, format!("expected item, found {token_name}"))
- .span_suggestion_short(
- span,
- "items are imported using the `use` keyword",
- "use",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::RecoverImportAsUse { span, token_name });
Ok(Some(u))
}
Err(e) => {
@@ -441,6 +437,11 @@ impl<'a> Parser<'a> {
}
}
+ fn parse_item_builtin(&mut self) -> PResult<'a, Option<ItemInfo>> {
+ // To be expanded
+ return Ok(None);
+ }
+
/// Parses an item macro, e.g., `item!();`.
fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> {
let path = self.parse_path(PathStyle::Mod)?; // `foo::bar`
@@ -450,7 +451,7 @@ impl<'a> Parser<'a> {
Ok(args) => {
self.eat_semi_for_macro_if_needed(&args);
self.complain_if_pub_macro(vis, false);
- Ok(MacCall { path, args, prior_type_ascription: self.last_type_ascription })
+ Ok(MacCall { path, args })
}
Err(mut err) => {
@@ -602,10 +603,24 @@ impl<'a> Parser<'a> {
let path = match ty_first.kind {
// This notably includes paths passed through `ty` macro fragments (#46438).
TyKind::Path(None, path) => path,
- _ => {
- self.sess.emit_err(errors::ExpectedTraitInTraitImplFoundType {
- span: ty_first.span,
- });
+ other => {
+ if let TyKind::ImplTrait(_, bounds) = other
+ && let [bound] = bounds.as_slice()
+ {
+ // Suggest removing extra `impl` keyword:
+ // `impl<T: Default> impl Default for Wrapper<T>`
+ // ^^^^^
+ let extra_impl_kw = ty_first.span.until(bound.span());
+ self.sess
+ .emit_err(errors::ExtraImplKeywordInTraitImpl {
+ extra_impl_kw,
+ impl_trait_span: ty_first.span
+ });
+ } else {
+ self.sess.emit_err(errors::ExpectedTraitInTraitImplFoundType {
+ span: ty_first.span,
+ });
+ }
err_path(ty_first.span)
}
};
@@ -684,7 +699,7 @@ impl<'a> Parser<'a> {
// ```
&& self
.span_to_snippet(self.prev_token.span)
- .map_or(false, |snippet| snippet == "}")
+ .is_ok_and(|snippet| snippet == "}")
&& self.token.kind == token::Semi;
let mut semicolon_span = self.token.span;
if !is_unnecessary_semicolon {
@@ -795,11 +810,7 @@ impl<'a> Parser<'a> {
// Parse optional colon and supertrait bounds.
let had_colon = self.eat(&token::Colon);
let span_at_colon = self.prev_token.span;
- let bounds = if had_colon {
- self.parse_generic_bounds(Some(self.prev_token.span))?
- } else {
- Vec::new()
- };
+ let bounds = if had_colon { self.parse_generic_bounds()? } else { Vec::new() };
let span_before_eq = self.prev_token.span;
if self.eat(&token::Eq) {
@@ -809,7 +820,7 @@ impl<'a> Parser<'a> {
self.sess.emit_err(errors::BoundsNotAllowedOnTraitAliases { span });
}
- let bounds = self.parse_generic_bounds(None)?;
+ let bounds = self.parse_generic_bounds()?;
generics.where_clause = self.parse_where_clause()?;
self.expect_semi()?;
@@ -890,7 +901,7 @@ impl<'a> Parser<'a> {
// Parse optional colon and param bounds.
let bounds =
- if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() };
+ if self.eat(&token::Colon) { self.parse_generic_bounds()? } else { Vec::new() };
let before_where_clause = self.parse_where_clause()?;
let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
@@ -963,15 +974,8 @@ impl<'a> Parser<'a> {
} else {
// Recover from using a colon as path separator.
while self.eat_noexpect(&token::Colon) {
- self.struct_span_err(self.prev_token.span, "expected `::`, found `:`")
- .span_suggestion_short(
- self.prev_token.span,
- "use double colon",
- "::",
- Applicability::MachineApplicable,
- )
- .note_once("import paths are delimited using `::`")
- .emit();
+ self.sess
+ .emit_err(errors::SingleColonImportPath { span: self.prev_token.span });
// We parse the rest of the path and append it to the original prefix.
self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None)?;
@@ -1134,13 +1138,11 @@ impl<'a> Parser<'a> {
))
}
- fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &str) -> Option<T> {
+ fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &'static str) -> Option<T> {
// FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`)
let span = self.sess.source_map().guess_head_span(span);
let descr = kind.descr();
- self.struct_span_err(span, &format!("{descr} is not supported in {ctx}"))
- .help(&format!("consider moving the {descr} out to a nearby module scope"))
- .emit();
+ self.sess.emit_err(errors::BadItemKind { span, descr, ctx });
None
}
@@ -1282,6 +1284,7 @@ impl<'a> Parser<'a> {
}
}
+ let prev_span = self.prev_token.span;
let id = self.parse_ident()?;
let mut generics = self.parse_generics()?;
generics.where_clause = self.parse_where_clause()?;
@@ -1293,10 +1296,28 @@ impl<'a> Parser<'a> {
(thin_vec![], false)
} else {
self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant()).map_err(
- |mut e| {
- e.span_label(id.span, "while parsing this enum");
+ |mut err| {
+ err.span_label(id.span, "while parsing this enum");
+ if self.token == token::Colon {
+ let snapshot = self.create_snapshot_for_diagnostic();
+ self.bump();
+ match self.parse_ty() {
+ Ok(_) => {
+ err.span_suggestion_verbose(
+ prev_span,
+ "perhaps you meant to use `struct` here",
+ "struct".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ Err(e) => {
+ e.cancel();
+ }
+ }
+ self.restore_snapshot(snapshot);
+ }
self.recover_stmt();
- e
+ err
},
)?
};
@@ -1445,7 +1466,7 @@ impl<'a> Parser<'a> {
VariantData::Struct(fields, recovered)
} else {
let token_str = super::token_descr(&self.token);
- let msg = &format!("expected `where` or `{{` after union name, found {token_str}");
+ let msg = format!("expected `where` or `{{` after union name, found {token_str}");
let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, "expected `where` or `{` after union name");
return Err(err);
@@ -1481,7 +1502,7 @@ impl<'a> Parser<'a> {
self.eat(&token::CloseDelim(Delimiter::Brace));
} else {
let token_str = super::token_descr(&self.token);
- let msg = &format!(
+ let msg = format!(
"expected {}`{{` after struct name, found {}",
if parsed_where { "" } else { "`where`, or " },
token_str
@@ -1618,7 +1639,7 @@ impl<'a> Parser<'a> {
let sp = self.prev_token.span.shrink_to_hi();
let mut err = self.struct_span_err(
sp,
- &format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)),
+ format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)),
);
// Try to recover extra trailing angle brackets
@@ -1713,27 +1734,13 @@ impl<'a> Parser<'a> {
self.expect_field_ty_separator()?;
let ty = self.parse_ty()?;
if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
- self.struct_span_err(self.token.span, "found single colon in a struct field type path")
- .span_suggestion_verbose(
- self.token.span,
- "write a path separator here",
- "::",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(errors::SingleColonStructType { span: self.token.span });
}
if self.token.kind == token::Eq {
self.bump();
let const_expr = self.parse_expr_anon_const()?;
let sp = ty.span.shrink_to_hi().to(const_expr.value.span);
- self.struct_span_err(sp, "default values on `struct` fields aren't supported")
- .span_suggestion(
- sp,
- "remove this unsupported default value",
- "",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::EqualsStructDefault { span: sp });
}
Ok(FieldDef {
span: lo.to(self.prev_token.span),
@@ -1770,7 +1777,7 @@ impl<'a> Parser<'a> {
Ok(_) => {
let mut err = self.struct_span_err(
lo.to(self.prev_token.span),
- &format!("functions are not allowed in {adt_ty} definitions"),
+ format!("functions are not allowed in {adt_ty} definitions"),
);
err.help(
"unlike in C++, Java, and C#, functions are declared in `impl` blocks",
@@ -1789,7 +1796,7 @@ impl<'a> Parser<'a> {
Ok((ident, _)) => {
let mut err = self.struct_span_err(
lo.with_hi(ident.span.hi()),
- &format!("structs are not allowed in {adt_ty} definitions"),
+ format!("structs are not allowed in {adt_ty} definitions"),
);
err.help("consider creating a new `struct` definition instead of nesting");
err
@@ -1871,14 +1878,10 @@ impl<'a> Parser<'a> {
return IsMacroRulesItem::Yes { has_bang: true };
} else if self.look_ahead(1, |t| (t.is_ident())) {
// macro_rules foo
- self.struct_span_err(macro_rules_span, "expected `!` after `macro_rules`")
- .span_suggestion(
- macro_rules_span,
- "add a `!`",
- "macro_rules!",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::MacroRulesMissingBang {
+ span: macro_rules_span,
+ hi: macro_rules_span.shrink_to_hi(),
+ });
return IsMacroRulesItem::Yes { has_bang: false };
}
@@ -1903,9 +1906,7 @@ impl<'a> Parser<'a> {
if self.eat(&token::Not) {
// Handle macro_rules! foo!
let span = self.prev_token.span;
- self.struct_span_err(span, "macro names aren't followed by a `!`")
- .span_suggestion(span, "remove the `!`", "", Applicability::MachineApplicable)
- .emit();
+ self.sess.emit_err(errors::MacroNameRemoveBang { span });
}
let body = self.parse_delim_args()?;
@@ -1925,25 +1926,9 @@ impl<'a> Parser<'a> {
let vstr = pprust::vis_to_string(vis);
let vstr = vstr.trim_end();
if macro_rules {
- let msg = format!("can't qualify macro_rules invocation with `{vstr}`");
- self.struct_span_err(vis.span, &msg)
- .span_suggestion(
- vis.span,
- "try exporting the macro",
- "#[macro_export]",
- Applicability::MaybeIncorrect, // speculative
- )
- .emit();
+ self.sess.emit_err(errors::MacroRulesVisibility { span: vis.span, vis: vstr });
} else {
- self.struct_span_err(vis.span, "can't qualify macro invocation with `pub`")
- .span_suggestion(
- vis.span,
- "remove the visibility",
- "",
- Applicability::MachineApplicable,
- )
- .help(&format!("try adjusting the macro to put `{vstr}` inside the invocation"))
- .emit();
+ self.sess.emit_err(errors::MacroInvocationVisibility { span: vis.span, vis: vstr });
}
}
@@ -1989,18 +1974,12 @@ impl<'a> Parser<'a> {
let kw_token = self.token.clone();
let kw_str = pprust::token_to_string(&kw_token);
let item = self.parse_item(ForceCollect::No)?;
-
- self.struct_span_err(
- kw_token.span,
- &format!("`{kw_str}` definition cannot be nested inside `{keyword}`"),
- )
- .span_suggestion(
- item.unwrap().span,
- &format!("consider creating a new `{kw_str}` definition instead of nesting"),
- "",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(errors::NestedAdt {
+ span: kw_token.span,
+ item: item.unwrap().span,
+ kw_str,
+ keyword: keyword.as_str(),
+ });
// We successfully parsed the item but we must inform the caller about nested problem.
return Ok(false);
}
@@ -2139,13 +2118,10 @@ impl<'a> Parser<'a> {
let _ = self.parse_expr()?;
self.expect_semi()?; // `;`
let span = eq_sp.to(self.prev_token.span);
- self.struct_span_err(span, "function body cannot be `= expression;`")
- .multipart_suggestion(
- "surround the expression with `{` and `}` instead of `=` and `;`",
- vec![(eq_sp, "{".to_string()), (self.prev_token.span, " }".to_string())],
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::FunctionBodyEqualsExpr {
+ span,
+ sugg: errors::FunctionBodyEqualsExprSugg { eq: eq_sp, semi: self.prev_token.span },
+ });
(AttrVec::new(), Some(self.mk_block_err(span)))
} else {
let expected = if req_body {
@@ -2289,11 +2265,11 @@ impl<'a> Parser<'a> {
err.span_suggestion(
self.token.uninterpolated_span(),
- &format!("`{original_kw}` already used earlier, remove this one"),
+ format!("`{original_kw}` already used earlier, remove this one"),
"",
Applicability::MachineApplicable,
)
- .span_note(original_sp, &format!("`{original_kw}` first seen here"));
+ .span_note(original_sp, format!("`{original_kw}` first seen here"));
}
// The keyword has not been seen yet, suggest correct placement in the function front matter
else if let Some(WrongKw::Misplaced(correct_pos_sp)) = wrong_kw {
@@ -2304,7 +2280,7 @@ impl<'a> Parser<'a> {
err.span_suggestion(
correct_pos_sp.to(misplaced_qual_sp),
- &format!("`{misplaced_qual}` must come before `{current_qual}`"),
+ format!("`{misplaced_qual}` must come before `{current_qual}`"),
format!("{misplaced_qual} {current_qual}"),
Applicability::MachineApplicable,
).note("keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`");
@@ -2328,7 +2304,7 @@ impl<'a> Parser<'a> {
if matches!(orig_vis.kind, VisibilityKind::Inherited) {
err.span_suggestion(
sp_start.to(self.prev_token.span),
- &format!("visibility `{vs}` must come before `{snippet}`"),
+ format!("visibility `{vs}` must come before `{snippet}`"),
format!("{vs} {snippet}"),
Applicability::MachineApplicable,
);
@@ -2577,14 +2553,12 @@ impl<'a> Parser<'a> {
}
fn recover_self_param(&mut self) -> bool {
- match self
- .parse_outer_attributes()
- .and_then(|_| self.parse_self_param())
- .map_err(|e| e.cancel())
- {
- Ok(Some(_)) => true,
- _ => false,
- }
+ matches!(
+ self.parse_outer_attributes()
+ .and_then(|_| self.parse_self_param())
+ .map_err(|e| e.cancel()),
+ Ok(Some(_))
+ )
}
}
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index aa57b8047..c23420661 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -43,7 +43,7 @@ use thin_vec::ThinVec;
use tracing::debug;
use crate::errors::{
- IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral,
+ self, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral,
};
bitflags::bitflags! {
@@ -148,9 +148,6 @@ pub struct Parser<'a> {
max_angle_bracket_count: u32,
last_unexpected_token_span: Option<Span>,
- /// Span pointing at the `:` for the last type ascription the parser has seen, and whether it
- /// looked like it could have been a mistyped path or literal `Option:Some(42)`).
- pub last_type_ascription: Option<(Span, bool /* likely path typo */)>,
/// If present, this `Parser` is not parsing Rust code but rather a macro call.
subparser_name: Option<&'static str>,
capture_state: CaptureState,
@@ -165,7 +162,7 @@ pub struct Parser<'a> {
// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
// it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Parser<'_>, 288);
+rustc_data_structures::static_assert_size!(Parser<'_>, 272);
/// Stores span information about a closure.
#[derive(Clone)]
@@ -470,7 +467,6 @@ impl<'a> Parser<'a> {
unmatched_angle_bracket_count: 0,
max_angle_bracket_count: 0,
last_unexpected_token_span: None,
- last_type_ascription: None,
subparser_name,
capture_state: CaptureState {
capturing: Capturing::No,
@@ -540,7 +536,9 @@ impl<'a> Parser<'a> {
} else if inedible.contains(&self.token.kind) {
// leave it in the input
Ok(false)
- } else if self.last_unexpected_token_span == Some(self.token.span) {
+ } else if self.token.kind != token::Eof
+ && self.last_unexpected_token_span == Some(self.token.span)
+ {
FatalError.raise();
} else {
self.expected_one_of_not_found(edible, inedible)
@@ -663,15 +661,10 @@ impl<'a> Parser<'a> {
if case == Case::Insensitive
&& let Some((ident, /* is_raw */ false)) = self.token.ident()
&& ident.as_str().to_lowercase() == kw.as_str().to_lowercase() {
- self
- .struct_span_err(ident.span, format!("keyword `{kw}` is written in a wrong case"))
- .span_suggestion(
- ident.span,
- "write it in the correct case",
- kw,
- Applicability::MachineApplicable
- ).emit();
-
+ self.sess.emit_err(errors::KwBadCase {
+ span: ident.span,
+ kw: kw.as_str()
+ });
self.bump();
return true;
}
@@ -914,7 +907,7 @@ impl<'a> Parser<'a> {
expect_err
.span_suggestion_verbose(
self.prev_token.span.shrink_to_hi().until(self.token.span),
- &msg,
+ msg,
" @ ",
Applicability::MaybeIncorrect,
)
@@ -930,7 +923,7 @@ impl<'a> Parser<'a> {
expect_err
.span_suggestion_short(
sp,
- &format!("missing `{}`", token_str),
+ format!("missing `{}`", token_str),
token_str,
Applicability::MaybeIncorrect,
)
@@ -946,10 +939,14 @@ impl<'a> Parser<'a> {
// propagate the help message from sub error 'e' to main error 'expect_err;
expect_err.children.push(xx.clone());
}
- expect_err.emit();
-
e.cancel();
- break;
+ if self.token == token::Colon {
+ // we will try to recover in `maybe_recover_struct_lit_bad_delims`
+ return Err(expect_err);
+ } else {
+ expect_err.emit();
+ break;
+ }
}
}
}
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 7a4d53ed8..adb0d372a 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -20,12 +20,10 @@ impl<'a> Parser<'a> {
pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool {
/// Checks whether the non-terminal may contain a single (non-keyword) identifier.
fn may_be_ident(nt: &token::Nonterminal) -> bool {
- match *nt {
- token::NtItem(_) | token::NtBlock(_) | token::NtVis(_) | token::NtLifetime(_) => {
- false
- }
- _ => true,
- }
+ !matches!(
+ *nt,
+ token::NtItem(_) | token::NtBlock(_) | token::NtVis(_) | token::NtLifetime(_)
+ )
}
match kind {
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 2246002f5..c317d9636 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1,6 +1,6 @@
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
use crate::errors::{
- AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
+ self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
ExpectedCommaAfterPatternField, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow,
InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect,
@@ -406,11 +406,11 @@ impl<'a> Parser<'a> {
// Parse pattern starting with a path
let (qself, path) = if self.eat_lt() {
// Parse a qualified path
- let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+ let (qself, path) = self.parse_qpath(PathStyle::Pat)?;
(Some(qself), path)
} else {
// Parse an unqualified path
- (None, self.parse_path(PathStyle::Expr)?)
+ (None, self.parse_path(PathStyle::Pat)?)
};
let span = lo.to(self.prev_token.span);
@@ -444,7 +444,7 @@ impl<'a> Parser<'a> {
super::token_descr(&self_.token)
);
- let mut err = self_.struct_span_err(self_.token.span, &msg);
+ let mut err = self_.struct_span_err(self_.token.span, msg);
err.span_label(self_.token.span, format!("expected {}", expected));
err
});
@@ -666,7 +666,7 @@ impl<'a> Parser<'a> {
fn parse_pat_mac_invoc(&mut self, path: Path) -> PResult<'a, PatKind> {
self.bump();
let args = self.parse_delim_args()?;
- let mac = P(MacCall { path, args, prior_type_ascription: self.last_type_ascription });
+ let mac = P(MacCall { path, args });
Ok(PatKind::MacCall(mac))
}
@@ -680,7 +680,7 @@ impl<'a> Parser<'a> {
let expected = Expected::to_string_or_fallback(expected);
let msg = format!("expected {}, found {}", expected, super::token_descr(&self.token));
- let mut err = self.struct_span_err(self.token.span, &msg);
+ let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, format!("expected {}", expected));
let sp = self.sess.source_map().start_point(self.token.span);
@@ -789,11 +789,11 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
let (qself, path) = if self.eat_lt() {
// Parse a qualified path
- let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+ let (qself, path) = self.parse_qpath(PathStyle::Pat)?;
(Some(qself), path)
} else {
// Parse an unqualified path
- (None, self.parse_path(PathStyle::Expr)?)
+ (None, self.parse_path(PathStyle::Pat)?)
};
let hi = self.prev_token.span;
Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path)))
@@ -908,18 +908,13 @@ impl<'a> Parser<'a> {
let box_span = self.prev_token.span;
if self.isnt_pattern_start() {
- self.struct_span_err(
- self.token.span,
- format!("expected pattern, found {}", super::token_descr(&self.token)),
- )
- .span_note(box_span, "`box` is a reserved keyword")
- .span_suggestion_verbose(
- box_span.shrink_to_lo(),
- "escape `box` to use it as an identifier",
- "r#",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ let descr = super::token_descr(&self.token);
+ self.sess.emit_err(errors::BoxNotPat {
+ span: self.token.span,
+ kw: box_span,
+ lo: box_span.shrink_to_lo(),
+ descr,
+ });
// We cannot use `parse_pat_ident()` since it will complain `box`
// is not an identifier.
@@ -983,7 +978,7 @@ impl<'a> Parser<'a> {
break;
}
let token_str = super::token_descr(&self.token);
- let msg = &format!("expected `}}`, found {}", token_str);
+ let msg = format!("expected `}}`, found {}", token_str);
let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, "expected `}`");
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index c25c23d84..feb7e829c 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -1,5 +1,6 @@
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{Parser, Restrictions, TokenType};
+use crate::errors::PathSingleColon;
use crate::{errors, maybe_whole};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
@@ -8,7 +9,7 @@ use rustc_ast::{
AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
Path, PathSegment, QSelf,
};
-use rustc_errors::{pluralize, Applicability, PResult};
+use rustc_errors::{Applicability, IntoDiagnostic, PResult};
use rustc_span::source_map::{BytePos, Span};
use rustc_span::symbol::{kw, sym, Ident};
use std::mem;
@@ -24,7 +25,19 @@ pub enum PathStyle {
/// In all such contexts the non-path interpretation is preferred by default for practical
/// reasons, but the path interpretation can be forced by the disambiguator `::`, e.g.
/// `x<y>` - comparisons, `x::<y>` - unambiguously a path.
+ ///
+ /// Also, a path may never be followed by a `:`. This means that we can eagerly recover if
+ /// we encounter it.
Expr,
+ /// The same as `Expr`, but may be followed by a `:`.
+ /// For example, this code:
+ /// ```rust
+ /// struct S;
+ ///
+ /// let S: S;
+ /// // ^ Followed by a `:`
+ /// ```
+ Pat,
/// In other contexts, notably in types, no ambiguity exists and paths can be written
/// without the disambiguator, e.g., `x<y>` - unambiguously a path.
/// Paths with disambiguators are still accepted, `x::<Y>` - unambiguously a path too.
@@ -38,6 +51,12 @@ pub enum PathStyle {
Mod,
}
+impl PathStyle {
+ fn has_generic_ambiguity(&self) -> bool {
+ matches!(self, Self::Expr | Self::Pat)
+ }
+}
+
impl<'a> Parser<'a> {
/// Parses a qualified path.
/// Assumes that the leading `<` has been parsed already.
@@ -150,16 +169,13 @@ impl<'a> Parser<'a> {
//
if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
{
- parser
- .struct_span_err(
- path.segments
- .iter()
- .filter_map(|segment| segment.args.as_ref())
- .map(|arg| arg.span())
- .collect::<Vec<_>>(),
- "unexpected generic arguments in path",
- )
- .emit();
+ let span = path
+ .segments
+ .iter()
+ .filter_map(|segment| segment.args.as_ref())
+ .map(|arg| arg.span())
+ .collect::<Vec<_>>();
+ parser.sess.emit_err(errors::GenericsInPath { span });
}
};
@@ -186,7 +202,6 @@ impl<'a> Parser<'a> {
segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
}
self.parse_path_segments(&mut segments, style, ty_generics)?;
-
Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None })
}
@@ -198,7 +213,7 @@ impl<'a> Parser<'a> {
) -> PResult<'a, ()> {
loop {
let segment = self.parse_path_segment(style, ty_generics)?;
- if style == PathStyle::Expr {
+ if style.has_generic_ambiguity() {
// In order to check for trailing angle brackets, we must have finished
// recursing (`parse_path_segment` can indirectly call this function),
// that is, the next token must be the highlighted part of the below example:
@@ -220,6 +235,29 @@ impl<'a> Parser<'a> {
segments.push(segment);
if self.is_import_coupler() || !self.eat(&token::ModSep) {
+ if style == PathStyle::Expr
+ && self.may_recover()
+ && self.token == token::Colon
+ && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
+ {
+ // Emit a special error message for `a::b:c` to help users
+ // otherwise, `a: c` might have meant to introduce a new binding
+ if self.token.span.lo() == self.prev_token.span.hi()
+ && self.look_ahead(1, |token| self.token.span.hi() == token.span.lo())
+ {
+ self.bump(); // bump past the colon
+ self.sess.emit_err(PathSingleColon {
+ span: self.prev_token.span,
+ type_ascription: self
+ .sess
+ .unstable_features
+ .is_nightly_build()
+ .then_some(()),
+ });
+ }
+ continue;
+ }
+
return Ok(());
}
}
@@ -273,8 +311,25 @@ impl<'a> Parser<'a> {
ty_generics,
)?;
self.expect_gt().map_err(|mut err| {
+ // Try to recover a `:` into a `::`
+ if self.token == token::Colon
+ && self.look_ahead(1, |token| {
+ token.is_ident() && !token.is_reserved_ident()
+ })
+ {
+ err.cancel();
+ err = PathSingleColon {
+ span: self.token.span,
+ type_ascription: self
+ .sess
+ .unstable_features
+ .is_nightly_build()
+ .then_some(()),
+ }
+ .into_diagnostic(self.diagnostic());
+ }
// Attempt to find places where a missing `>` might belong.
- if let Some(arg) = args
+ else if let Some(arg) = args
.iter()
.rev()
.find(|arg| !matches!(arg, AngleBracketedArg::Constraint(_)))
@@ -467,23 +522,10 @@ impl<'a> Parser<'a> {
// i.e. no multibyte characters, in this range.
let span =
lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
- self.struct_span_err(
+ self.sess.emit_err(errors::UnmatchedAngle {
span,
- &format!(
- "unmatched angle bracket{}",
- pluralize!(snapshot.unmatched_angle_bracket_count)
- ),
- )
- .span_suggestion(
- span,
- &format!(
- "remove extra angle bracket{}",
- pluralize!(snapshot.unmatched_angle_bracket_count)
- ),
- "",
- Applicability::MachineApplicable,
- )
- .emit();
+ plural: snapshot.unmatched_angle_bracket_count > 1,
+ });
// Try again without unmatched angle bracket characters.
self.parse_angle_args(ty_generics)
@@ -564,7 +606,7 @@ impl<'a> Parser<'a> {
let kind = if self.eat(&token::Colon) {
// Parse associated type constraint bound.
- let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
+ let bounds = self.parse_generic_bounds()?;
AssocConstraintKind::Bound { bounds }
} else if self.eat(&token::Eq) {
self.parse_assoc_equality_term(ident, self.prev_token.span)?
@@ -620,10 +662,7 @@ impl<'a> Parser<'a> {
c.into()
}
Some(GenericArg::Lifetime(lt)) => {
- self.struct_span_err(span, "associated lifetimes are not supported")
- .span_label(lt.ident.span, "the lifetime is given here")
- .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
- .emit();
+ self.sess.emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span });
self.mk_ty(span, ast::TyKind::Err).into()
}
None => {
@@ -640,14 +679,14 @@ impl<'a> Parser<'a> {
);
err.span_suggestion(
eq.to(before_next),
- &format!("remove the `=` if `{}` is a type", ident),
+ format!("remove the `=` if `{}` is a type", ident),
"",
Applicability::MaybeIncorrect,
)
} else {
err.span_label(
self.token.span,
- &format!("expected type, found {}", super::token_descr(&self.token)),
+ format!("expected type, found {}", super::token_descr(&self.token)),
)
};
return Err(err);
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index fbe5b88c4..54f9fc5d2 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -10,6 +10,8 @@ use super::{
use crate::errors;
use crate::maybe_whole;
+use crate::errors::MalformedLoopLabel;
+use ast::Label;
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, TokenKind};
@@ -19,7 +21,8 @@ use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt};
use rustc_ast::{StmtKind, DUMMY_NODE_ID};
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
use rustc_span::source_map::{BytePos, Span};
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::{kw, sym, Ident};
+
use std::mem;
use thin_vec::{thin_vec, ThinVec};
@@ -37,7 +40,8 @@ impl<'a> Parser<'a> {
/// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of whether
/// or not we have attributes
- pub(crate) fn parse_stmt_without_recovery(
+ // Public for `cfg_eval` macro expansion.
+ pub fn parse_stmt_without_recovery(
&mut self,
capture_semi: bool,
force_collect: ForceCollect,
@@ -87,7 +91,11 @@ impl<'a> Parser<'a> {
attrs,
errors::InvalidVariableDeclarationSub::UseLetNotVar,
)?
- } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
+ } else if self.check_path()
+ && !self.token.is_qpath_start()
+ && !self.is_path_start_item()
+ && !self.is_builtin()
+ {
// We have avoided contextual keywords like `union`, items with `crate` visibility,
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
// that starts like a path (1 token), but it fact not a path.
@@ -96,7 +104,13 @@ impl<'a> Parser<'a> {
ForceCollect::Yes => {
self.collect_tokens_no_attrs(|this| this.parse_stmt_path_start(lo, attrs))?
}
- ForceCollect::No => self.parse_stmt_path_start(lo, attrs)?,
+ ForceCollect::No => match self.parse_stmt_path_start(lo, attrs) {
+ Ok(stmt) => stmt,
+ Err(mut err) => {
+ self.suggest_add_missing_let_for_stmt(&mut err);
+ return Err(err);
+ }
+ },
}
} else if let Some(item) = self.parse_item_common(
attrs.clone(),
@@ -186,7 +200,7 @@ impl<'a> Parser<'a> {
_ => MacStmtStyle::NoBraces,
};
- let mac = P(MacCall { path, args, prior_type_ascription: self.last_type_ascription });
+ let mac = P(MacCall { path, args });
let kind = if (style == MacStmtStyle::Braces
&& self.token != token::Dot
@@ -546,10 +560,27 @@ impl<'a> Parser<'a> {
}
let stmt = match self.parse_full_stmt(recover) {
Err(mut err) if recover.yes() => {
- self.maybe_annotate_with_ascription(&mut err, false);
if let Some(ref mut snapshot) = snapshot {
snapshot.recover_diff_marker();
}
+ if self.token == token::Colon {
+ // if next token is following a colon, it's likely a path
+ // and we can suggest a path separator
+ self.bump();
+ if self.token.span.lo() == self.prev_token.span.hi() {
+ err.span_suggestion_verbose(
+ self.prev_token.span,
+ "maybe write a path separator here",
+ "::",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ if self.sess.unstable_features.is_nightly_build() {
+ // FIXME(Nilstrieb): Remove this again after a few months.
+ err.note("type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>");
+ }
+ }
+
err.emit();
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
Some(self.mk_stmt_err(self.token.span))
@@ -580,47 +611,104 @@ impl<'a> Parser<'a> {
};
let mut eat_semi = true;
+ let mut add_semi_to_stmt = false;
+
match &mut stmt.kind {
// Expression without semicolon.
StmtKind::Expr(expr)
if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => {
// Just check for errors and recover; do not eat semicolon yet.
// `expect_one_of` returns PResult<'a, bool /* recovered */>
- let replace_with_err =
- match self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]) {
+
+ let expect_result = self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]);
+
+ let replace_with_err = 'break_recover: {
+ match expect_result {
// Recover from parser, skip type error to avoid extra errors.
- Ok(true) => true,
- Err(mut e) => {
- if let TokenKind::DocComment(..) = self.token.kind &&
- let Ok(snippet) = self.span_to_snippet(self.token.span) {
+ Ok(true) => true,
+ Err(mut e) => {
+ if let TokenKind::DocComment(..) = self.token.kind
+ && let Ok(snippet) = self.span_to_snippet(self.token.span)
+ {
let sp = self.token.span;
let marker = &snippet[..3];
let (comment_marker, doc_comment_marker) = marker.split_at(2);
e.span_suggestion(
sp.with_hi(sp.lo() + BytePos(marker.len() as u32)),
- &format!(
+ format!(
"add a space before `{}` to use a regular comment",
doc_comment_marker,
),
format!("{} {}", comment_marker, doc_comment_marker),
Applicability::MaybeIncorrect,
);
- }
+ }
+
+ if self.recover_colon_as_semi() {
+ // recover_colon_as_semi has already emitted a nicer error.
+ e.delay_as_bug();
+ add_semi_to_stmt = true;
+ eat_semi = false;
- if let Err(mut e) =
- self.check_mistyped_turbofish_with_multiple_type_params(e, expr)
- {
- if recover.no() {
- return Err(e);
+ break 'break_recover false;
}
- e.emit();
- self.recover_stmt();
+
+ match &expr.kind {
+ ExprKind::Path(None, ast::Path { segments, .. }) if segments.len() == 1 => {
+ if self.token == token::Colon
+ && self.look_ahead(1, |token| {
+ token.is_whole_block() || matches!(
+ token.kind,
+ token::Ident(kw::For | kw::Loop | kw::While, false)
+ | token::OpenDelim(Delimiter::Brace)
+ )
+ })
+ {
+ let snapshot = self.create_snapshot_for_diagnostic();
+ let label = Label {
+ ident: Ident::from_str_and_span(
+ &format!("'{}", segments[0].ident),
+ segments[0].ident.span,
+ ),
+ };
+ match self.parse_expr_labeled(label, false) {
+ Ok(labeled_expr) => {
+ e.delay_as_bug();
+ self.sess.emit_err(MalformedLoopLabel {
+ span: label.ident.span,
+ correct_label: label.ident,
+ });
+ *expr = labeled_expr;
+ break 'break_recover false;
+ }
+ Err(err) => {
+ err.cancel();
+ self.restore_snapshot(snapshot);
+ }
+ }
+ }
+ }
+ _ => {}
+ }
+
+ if let Err(mut e) =
+ self.check_mistyped_turbofish_with_multiple_type_params(e, expr)
+ {
+ if recover.no() {
+ return Err(e);
+ }
+ e.emit();
+ self.recover_stmt();
+ }
+
+ true
+
}
- true
+ Ok(false) => false
}
- _ => false
};
+
if replace_with_err {
// We already emitted an error, so don't emit another type error
let sp = expr.span.to(self.prev_token.span);
@@ -643,9 +731,10 @@ impl<'a> Parser<'a> {
StmtKind::Empty | StmtKind::Item(_) | StmtKind::Local(_) | StmtKind::Semi(_) => eat_semi = false,
}
- if eat_semi && self.eat(&token::Semi) {
+ if add_semi_to_stmt || (eat_semi && self.eat(&token::Semi)) {
stmt = stmt.add_trailing_semicolon();
}
+
stmt.span = stmt.span.to(self.prev_token.span);
Ok(Some(stmt))
}
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 400c8dbe9..a29b696ae 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -1,10 +1,9 @@
use super::{Parser, PathStyle, TokenType};
use crate::errors::{
- DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
+ self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
- InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
- NegativeBoundsNotSupported, NegativeBoundsNotSupportedSugg, NestedCVariadicType,
+ InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType,
ReturnTypesUseThinArrow,
};
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
@@ -14,8 +13,9 @@ use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::util::case::Case;
use rustc_ast::{
- self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
- MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
+ self as ast, BareFnTy, BoundPolarity, FnRetTy, GenericBound, GenericBounds, GenericParam,
+ Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier,
+ TraitObjectSyntax, Ty, TyKind,
};
use rustc_errors::{Applicability, PResult};
use rustc_span::source_map::Span;
@@ -23,10 +23,10 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use thin_vec::{thin_vec, ThinVec};
-/// Any `?` or `~const` modifiers that appear at the start of a bound.
+/// Any `?`, `!`, or `~const` modifiers that appear at the start of a bound.
struct BoundModifiers {
/// `?Trait`.
- maybe: Option<Span>,
+ bound_polarity: BoundPolarity,
/// `~const Trait`.
maybe_const: Option<Span>,
@@ -34,11 +34,13 @@ struct BoundModifiers {
impl BoundModifiers {
fn to_trait_bound_modifier(&self) -> TraitBoundModifier {
- match (self.maybe, self.maybe_const) {
- (None, None) => TraitBoundModifier::None,
- (Some(_), None) => TraitBoundModifier::Maybe,
- (None, Some(_)) => TraitBoundModifier::MaybeConst,
- (Some(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
+ match (self.bound_polarity, self.maybe_const) {
+ (BoundPolarity::Positive, None) => TraitBoundModifier::None,
+ (BoundPolarity::Negative(_), None) => TraitBoundModifier::Negative,
+ (BoundPolarity::Maybe(_), None) => TraitBoundModifier::Maybe,
+ (BoundPolarity::Positive, Some(_)) => TraitBoundModifier::MaybeConst,
+ (BoundPolarity::Negative(_), Some(_)) => TraitBoundModifier::MaybeConstNegative,
+ (BoundPolarity::Maybe(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
}
}
}
@@ -315,9 +317,8 @@ impl<'a> Parser<'a> {
}
} else {
let msg = format!("expected type, found {}", super::token_descr(&self.token));
- let mut err = self.struct_span_err(self.token.span, &msg);
+ let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, "expected type");
- self.maybe_annotate_with_ascription(&mut err, true);
return Err(err);
};
@@ -369,7 +370,7 @@ impl<'a> Parser<'a> {
fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus());
- let bounds = self.parse_generic_bounds_common(allow_plus, None)?;
+ let bounds = self.parse_generic_bounds_common(allow_plus)?;
if lt_no_plus {
self.sess.emit_err(NeedPlusAfterTraitObjectLifetime { span: lo });
}
@@ -396,7 +397,7 @@ impl<'a> Parser<'a> {
) -> PResult<'a, TyKind> {
if plus {
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
- bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?);
+ bounds.append(&mut self.parse_generic_bounds()?);
}
Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
}
@@ -588,24 +589,18 @@ impl<'a> Parser<'a> {
// Always parse bounds greedily for better error recovery.
if self.token.is_lifetime() {
self.look_ahead(1, |t| {
- if let token::Ident(symname, _) = t.kind {
+ if let token::Ident(sym, _) = t.kind {
// parse pattern with "'a Sized" we're supposed to give suggestion like
// "'a + Sized"
- self.struct_span_err(
- self.token.span,
- &format!("expected `+` between lifetime and {}", symname),
- )
- .span_suggestion_verbose(
- self.token.span.shrink_to_hi(),
- "add `+`",
- " +",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(errors::MissingPlusBounds {
+ span: self.token.span,
+ hi: self.token.span.shrink_to_hi(),
+ sym,
+ });
}
})
}
- let bounds = self.parse_generic_bounds(None)?;
+ let bounds = self.parse_generic_bounds()?;
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
}
@@ -636,7 +631,7 @@ impl<'a> Parser<'a> {
};
// Always parse bounds greedily for better error recovery.
- let bounds = self.parse_generic_bounds(None)?;
+ let bounds = self.parse_generic_bounds()?;
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
Ok(TyKind::TraitObject(bounds, syntax))
}
@@ -657,11 +652,7 @@ impl<'a> Parser<'a> {
let path = self.parse_path_inner(PathStyle::Type, ty_generics)?;
if self.eat(&token::Not) {
// Macro invocation in type position
- Ok(TyKind::MacCall(P(MacCall {
- path,
- args: self.parse_delim_args()?,
- prior_type_ascription: self.last_type_ascription,
- })))
+ Ok(TyKind::MacCall(P(MacCall { path, args: self.parse_delim_args()? })))
} else if allow_plus == AllowPlus::Yes && self.check_plus() {
// `Trait1 + Trait2 + 'a`
self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true)
@@ -671,23 +662,15 @@ impl<'a> Parser<'a> {
}
}
- pub(super) fn parse_generic_bounds(
- &mut self,
- colon_span: Option<Span>,
- ) -> PResult<'a, GenericBounds> {
- self.parse_generic_bounds_common(AllowPlus::Yes, colon_span)
+ pub(super) fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> {
+ self.parse_generic_bounds_common(AllowPlus::Yes)
}
/// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`.
///
/// See `parse_generic_bound` for the `BOUND` grammar.
- fn parse_generic_bounds_common(
- &mut self,
- allow_plus: AllowPlus,
- colon_span: Option<Span>,
- ) -> PResult<'a, GenericBounds> {
+ fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> {
let mut bounds = Vec::new();
- let mut negative_bounds = Vec::new();
// In addition to looping while we find generic bounds:
// We continue even if we find a keyword. This is necessary for error recovery on,
@@ -704,19 +687,12 @@ impl<'a> Parser<'a> {
self.sess.emit_err(InvalidDynKeyword { span: self.token.span });
self.bump();
}
- match self.parse_generic_bound()? {
- Ok(bound) => bounds.push(bound),
- Err(neg_sp) => negative_bounds.push(neg_sp),
- }
+ bounds.push(self.parse_generic_bound()?);
if allow_plus == AllowPlus::No || !self.eat_plus() {
break;
}
}
- if !negative_bounds.is_empty() {
- self.error_negative_bounds(colon_span, &bounds, negative_bounds);
- }
-
Ok(bounds)
}
@@ -724,55 +700,22 @@ impl<'a> Parser<'a> {
fn can_begin_bound(&mut self) -> bool {
// This needs to be synchronized with `TokenKind::can_begin_bound`.
self.check_path()
- || self.check_lifetime()
- || self.check(&token::Not) // Used for error reporting only.
- || self.check(&token::Question)
- || self.check(&token::Tilde)
- || self.check_keyword(kw::For)
- || self.check(&token::OpenDelim(Delimiter::Parenthesis))
- }
-
- fn error_negative_bounds(
- &self,
- colon_span: Option<Span>,
- bounds: &[GenericBound],
- negative_bounds: Vec<Span>,
- ) {
- let sub = if let Some(bound_list) = colon_span {
- let bound_list = bound_list.to(self.prev_token.span);
- let mut new_bound_list = String::new();
- if !bounds.is_empty() {
- let mut snippets = bounds.iter().map(|bound| self.span_to_snippet(bound.span()));
- while let Some(Ok(snippet)) = snippets.next() {
- new_bound_list.push_str(" + ");
- new_bound_list.push_str(&snippet);
- }
- new_bound_list = new_bound_list.replacen(" +", ":", 1);
- }
-
- Some(NegativeBoundsNotSupportedSugg {
- bound_list,
- num_bounds: negative_bounds.len(),
- fixed: new_bound_list,
- })
- } else {
- None
- };
-
- let last_span = *negative_bounds.last().expect("no negative bounds, but still error?");
- self.sess.emit_err(NegativeBoundsNotSupported { negative_bounds, last_span, sub });
+ || self.check_lifetime()
+ || self.check(&token::Not)
+ || self.check(&token::Question)
+ || self.check(&token::Tilde)
+ || self.check_keyword(kw::For)
+ || self.check(&token::OpenDelim(Delimiter::Parenthesis))
}
/// Parses a bound according to the grammar:
/// ```ebnf
/// BOUND = TY_BOUND | LT_BOUND
/// ```
- fn parse_generic_bound(&mut self) -> PResult<'a, Result<GenericBound, Span>> {
- let anchor_lo = self.prev_token.span;
+ fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
let lo = self.token.span;
let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis));
let inner_lo = self.token.span;
- let is_negative = self.eat(&token::Not);
let modifiers = self.parse_ty_bound_modifiers()?;
let bound = if self.token.is_lifetime() {
@@ -782,7 +725,7 @@ impl<'a> Parser<'a> {
self.parse_generic_ty_bound(lo, has_parens, modifiers)?
};
- Ok(if is_negative { Err(anchor_lo.to(self.prev_token.span)) } else { Ok(bound) })
+ Ok(bound)
}
/// Parses a lifetime ("outlives") bound, e.g. `'a`, according to:
@@ -807,16 +750,17 @@ impl<'a> Parser<'a> {
/// Emits an error if any trait bound modifiers were present.
fn error_lt_bound_with_modifiers(&self, modifiers: BoundModifiers) {
if let Some(span) = modifiers.maybe_const {
- self.struct_span_err(
- span,
- "`~const` may only modify trait bounds, not lifetime bounds",
- )
- .emit();
+ self.sess.emit_err(errors::TildeConstLifetime { span });
}
- if let Some(span) = modifiers.maybe {
- self.struct_span_err(span, "`?` may only modify trait bounds, not lifetime bounds")
- .emit();
+ match modifiers.bound_polarity {
+ BoundPolarity::Positive => {}
+ BoundPolarity::Negative(span) => {
+ self.sess.emit_err(errors::ModifierLifetime { span, sigil: "!" });
+ }
+ BoundPolarity::Maybe(span) => {
+ self.sess.emit_err(errors::ModifierLifetime { span, sigil: "?" });
+ }
}
}
@@ -824,19 +768,14 @@ impl<'a> Parser<'a> {
fn recover_paren_lifetime(&mut self, lo: Span, inner_lo: Span) -> PResult<'a, ()> {
let inner_span = inner_lo.to(self.prev_token.span);
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
- let mut err = self.struct_span_err(
- lo.to(self.prev_token.span),
- "parenthesized lifetime bounds are not supported",
- );
- if let Ok(snippet) = self.span_to_snippet(inner_span) {
- err.span_suggestion_short(
- lo.to(self.prev_token.span),
- "remove the parentheses",
- snippet,
- Applicability::MachineApplicable,
- );
- }
- err.emit();
+ let span = lo.to(self.prev_token.span);
+ let (sugg, snippet) = if let Ok(snippet) = self.span_to_snippet(inner_span) {
+ (Some(span), snippet)
+ } else {
+ (None, String::new())
+ };
+
+ self.sess.emit_err(errors::ParenthesizedLifetime { span, sugg, snippet });
Ok(())
}
@@ -857,24 +796,23 @@ impl<'a> Parser<'a> {
} else if self.eat_keyword(kw::Const) {
let span = self.prev_token.span;
self.sess.gated_spans.gate(sym::const_trait_impl, span);
-
- self.struct_span_err(span, "const bounds must start with `~`")
- .span_suggestion(
- span.shrink_to_lo(),
- "add `~`",
- "~",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::ConstMissingTilde { span, start: span.shrink_to_lo() });
Some(span)
} else {
None
};
- let maybe = self.eat(&token::Question).then_some(self.prev_token.span);
+ let bound_polarity = if self.eat(&token::Question) {
+ BoundPolarity::Maybe(self.prev_token.span)
+ } else if self.eat(&token::Not) {
+ self.sess.gated_spans.gate(sym::negative_bounds, self.prev_token.span);
+ BoundPolarity::Negative(self.prev_token.span)
+ } else {
+ BoundPolarity::Positive
+ };
- Ok(BoundModifiers { maybe, maybe_const })
+ Ok(BoundModifiers { bound_polarity, maybe_const })
}
/// Parses a type bound according to:
@@ -944,14 +882,10 @@ impl<'a> Parser<'a> {
self.parse_remaining_bounds(bounds, true)?;
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
let sp = vec![lo, self.prev_token.span];
- let sugg = vec![(lo, String::from(" ")), (self.prev_token.span, String::new())];
- self.struct_span_err(sp, "incorrect braces around trait bounds")
- .multipart_suggestion(
- "remove the parentheses",
- sugg,
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::IncorrectBracesTraitBounds {
+ span: sp,
+ sugg: errors::IncorrectBracesTraitBoundsSugg { l: lo, r: self.prev_token.span },
+ });
} else {
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
}
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 72402a200..928fdce31 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -1,6 +1,6 @@
//! Meta-syntax validation logic of attributes for post-expansion.
-use crate::parse_in;
+use crate::{errors, parse_in};
use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::MetaItemKind;
@@ -45,7 +45,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
kind: match &item.args {
AttrArgs::Empty => MetaItemKind::Word,
AttrArgs::Delimited(DelimArgs { dspan, delim, tokens }) => {
- check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters");
+ check_meta_bad_delim(sess, *dspan, *delim);
let nmis = parse_in(sess, tokens.clone(), "meta list", |p| p.parse_meta_seq_top())?;
MetaItemKind::List(nmis)
}
@@ -68,7 +68,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
}
} else {
// The non-error case can happen with e.g. `#[foo = 1+1]`. The error case can
- // happen with e.g. `#[foo = include_str!("non-existent-file.rs")]`; in that
+ // happen with e.g. `#[foo = include_str!("nonexistent-file.rs")]`; in that
// case we delay the error because an earlier error will have already been
// reported.
let msg = format!("unexpected expression: `{}`", pprust::expr_to_string(expr));
@@ -84,19 +84,24 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
})
}
-pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) {
+pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter) {
if let ast::MacDelimiter::Parenthesis = delim {
return;
}
+ sess.emit_err(errors::MetaBadDelim {
+ span: span.entire(),
+ sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close },
+ });
+}
- sess.span_diagnostic
- .struct_span_err(span.entire(), msg)
- .multipart_suggestion(
- "the delimiters should be `(` and `)`",
- vec![(span.open, "(".to_string()), (span.close, ")".to_string())],
- Applicability::MachineApplicable,
- )
- .emit();
+pub fn check_cfg_attr_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter) {
+ if let ast::MacDelimiter::Parenthesis = delim {
+ return;
+ }
+ sess.emit_err(errors::CfgAttrBadDelim {
+ span: span.entire(),
+ sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close },
+ });
}
/// Checks that the given meta-item is compatible with this `AttributeTemplate`.
@@ -181,10 +186,10 @@ fn emit_malformed_attribute(
suggestions.push(code);
}
if should_warn(name) {
- sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, &msg);
+ sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, msg);
} else {
sess.span_diagnostic
- .struct_span_err(span, &error_msg)
+ .struct_span_err(span, error_msg)
.span_suggestions(
span,
if suggestions.len() == 1 {