Skip to content

Commit 64afa26

Browse files
authored
Rollup merge of rust-lang#64894 - Centril:fix-64682, r=petrochenkov
syntax: fix dropping of attribute on first param of non-method assocated fn Fixes rust-lang#64682. The general idea is that we bake parsing of `self` into `parse_param_general` and then we just use standard list parsing. Overall, this simplifies the parsing and makes it more consistent. r? @petrochenkov cc @c410-f3r
2 parents 4ada68e + 8fd03b1 commit 64afa26

15 files changed

+391
-127
lines changed

src/libsyntax/parse/parser.rs

+23-50
Original file line numberDiff line numberDiff line change
@@ -974,15 +974,22 @@ impl<'a> Parser<'a> {
974974
/// This version of parse param doesn't necessarily require identifier names.
975975
fn parse_param_general(
976976
&mut self,
977+
is_self_allowed: bool,
977978
is_trait_item: bool,
978979
allow_c_variadic: bool,
979980
is_name_required: impl Fn(&token::Token) -> bool,
980981
) -> PResult<'a, Param> {
981982
let lo = self.token.span;
982983
let attrs = self.parse_outer_attributes()?;
984+
985+
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
983986
if let Some(mut param) = self.parse_self_param()? {
984987
param.attrs = attrs.into();
985-
return self.recover_bad_self_param(param, is_trait_item);
988+
return if is_self_allowed {
989+
Ok(param)
990+
} else {
991+
self.recover_bad_self_param(param, is_trait_item)
992+
};
986993
}
987994

988995
let is_name_required = is_name_required(&self.token);
@@ -1207,6 +1214,7 @@ impl<'a> Parser<'a> {
12071214
}
12081215
};
12091216
match p.parse_param_general(
1217+
false,
12101218
false,
12111219
allow_c_variadic,
12121220
do_not_enforce_named_arguments_for_c_variadic
@@ -1361,60 +1369,25 @@ impl<'a> Parser<'a> {
13611369
Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident)))
13621370
}
13631371

