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

@@ -71,6 +71,17 @@ parse_attr_without_generics = attribute without generic parameters
parse_attribute_on_param_type = attributes cannot be applied to a function parameter's type parse_attribute_on_param_type = attributes cannot be applied to a function parameter's type
.label = attributes are not allowed here .label = attributes are not allowed here
parse_attribute_on_type = attributes cannot be applied to types
.label = attributes are not allowed here
.suggestion = remove attribute from here
parse_attribute_on_generic_arg = attributes cannot be applied to generic arguments
.label = attributes are not allowed here
.suggestion = remove attribute from here
parse_attribute_on_empty_type = attributes cannot be applied here
.label = attributes are not allowed here
parse_bad_assoc_type_bounds = bounds on associated types do not belong here parse_bad_assoc_type_bounds = bounds on associated types do not belong here
.label = belongs in `where` clause .label = belongs in `where` clause

View File

@@ -1489,6 +1489,34 @@ pub(crate) struct AttributeOnParamType {
pub span: Span, 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)] #[derive(Diagnostic)]
#[diag(parse_pattern_method_param_without_body, code = E0642)] #[diag(parse_pattern_method_param_without_body, code = E0642)]
pub(crate) struct PatternMethodParamWithoutBody { pub(crate) struct PatternMethodParamWithoutBody {

View File

@@ -17,11 +17,11 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{Parser, Restrictions, TokenType}; use super::{Parser, Restrictions, TokenType};
use crate::ast::{PatKind, TyKind}; use crate::ast::{PatKind, TyKind};
use crate::errors::{ use crate::errors::{
self, FnPathFoundNamedParams, PathFoundAttributeInParams, PathFoundCVariadicParams, self, AttributeOnEmptyType, AttributeOnGenericArg, FnPathFoundNamedParams,
PathSingleColon, PathTripleColon, PathFoundAttributeInParams, PathFoundCVariadicParams, PathSingleColon, PathTripleColon,
}; };
use crate::exp; use crate::exp;
use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma}; use crate::parser::{CommaRecoveryMode, ExprKind, RecoverColon, RecoverComma};
/// Specifies how to parse a path. /// Specifies how to parse a path.
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
@@ -880,6 +880,12 @@ impl<'a> Parser<'a> {
&mut self, &mut self,
ty_generics: Option<&Generics>, ty_generics: Option<&Generics>,
) -> PResult<'a, Option<GenericArg>> { ) -> 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 start = self.token.span;
let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
// Parse lifetime argument. // Parse lifetime argument.
@@ -934,6 +940,9 @@ impl<'a> Parser<'a> {
} }
} else if self.token.is_keyword(kw::Const) { } else if self.token.is_keyword(kw::Const) {
return self.recover_const_param_declaration(ty_generics); 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 { } else {
// Fall back by trying to parse a const-expr expression. If we successfully do so, // 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. // 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)) Ok(Some(arg))
} }

View File

@@ -14,10 +14,10 @@ use thin_vec::{ThinVec, thin_vec};
use super::{Parser, PathStyle, SeqSep, TokenType, Trailing}; use super::{Parser, PathStyle, SeqSep, TokenType, Trailing};
use crate::errors::{ use crate::errors::{
self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, self, AttributeOnEmptyType, AttributeOnType, DynAfterMut, ExpectedFnPathFoundFnKeyword,
FnPtrWithGenerics, FnPtrWithGenericsSugg, HelpUseLatestEdition, InvalidDynKeyword, ExpectedMutOrConstInRawPointerType, FnPtrWithGenerics, FnPtrWithGenericsSugg,
LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
ReturnTypesUseThinArrow, NestedCVariadicType, ReturnTypesUseThinArrow,
}; };
use crate::parser::item::FrontMatterParsingMode; use crate::parser::item::FrontMatterParsingMode;
use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; use crate::{exp, maybe_recover_from_interpolated_ty_qpath};
@@ -253,7 +253,27 @@ impl<'a> Parser<'a> {
) -> PResult<'a, P<Ty>> { ) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); 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( if let Some(ty) = self.eat_metavar_seq_with_matcher(
|mv_kind| matches!(mv_kind, MetaVarKind::Ty { .. }), |mv_kind| matches!(mv_kind, MetaVarKind::Ty { .. }),
|this| this.parse_ty_no_question_mark_recover(), |this| this.parse_ty_no_question_mark_recover(),

