Change:
It feels like rustc should be able to determine that a trait followed by a is a -family trait bound and be able to suggest this behavior. If that is too general it could just check for , , . Very similar is if parenthesis are missing from regular declarations: Also happens on nightly according to Rust Playground. I'd like to try my hand at implementing this diagnostic, but I'll likely need a little bit of locational guidance. A naive code search show that the message is emitted by this code is the parser diagnostics, but I'm not sure if the adjustment would need to be made within that or from where it is invoked in this case. Edit: Updated to use the wording "-family trait bounds" rather than "HRTBs"._
Where this function is invoked. Try looking for the code that parses .
If you end up writing a fix, note that those trait bounds are usually called -family trait bounds, not “HRTBs”. The latter would require at least one higher-rank parameter to be involved (e.g. ).
It seems this diagnostic contextually comes from which does this token search by . As corroboration it also seems that declaring a regular without parenthesis causes a similar if more contextually understandable error: I naively think that the adjustment point should probably be rather than ... However I don't understand how the output gets multiple possibilities e.g. and in this output: or the whole list of Since it's only calling with from ... I guess this requires catching the result in and handling this result type somehow?
Any time you call , it stashes the token type you tried probing for and it'll present that in a list whenever you get to . (Or something like that).
Anyways, it shouldn't matter -- in the caller to (when parsing ), you could add a check for before calling and handle the token specifically.
Just chiming in to mention: in any parser change you make here make sure you don't start accepting new code and add tests for all combinations you can think of.

Discussion:
*[false] a } `for` parameter list <ins> parse_fn_trait_missing_paren = `Fn` bounds require arguments in parentheses .add_paren = add the missing parentheses </ins> parse_forgot_paren = perhaps you forgot parentheses? parse_found_expr_would_be_stmt = expected expression, found `{$token}`

pub for_param_list_exists: bool, } <ins> pub(crate) struct FnTraitMissingParen { pub span: Span, pub machine_applicable: bool, } impl AddToDiagnostic for FnTraitMissingParen { fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) where F: Fn( &mut rustc_errors::Diagnostic, rustc_errors::SubdiagnosticMessage, ) -> rustc_errors::SubdiagnosticMessage, { diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren); let applicability = if self.machine_applicable { Applicability::MachineApplicable } else { Applicability::MaybeIncorrect }; diag.span_suggestion_short( self.span.shrink_to_hi(), crate::fluent_generated::parse_add_paren, "()", applicability, ); } } </ins> #[derive(Diagnostic)] #[diag(parse_unexpected_if_with_if)] pub(crate) struct UnexpectedIfWithIf(

err.span_label(ident.span, "while parsing this `fn`"); err.emit(); } else { <ins> // check for typo'd Fn* trait bounds such as // fn foo<F>() where F: FnOnce -> () {} if self.token.kind == token::RArrow { let machine_applicable = [sym::FnOnce, sym::FnMut, sym::Fn] .into_iter() .any(|s| self.prev_token.is_ident_named(s)); err.subdiagnostic(errors::FnTraitMissingParen { span: self.prev_token.span, machine_applicable, }); } </ins> return Err(err); } }

Error, File, FileType, <ins> Fn, FnMut, FnOnce, </ins> FormatSpec, Formatter, From,

<ins> // run-rustfix pub fn func<F>() where F: FnOnce() -> () {} //~^ ERROR expected one of //~| NOTE expected one of //~| NOTE `Fn` bounds require arguments in parentheses fn main() {} </ins>

<ins> // run-rustfix pub fn func<F>() where F: FnOnce -> () {} //~^ ERROR expected one of //~| NOTE expected one of //~| NOTE `Fn` bounds require arguments in parentheses fn main() {} </ins>

<ins> error: expected one of `(`, `+`, `,`, `::`, `<`, or `{`, found `->` --> $DIR/issue-108109-fn-trait-missing-paren.rs:3:34 | LL | pub fn func<F>() where F: FnOnce -> () {} |                           -------^^ expected one of `(`, `+`, `,`, `::`, `<`, or `{` |                           |     | |                           |     help: try adding parentheses |                           `Fn` bounds require arguments in parentheses error: aborting due to previous error </ins>