1364-
/// Returns the parsed optional self parameter with attributes and whether a self
1365-
/// shortcut was used.
1366-
fn parse_self_parameter_with_attrs(&mut self) -> PResult<'a, Option<Param>> {
1367-
let attrs = self.parse_outer_attributes()?;
1368-
let param_opt = self.parse_self_param()?;
1369-
Ok(param_opt.map(|mut param| {
1370-
param.attrs = attrs.into();
1371-
param
1372-
}))
1373-
}
1374-
13751372
/// Parses the parameter list and result type of a function that may have a `self` parameter.
1376-
fn parse_fn_decl_with_self<F>(&mut self, parse_param_fn: F) -> PResult<'a, P<FnDecl>>
1377-
where F: FnMut(&mut Parser<'a>) -> PResult<'a, Param>,
1378-
{
1379-
self.expect(&token::OpenDelim(token::Paren))?;
1380-
1381-
// Parse optional self argument.
1382-
let self_param = self.parse_self_parameter_with_attrs()?;
1383-
1384-
// Parse the rest of the function parameter list.
1385-
let sep = SeqSep::trailing_allowed(token::Comma);
1386-
let (mut fn_inputs, recovered) = if let Some(self_param) = self_param {
1387-
if self.check(&token::CloseDelim(token::Paren)) {
1388-
(vec![self_param], false)
1389-
} else if self.eat(&token::Comma) {
1390-
let mut fn_inputs = vec![self_param];
1391-
let (mut input, _, recovered) = self.parse_seq_to_before_end(
1392-
&token::CloseDelim(token::Paren), sep, parse_param_fn)?;
1393-
fn_inputs.append(&mut input);
1394-
(fn_inputs, recovered)
1395-
} else {
1396-
match self.expect_one_of(&[], &[]) {
1397-
Err(err) => return Err(err),
1398-
Ok(recovered) => (vec![self_param], recovered),
1399-
}
1400-
}
1401-
} else {
1402-
let (input, _, recovered) =
1403-
self.parse_seq_to_before_end(&token::CloseDelim(token::Paren),
1404-
sep,
1405-
parse_param_fn)?;
1406-
(input, recovered)
1407-
};
1373+
fn parse_fn_decl_with_self(
1374+
&mut self,
1375+
is_name_required: impl Copy + Fn(&token::Token) -> bool,
1376+
) -> PResult<'a, P<FnDecl>> {
1377+
// Parse the arguments, starting out with `self` being allowed...
1378+
let mut is_self_allowed = true;
1379+
let (mut inputs, _): (Vec<_>, _) = self.parse_paren_comma_seq(|p| {
1380+
let res = p.parse_param_general(is_self_allowed, true, false, is_name_required);
1381+
// ...but now that we've parsed the first argument, `self` is no longer allowed.
1382+
is_self_allowed = false;
1383+
res
1384+
})?;
14081385

1409-
if !recovered {
1410-
// Parse closing paren and return type.
1411-
self.expect(&token::CloseDelim(token::Paren))?;
1412-
}
14131386
// Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
1414-
self.deduplicate_recovered_params_names(&mut fn_inputs);
1387+
self.deduplicate_recovered_params_names(&mut inputs);
14151388

14161389
Ok(P(FnDecl {
1417-
inputs: fn_inputs,
1390+
inputs,
14181391
output: self.parse_ret_ty(true)?,
14191392
}))
14201393
}

src/libsyntax/parse/parser/item.rs

+18-26
Original file line numberDiff line numberDiff line change
@@ -424,13 +424,7 @@ impl<'a> Parser<'a> {
424424
} else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
425425
let ident = self.parse_ident().unwrap();
426426
self.bump(); // `(`
427-
let kw_name = if let Ok(Some(_)) = self.parse_self_parameter_with_attrs()
428-
.map_err(|mut e| e.cancel())
429-
{
430-
"method"
431-
} else {
432-
"function"
433-
};
427+
let kw_name = self.recover_first_param();
434428
self.consume_block(token::Paren);
435429
let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) {
436430
self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]);
@@ -477,13 +471,7 @@ impl<'a> Parser<'a> {
477471
self.eat_to_tokens(&[&token::Gt]);
478472
self.bump(); // `>`
479473
let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) {
480-
if let Ok(Some(_)) = self.parse_self_parameter_with_attrs()
481-
.map_err(|mut e| e.cancel())
482-
{
483-
("fn", "method", false)
484-
} else {
485-
("fn", "function", false)
486-
}
474+
("fn", self.recover_first_param(), false)
487475
} else if self.check(&token::OpenDelim(token::Brace)) {
488476
("struct", "struct", false)
489477
} else {
@@ -505,6 +493,16 @@ impl<'a> Parser<'a> {
505493
self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility)
506494
}
507495

