Added tests and fixed corner case for trailing attributes with no attached binding in generics.

This commit is contained in:
Felix S. Klock II 2016-07-11 18:29:45 +02:00
parent c242fc3ea3
commit 3a9b7be10b
4 changed files with 94 additions and 1 deletions

View File

@ -1958,7 +1958,7 @@ impl<'a> Parser<'a> {
assert!(recv.is_empty());
*recv = attrs;
} else {
let msg = "encountered trailing attributes after lifetime parameters";
let msg = "trailing attribute after lifetime parameters";
return Err(self.fatal(msg));
}
debug!("parse_lifetime_defs ret {:?}", res);
@ -4294,12 +4294,21 @@ impl<'a> Parser<'a> {
let span_lo = self.span.lo;
if self.eat(&token::Lt) {
// Upon encountering attribute in generics list, we do not
// know if it is attached to lifetime or to type param.
//
// Solution: 1. eagerly parse attributes in tandem with
// lifetime defs, 2. store last set of parsed (and unused)
// attributes in `attrs`, and 3. pass in those attributes
// when parsing formal type param after lifetime defs.
let mut attrs = vec![];
let lifetime_defs = self.parse_lifetime_defs(Some(&mut attrs))?;
let mut seen_default = false;
let mut post_lifetime_attrs = Some(attrs);
let ty_params = self.parse_seq_to_gt(Some(token::Comma), |p| {
p.forbid_lifetime()?;
// Move out of `post_lifetime_attrs` if present. O/w
// not first type param: parse attributes anew.
let attrs = match post_lifetime_attrs.as_mut() {
None => p.parse_outer_attributes()?,
Some(attrs) => mem::replace(attrs, vec![]),
@ -4315,6 +4324,12 @@ impl<'a> Parser<'a> {
}
Ok(ty_param)
})?;
if let Some(attrs) = post_lifetime_attrs {
if !attrs.is_empty() {
self.span_err(attrs[0].span,
"trailing attribute after lifetime parameters");
}
}
Ok(ast::Generics {
lifetimes: lifetime_defs,
ty_params: ty_params,

View File

@ -0,0 +1,26 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This test checks variations on `<#[attr] 'a, #[oops]>`, where
// `#[oops]` is left dangling (that is, it is unattached, with no
// formal binding following it).
#![feature(generic_param_attrs, rustc_attrs)]
#![allow(dead_code)]
struct RefIntPair<'a, 'b>(&'a u32, &'b u32);
impl<#[rustc_1] 'a, 'b, #[oops]> RefIntPair<'a, 'b> {
//~^ ERROR trailing attribute after lifetime parameters
}
fn main() {
}

View File

@ -0,0 +1,26 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This test checks variations on `<#[attr] 'a, #[oops]>`, where
// `#[oops]` is left dangling (that is, it is unattached, with no
// formal binding following it).
#![feature(generic_param_attrs, rustc_attrs)]
#![allow(dead_code)]
struct RefAny<'a, T>(&'a T);
impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> {
//~^ ERROR expected identifier, found `>`
}
fn main() {
}

View File

@ -0,0 +1,26 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This test checks variations on `<#[attr] 'a, #[oops]>`, where
// `#[oops]` is left dangling (that is, it is unattached, with no
// formal binding following it).
struct RefIntPair<'a, 'b>(&'a u32, &'b u32);
fn hof_lt<Q>(_: Q)
where Q: for <#[rustc_1] 'a, 'b, #[oops]> Fn(RefIntPair<'a,'b>) -> &'b u32
//~^ ERROR trailing attribute after lifetime parameters
{
}
fn main() {
}