Skip to content

Commit 3a9b7be

Browse files
committed
Added tests and fixed corner case for trailing attributes with no attached binding in generics.
1 parent c242fc3 commit 3a9b7be

4 files changed

+94
-1
lines changed

src/libsyntax/parse/parser.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -1958,7 +1958,7 @@ impl<'a> Parser<'a> {
19581958
assert!(recv.is_empty());
19591959
*recv = attrs;
19601960
} else {
1961-
let msg = "encountered trailing attributes after lifetime parameters";
1961+
let msg = "trailing attribute after lifetime parameters";
19621962
return Err(self.fatal(msg));
19631963
}
19641964
debug!("parse_lifetime_defs ret {:?}", res);
@@ -4294,12 +4294,21 @@ impl<'a> Parser<'a> {
42944294
let span_lo = self.span.lo;
42954295

42964296
if self.eat(&token::Lt) {
4297+
// Upon encountering attribute in generics list, we do not
4298+
// know if it is attached to lifetime or to type param.
4299+
//
4300+
// Solution: 1. eagerly parse attributes in tandem with
4301+
// lifetime defs, 2. store last set of parsed (and unused)
4302+
// attributes in `attrs`, and 3. pass in those attributes
4303+
// when parsing formal type param after lifetime defs.
42974304
let mut attrs = vec![];
42984305
let lifetime_defs = self.parse_lifetime_defs(Some(&mut attrs))?;
42994306
let mut seen_default = false;
43004307
let mut post_lifetime_attrs = Some(attrs);
43014308
let ty_params = self.parse_seq_to_gt(Some(token::Comma), |p| {
43024309
p.forbid_lifetime()?;
4310+
// Move out of `post_lifetime_attrs` if present. O/w
4311+
// not first type param: parse attributes anew.
43034312
let attrs = match post_lifetime_attrs.as_mut() {
43044313
None => p.parse_outer_attributes()?,
43054314
Some(attrs) => mem::replace(attrs, vec![]),
@@ -4315,6 +4324,12 @@ impl<'a> Parser<'a> {
43154324
}
43164325
Ok(ty_param)
43174326
})?;
4327+
if let Some(attrs) = post_lifetime_attrs {
4328+
if !attrs.is_empty() {
4329+
self.span_err(attrs[0].span,
4330+
"trailing attribute after lifetime parameters");
4331+
}
4332+
}
43184333
Ok(ast::Generics {
43194334
lifetimes: lifetime_defs,
43204335
ty_params: ty_params,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This test checks variations on `<#[attr] 'a, #[oops]>`, where
12+
// `#[oops]` is left dangling (that is, it is unattached, with no
13+
// formal binding following it).
14+
15+
#![feature(generic_param_attrs, rustc_attrs)]
16+
#![allow(dead_code)]
17+
18+
struct RefIntPair<'a, 'b>(&'a u32, &'b u32);
19+
20+
impl<#[rustc_1] 'a, 'b, #[oops]> RefIntPair<'a, 'b> {
21+
//~^ ERROR trailing attribute after lifetime parameters
22+
}
23+
24+
fn main() {
25+
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This test checks variations on `<#[attr] 'a, #[oops]>`, where
12+
// `#[oops]` is left dangling (that is, it is unattached, with no
13+
// formal binding following it).
14+
15+
#![feature(generic_param_attrs, rustc_attrs)]
16+
#![allow(dead_code)]
17+
18+
struct RefAny<'a, T>(&'a T);
19+
20+
impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> {
21+
//~^ ERROR expected identifier, found `>`
22+
}
23+
24+
fn main() {
25+
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This test checks variations on `<#[attr] 'a, #[oops]>`, where
12+
// `#[oops]` is left dangling (that is, it is unattached, with no
13+
// formal binding following it).
14+
15+
struct RefIntPair<'a, 'b>(&'a u32, &'b u32);
16+
17+
fn hof_lt<Q>(_: Q)
18+
where Q: for <#[rustc_1] 'a, 'b, #[oops]> Fn(RefIntPair<'a,'b>) -> &'b u32
19+
//~^ ERROR trailing attribute after lifetime parameters
20+
{
21+
22+
}
23+
24+
fn main() {
25+
26+
}

0 commit comments

Comments
 (0)