496+
fn recover_first_param(&mut self) -> &'static str {
497+
match self.parse_outer_attributes()
498+
.and_then(|_| self.parse_self_param())
499+
.map_err(|mut e| e.cancel())
500+
{
501+
Ok(Some(_)) => "method",
502+
_ => "function",
503+
}
504+
}
505+
508506
/// This is the fall-through for parsing items.
509507
fn parse_macro_use_or_failure(
510508
&mut self,
@@ -861,9 +859,7 @@ impl<'a> Parser<'a> {
861859
let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
862860
let ident = self.parse_ident()?;
863861
let mut generics = self.parse_generics()?;
864-
let decl = self.parse_fn_decl_with_self(|p| {
865-
p.parse_param_general(true, false, |_| true)
866-
})?;
862+
let decl = self.parse_fn_decl_with_self(|_| true)?;
867863
generics.where_clause = self.parse_where_clause()?;
868864
*at_end = true;
869865
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
@@ -1034,15 +1030,11 @@ impl<'a> Parser<'a> {
10341030
let ident = self.parse_ident()?;
10351031
let mut generics = self.parse_generics()?;
10361032

1037-
let decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| {
1038-
// This is somewhat dubious; We don't want to allow
1039-
// argument names to be left off if there is a
1040-
// definition...
1041-
1042-
// We don't allow argument names to be left off in edition 2018.
1043-
let is_name_required = p.token.span.rust_2018();
1044-
p.parse_param_general(true, false, |_| is_name_required)
1045-
})?;
1033+
// This is somewhat dubious; We don't want to allow
1034+
// argument names to be left off if there is a definition...
1035+
//
1036+
// We don't allow argument names to be left off in edition 2018.
1037+
let decl = self.parse_fn_decl_with_self(|t| t.span.rust_2018())?;
10461038
generics.where_clause = self.parse_where_clause()?;
10471039

10481040
let sig = ast::MethodSig {

src/test/ui/lint/lint-unused-variables.rs

+15
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ impl RefStruct {
2929
b: i32,
3030
//~^ ERROR unused variable: `b`
3131
) {}
32+
fn issue_64682_associated_fn(
33+
#[allow(unused_variables)] a: i32,
34+
b: i32,
35+
//~^ ERROR unused variable: `b`
36+
) {}
3237
}
3338
trait RefTrait {
3439
fn bar(
@@ -37,6 +42,11 @@ trait RefTrait {
3742
b: i32,
3843
//~^ ERROR unused variable: `b`
3944
) {}
45+
fn issue_64682_associated_fn(
46+
#[allow(unused_variables)] a: i32,
47+
b: i32,
48+
//~^ ERROR unused variable: `b`
49+
) {}
4050
}
4151
impl RefTrait for RefStruct {
4252
fn bar(
@@ -45,6 +55,11 @@ impl RefTrait for RefStruct {
4555
b: i32,
4656
//~^ ERROR unused variable: `b`
4757
) {}
58+
fn issue_64682_associated_fn(
59+
#[allow(unused_variables)] a: i32,
60+
b: i32,
61+
//~^ ERROR unused variable: `b`
62+
) {}
4863
}
4964

5065
fn main() {

src/test/ui/lint/lint-unused-variables.stderr

+23-5
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,25 @@ LL | b: i32,
1717
| ^ help: consider prefixing with an underscore: `_b`
1818

1919
error: unused variable: `a`
20-
--> $DIR/lint-unused-variables.rs:53:9
20+
--> $DIR/lint-unused-variables.rs:68:9
2121
|
2222
LL | a: i32,
2323
| ^ help: consider prefixing with an underscore: `_a`
2424

2525
error: unused variable: `b`
26-
--> $DIR/lint-unused-variables.rs:59:9
26+
--> $DIR/lint-unused-variables.rs:74:9
2727
|
2828
LL | b: i32,
2929
| ^ help: consider prefixing with an underscore: `_b`
3030

3131
error: unused variable: `b`
32-
--> $DIR/lint-unused-variables.rs:37:9
32+
--> $DIR/lint-unused-variables.rs:42:9
33+
|
34+
LL | b: i32,
35+
| ^ help: consider prefixing with an underscore: `_b`
36+
37+
error: unused variable: `b`
38+
--> $DIR/lint-unused-variables.rs:47:9
3339
|
3440
LL | b: i32,
3541
| ^ help: consider prefixing with an underscore: `_b`
@@ -47,10 +53,22 @@ LL | b: i32,
4753
| ^ help: consider prefixing with an underscore: `_b`
4854

4955
error: unused variable: `b`
50-
--> $DIR/lint-unused-variables.rs:45:9
56+
--> $DIR/lint-unused-variables.rs:34:9
57+
|
58+
LL | b: i32,
59+
| ^ help: consider prefixing with an underscore: `_b`
60+
61+
error: unused variable: `b`
62+
--> $DIR/lint-unused-variables.rs:55:9
63+
|
64+
LL | b: i32,
65+
| ^ help: consider prefixing with an underscore: `_b`
66+
67+
error: unused variable: `b`
68+
--> $DIR/lint-unused-variables.rs:60:9
5169
|
5270
LL | b: i32,
5371
| ^ help: consider prefixing with an underscore: `_b`
5472

55-
error: aborting due to 8 previous errors
73+
error: aborting due to 11 previous errors
5674

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#[cfg(FALSE)]
2+
impl S {
3+
fn f(#[attr]) {} //~ ERROR expected parameter name, found `)`
4+
}
5+
6+
#[cfg(FALSE)]
7+
impl T for S {
8+
fn f(#[attr]) {} //~ ERROR expected parameter name, found `)`
9+
}
10+
11+
#[cfg(FALSE)]
12+
trait T {
13+
fn f(#[attr]); //~ ERROR expected argument name, found `)`
14+
}
15+
16+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: expected parameter name, found `)`
2+
--> $DIR/attr-without-param.rs:3:17
3+
|
4+
LL | fn f(#[attr]) {}
5+
| ^ expected parameter name
6+
7+
error: expected parameter name, found `)`
8+
--> $DIR/attr-without-param.rs:8:17
9+
|
10+
LL | fn f(#[attr]) {}
11+
| ^ expected parameter name
12+
13+
error: expected argument name, found `)`
14+
--> $DIR/attr-without-param.rs:13:17
15+
|
16+
LL | fn f(#[attr]);
17+
| ^ expected argument name
18+
19+
error: aborting due to 3 previous errors
20+

src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ macro_rules! checker {
1111
($attr_name:ident, $expected:literal) => {
1212
#[proc_macro_attribute]
1313
pub fn $attr_name(attr: TokenStream, input: TokenStream) -> TokenStream {
14-
assert!(attr.to_string().is_empty());
1514
assert_eq!(input.to_string(), $expected);
1615
TokenStream::new()
1716
}
@@ -28,7 +27,18 @@ checker!(attr_inherent_1, "fn inherent1(#[a1] self, #[a2] arg1: u8) { }");
2827
checker!(attr_inherent_2, "fn inherent2(#[a1] &self, #[a2] arg1: u8) { }");
2928
checker!(attr_inherent_3, "fn inherent3<'a>(#[a1] &'a mut self, #[a2] arg1: u8) { }");
3029
checker!(attr_inherent_4, "fn inherent4<'a>(#[a1] self: Box<Self>, #[a2] arg1: u8) { }");
30+
checker!(attr_inherent_issue_64682, "fn inherent5(#[a1] #[a2] arg1: u8, #[a3] arg2: u8) { }");
3131
checker!(attr_trait_1, "fn trait1(#[a1] self, #[a2] arg1: u8);");
3232
checker!(attr_trait_2, "fn trait2(#[a1] &self, #[a2] arg1: u8);");
3333
checker!(attr_trait_3, "fn trait3<'a>(#[a1] &'a mut self, #[a2] arg1: u8);");
3434
checker!(attr_trait_4, "fn trait4<'a>(#[a1] self: Box<Self>, #[a2] arg1: u8, #[a3] Vec<u8>);");
35+
checker!(attr_trait_issue_64682, "fn trait5(#[a1] #[a2] arg1: u8, #[a3] arg2: u8);");
36+
checker!(rename_params, r#"impl Foo {
37+
fn hello(#[angery(true)] a: i32, #[a2] b: i32, #[what = "how"] c: u32) { }
38+
fn hello2(#[a1] #[a2] a: i32, #[what = "how"] b: i32,
39+
#[angery(true)] c: u32) {
40+
}
41+
fn hello_self(#[a1] #[a2] &self, #[a1] #[a2] a: i32,
42+
#[what = "how"] b: i32, #[angery(true)] c: u32) {
43+
}
44+
}"#);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// aux-build:param-attrs.rs
2+
3+
// check-pass
4+
5+
extern crate param_attrs;
6+
7+
use param_attrs::rename_params;
8+
9+
#[rename_params(send_help)]
10+
impl Foo {
11+
fn hello(#[angery(true)] a: i32, #[a2] b: i32, #[what = "how"] c: u32) {}
12+
fn hello2(#[a1] #[a2] a: i32, #[what = "how"] b: i32, #[angery(true)] c: u32) {}
13+
fn hello_self(
14+
#[a1] #[a2] &self,
15+
#[a1] #[a2] a: i32,
16+
#[what = "how"] b: i32,
17+
#[angery(true)] c: u32
18+
) {}
19+
}
20+
21+
fn main() {}

0 commit comments

Comments
 (0)