View File

@@ -0,0 +1,29 @@
//! Regression test for: <https://github.com/rust-lang/rust/issues/144132>
//! <https://github.com/rust-lang/rust/issues/135017>
struct Baz<const N: usize>(i32);
fn main() {
let _: Baz<#[cfg(any())]> = todo!();
//~^ ERROR attributes cannot be applied here
}
fn f(_param: #[attr]) {}
//~^ ERROR attributes cannot be applied to a function parameter's type
//~| ERROR expected type, found `)`
fn g() -> #[attr] { 0 }
//~^ ERROR attributes cannot be applied here
struct S {
field: #[attr],
//~^ ERROR attributes cannot be applied here
field1: (#[attr], i32),
//~^ ERROR attributes cannot be applied here
}
type Tuple = (#[attr], String);
//~^ ERROR attributes cannot be applied here
impl #[attr] {}
//~^ ERROR attributes cannot be applied here

View File

@@ -0,0 +1,52 @@
error: attributes cannot be applied here
--> $DIR/attribute-on-empty.rs:7:16
|
LL | let _: Baz<#[cfg(any())]> = todo!();
| - ^^^^^^^^^^^^^ attributes are not allowed here
| |
| while parsing the type for `_`
error: attributes cannot be applied to a function parameter's type
--> $DIR/attribute-on-empty.rs:11:14
|
LL | fn f(_param: #[attr]) {}
| ^^^^^^^ attributes are not allowed here
error: expected type, found `)`
--> $DIR/attribute-on-empty.rs:11:21
|
LL | fn f(_param: #[attr]) {}
| ^ expected type
error: attributes cannot be applied here
--> $DIR/attribute-on-empty.rs:15:11
|
LL | fn g() -> #[attr] { 0 }
| ^^^^^^^ attributes are not allowed here
error: attributes cannot be applied here
--> $DIR/attribute-on-empty.rs:19:12
|
LL | field: #[attr],
| ^^^^^^^ attributes are not allowed here
error: attributes cannot be applied here
--> $DIR/attribute-on-empty.rs:21:14
|
LL | field1: (#[attr], i32),
| ^^^^^^^ attributes are not allowed here
error: attributes cannot be applied here
--> $DIR/attribute-on-empty.rs:25:15
|
LL | type Tuple = (#[attr], String);
| ^^^^^^^ attributes are not allowed here
error: attributes cannot be applied here
--> $DIR/attribute-on-empty.rs:28:6
|
LL | impl #[attr] {}
| ^^^^^^^ attributes are not allowed here
error: aborting due to 8 previous errors

View File

@@ -0,0 +1,58 @@
//! Regression test for: <https://github.com/rust-lang/rust/issues/144132>
//! <https://github.com/rust-lang/rust/issues/135017>
//@ run-rustfix
#![allow(dead_code, unused_variables)]
struct Foo<T>(T);
struct Bar<'a>(&'a i32);
struct Baz<const N: usize>(i32);
fn main() {
let foo: Foo<i32> = Foo(2i32);
//~^ ERROR attributes cannot be applied to generic arguments
let _: &'static str = "123";
//~^ ERROR attributes cannot be applied to types
let _: Bar<'static> = Bar(&123);
//~^ ERROR attributes cannot be applied to generic arguments
let _: Baz<42> = Baz(42);
//~^ ERROR attributes cannot be applied to generic arguments
let _: Foo<String> = Foo(String::new());
//~^ ERROR attributes cannot be applied to generic arguments
let _: Bar<'static> = Bar(&456);
//~^ ERROR attributes cannot be applied to generic arguments
let _generic: Box<i32> = Box::new(1);
//~^ ERROR attributes cannot be applied to generic arguments
let _assignment: i32 = *Box::new(1);
//~^ ERROR attributes cannot be applied to types
let _complex: Vec<String> = vec![];
//~^ ERROR attributes cannot be applied to generic arguments
let _nested: Box<Vec<u64>> = Box::new(vec![]);
//~^ ERROR attributes cannot be applied to generic arguments
}
fn g() -> i32 { 0 }
//~^ ERROR attributes cannot be applied to types
struct S {
field: i32,
//~^ ERROR attributes cannot be applied to types
field1: (i32, i32),
//~^ ERROR attributes cannot be applied to types
}
type Tuple = (i32, String);
//~^ ERROR attributes cannot be applied to types
impl S {}
//~^ ERROR attributes cannot be applied to types

View File

@@ -0,0 +1,58 @@
//! Regression test for: <https://github.com/rust-lang/rust/issues/144132>
//! <https://github.com/rust-lang/rust/issues/135017>
//@ run-rustfix
#![allow(dead_code, unused_variables)]
struct Foo<T>(T);
struct Bar<'a>(&'a i32);
struct Baz<const N: usize>(i32);
fn main() {
let foo: Foo<#[cfg(not(wrong))] i32> = Foo(2i32);
//~^ ERROR attributes cannot be applied to generic arguments
let _: #[attr] &'static str = "123";
//~^ ERROR attributes cannot be applied to types
let _: Bar<#[cfg(any())] 'static> = Bar(&123);
//~^ ERROR attributes cannot be applied to generic arguments
let _: Baz<#[cfg(any())] 42> = Baz(42);
//~^ ERROR attributes cannot be applied to generic arguments
let _: Foo<#[cfg(not(wrong))]String> = Foo(String::new());
//~^ ERROR attributes cannot be applied to generic arguments
let _: Bar<#[cfg(any())] 'static> = Bar(&456);
//~^ ERROR attributes cannot be applied to generic arguments
let _generic: Box<#[attr] i32> = Box::new(1);
//~^ ERROR attributes cannot be applied to generic arguments
let _assignment: #[attr] i32 = *Box::new(1);
//~^ ERROR attributes cannot be applied to types
let _complex: Vec<#[derive(Debug)] String> = vec![];
//~^ ERROR attributes cannot be applied to generic arguments
let _nested: Box<Vec<#[cfg(feature = "test")] u64>> = Box::new(vec![]);
//~^ ERROR attributes cannot be applied to generic arguments
}
fn g() -> #[attr] i32 { 0 }
//~^ ERROR attributes cannot be applied to types
struct S {
field: #[attr] i32,
//~^ ERROR attributes cannot be applied to types
field1: (#[attr] i32, i32),
//~^ ERROR attributes cannot be applied to types
}
type Tuple = (#[attr] i32, String);
//~^ ERROR attributes cannot be applied to types
impl #[attr] S {}
//~^ ERROR attributes cannot be applied to types

View File

@@ -0,0 +1,92 @@
error: attributes cannot be applied to generic arguments
--> $DIR/attribute-on-type.rs:13:18
|
LL | let foo: Foo<#[cfg(not(wrong))] i32> = Foo(2i32);
| ^^^^^^^^^^^^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to types
--> $DIR/attribute-on-type.rs:16:12
|
LL | let _: #[attr] &'static str = "123";
| ^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to generic arguments
--> $DIR/attribute-on-type.rs:19:16
|
LL | let _: Bar<#[cfg(any())] 'static> = Bar(&123);
| ^^^^^^^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to generic arguments
--> $DIR/attribute-on-type.rs:22:16
|
LL | let _: Baz<#[cfg(any())] 42> = Baz(42);
| ^^^^^^^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to generic arguments
--> $DIR/attribute-on-type.rs:25:16
|
LL | let _: Foo<#[cfg(not(wrong))]String> = Foo(String::new());
| ^^^^^^^^^^^^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to generic arguments
--> $DIR/attribute-on-type.rs:28:16
|
LL | let _: Bar<#[cfg(any())] 'static> = Bar(&456);
| ^^^^^^^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to generic arguments
--> $DIR/attribute-on-type.rs:31:23
|
LL | let _generic: Box<#[attr] i32> = Box::new(1);
| ^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to types
--> $DIR/attribute-on-type.rs:34:22
|
LL | let _assignment: #[attr] i32 = *Box::new(1);
| ^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to generic arguments
--> $DIR/attribute-on-type.rs:37:23
|
LL | let _complex: Vec<#[derive(Debug)] String> = vec![];
| ^^^^^^^^^^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to generic arguments
--> $DIR/attribute-on-type.rs:40:26
|
LL | let _nested: Box<Vec<#[cfg(feature = "test")] u64>> = Box::new(vec![]);
| ^^^^^^^^^^^^^^^^^^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to types
--> $DIR/attribute-on-type.rs:44:11
|
LL | fn g() -> #[attr] i32 { 0 }
| ^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to types
--> $DIR/attribute-on-type.rs:48:12
|
LL | field: #[attr] i32,
| ^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to types
--> $DIR/attribute-on-type.rs:50:14
|
LL | field1: (#[attr] i32, i32),
| ^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to types
--> $DIR/attribute-on-type.rs:54:15
|
LL | type Tuple = (#[attr] i32, String);
| ^^^^^^^ attributes are not allowed here
error: attributes cannot be applied to types
--> $DIR/attribute-on-type.rs:57:6
|
LL | impl #[attr] S {}
| ^^^^^^^ attributes are not allowed here
error: aborting due to 15 previous errors

View File

@@ -1,5 +1,5 @@
fn main() { fn main() {
x::<#[a]y::<z>> x::<#[a]y::<z>>
//~^ ERROR invalid const generic expression //~^ ERROR attributes cannot be applied to generic arguments
//~| ERROR cannot find value `x` in this scope //~| ERROR cannot find value `x` in this scope
} }

View File

@@ -1,13 +1,8 @@
error: invalid const generic expression error: attributes cannot be applied to generic arguments
--> $DIR/issue-103143.rs:2:13 --> $DIR/issue-103143.rs:2:9
| |
LL | x::<#[a]y::<z>> LL | x::<#[a]y::<z>>
| ^^^^^^ | ^^^^ attributes are not allowed here
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
LL | x::<#[a]{ y::<z> }>
| + +
error[E0425]: cannot find value `x` in this scope error[E0425]: cannot find value `x` in this scope
--> $DIR/issue-103143.rs:2:5 --> $DIR/issue-103143.rs:2:5

View File

@@ -1,7 +1,9 @@
// Regression test for issues #100790 and #106439. // Regression test for issues #100790 and #106439.
//@ run-rustfix //@ run-rustfix
pub struct Example(#[allow(dead_code)] usize) #![allow(dead_code)]
pub struct Example(usize)
where where
(): Sized; (): Sized;
//~^^^ ERROR where clauses are not allowed before tuple struct bodies //~^^^ ERROR where clauses are not allowed before tuple struct bodies

View File

@@ -1,10 +1,12 @@
// Regression test for issues #100790 and #106439. // Regression test for issues #100790 and #106439.
//@ run-rustfix //@ run-rustfix
#![allow(dead_code)]
pub struct Example pub struct Example
where where
(): Sized, (): Sized,
(#[allow(dead_code)] usize); (usize);
//~^^^ ERROR where clauses are not allowed before tuple struct bodies //~^^^ ERROR where clauses are not allowed before tuple struct bodies
struct _Demo struct _Demo

View File

@@ -1,23 +1,23 @@
error: where clauses are not allowed before tuple struct bodies error: where clauses are not allowed before tuple struct bodies
--> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:5:1 --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:7:1
| |
LL | pub struct Example LL | pub struct Example
| ------- while parsing this tuple struct | ------- while parsing this tuple struct
LL | / where LL | / where
LL | | (): Sized, LL | | (): Sized,
| |______________^ unexpected where clause | |______________^ unexpected where clause
LL | (#[allow(dead_code)] usize); LL | (usize);
| --------------------------- the struct body | ------- the struct body
| |
help: move the body before the where clause help: move the body before the where clause
| |
LL ~ pub struct Example(#[allow(dead_code)] usize) LL ~ pub struct Example(usize)
LL | where LL | where
LL ~ (): Sized; LL ~ (): Sized;
| |
error: where clauses are not allowed before tuple struct bodies error: where clauses are not allowed before tuple struct bodies
--> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:11:1 --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:13:1
| |
LL | struct _Demo LL | struct _Demo
| ----- while parsing this tuple struct | ----- while parsing this tuple struct