Rollup merge of #144195 - Kivooeo:bad-attr, r=fmease,compiler-errors

Parser: Recover from attributes applied to types and generic args

r? compiler

Add clearer error messages for invalid attribute usage in types or generic types

fixes rust-lang/rust#135017
fixes rust-lang/rust#144132
This commit is contained in:
Guillaume Gomez
2025-08-06 21:29:26 +02:00
committed by GitHub
14 changed files with 395 additions and 23 deletions

View File

@@ -1489,6 +1489,34 @@ pub(crate) struct AttributeOnParamType {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(parse_attribute_on_type)]
pub(crate) struct AttributeOnType {
#[primary_span]
#[label]
pub span: Span,
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
pub fix_span: Span,
}
#[derive(Diagnostic)]
#[diag(parse_attribute_on_generic_arg)]
pub(crate) struct AttributeOnGenericArg {
#[primary_span]
#[label]
pub span: Span,
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
pub fix_span: Span,
}
#[derive(Diagnostic)]
#[diag(parse_attribute_on_empty_type)]
pub(crate) struct AttributeOnEmptyType {
#[primary_span]
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(parse_pattern_method_param_without_body, code = E0642)]
pub(crate) struct PatternMethodParamWithoutBody {

View File

@@ -17,11 +17,11 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{Parser, Restrictions, TokenType};
use crate::ast::{PatKind, TyKind};
use crate::errors::{
self, FnPathFoundNamedParams, PathFoundAttributeInParams, PathFoundCVariadicParams,
PathSingleColon, PathTripleColon,
self, AttributeOnEmptyType, AttributeOnGenericArg, FnPathFoundNamedParams,
PathFoundAttributeInParams, PathFoundCVariadicParams, PathSingleColon, PathTripleColon,
};
use crate::exp;
use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma};
use crate::parser::{CommaRecoveryMode, ExprKind, RecoverColon, RecoverComma};
/// Specifies how to parse a path.
#[derive(Copy, Clone, PartialEq)]
@@ -880,6 +880,12 @@ impl<'a> Parser<'a> {
&mut self,
ty_generics: Option<&Generics>,
) -> PResult<'a, Option<GenericArg>> {
let mut attr_span: Option<Span> = None;
if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) {
let attrs_wrapper = self.parse_outer_attributes()?;
let raw_attrs = attrs_wrapper.take_for_recovery(self.psess);
attr_span = Some(raw_attrs[0].span.to(raw_attrs.last().unwrap().span));
}
let start = self.token.span;
let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
// Parse lifetime argument.
@@ -934,6 +940,9 @@ impl<'a> Parser<'a> {
}
} else if self.token.is_keyword(kw::Const) {
return self.recover_const_param_declaration(ty_generics);
} else if let Some(attr_span) = attr_span {
let diag = self.dcx().create_err(AttributeOnEmptyType { span: attr_span });
return Err(diag);
} else {
// Fall back by trying to parse a const-expr expression. If we successfully do so,
// then we should report an error that it needs to be wrapped in braces.
@@ -953,6 +962,22 @@ impl<'a> Parser<'a> {
}
}
};
if let Some(attr_span) = attr_span {
let guar = self.dcx().emit_err(AttributeOnGenericArg {
span: attr_span,
fix_span: attr_span.until(arg.span()),
});
return Ok(Some(match arg {
GenericArg::Type(_) => GenericArg::Type(self.mk_ty(attr_span, TyKind::Err(guar))),
GenericArg::Const(_) => {
let error_expr = self.mk_expr(attr_span, ExprKind::Err(guar));
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: error_expr })
}
GenericArg::Lifetime(lt) => GenericArg::Lifetime(lt),
}));
}
Ok(Some(arg))
}

View File

@@ -14,10 +14,10 @@ use thin_vec::{ThinVec, thin_vec};
use super::{Parser, PathStyle, SeqSep, TokenType, Trailing};
use crate::errors::{
self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
FnPtrWithGenerics, FnPtrWithGenericsSugg, HelpUseLatestEdition, InvalidDynKeyword,
LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType,
ReturnTypesUseThinArrow,
self, AttributeOnEmptyType, AttributeOnType, DynAfterMut, ExpectedFnPathFoundFnKeyword,
ExpectedMutOrConstInRawPointerType, FnPtrWithGenerics, FnPtrWithGenericsSugg,
HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
NestedCVariadicType, ReturnTypesUseThinArrow,
};
use crate::parser::item::FrontMatterParsingMode;
use crate::{exp, maybe_recover_from_interpolated_ty_qpath};
@@ -253,7 +253,27 @@ impl<'a> Parser<'a> {
) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) {
let attrs_wrapper = self.parse_outer_attributes()?;
let raw_attrs = attrs_wrapper.take_for_recovery(self.psess);
let attr_span = raw_attrs[0].span.to(raw_attrs.last().unwrap().span);
let (full_span, guar) = match self.parse_ty() {
Ok(ty) => {
let full_span = attr_span.until(ty.span);
let guar = self
.dcx()
.emit_err(AttributeOnType { span: attr_span, fix_span: full_span });
(attr_span, guar)
}
Err(err) => {
err.cancel();
let guar = self.dcx().emit_err(AttributeOnEmptyType { span: attr_span });
(attr_span, guar)
}
};
return Ok(self.mk_ty(full_span, TyKind::Err(guar)));
}
if let Some(ty) = self.eat_metavar_seq_with_matcher(
|mv_kind| matches!(mv_kind, MetaVarKind::Ty { .. }),
|this| this.parse_ty_no_question_mark_recover(),