Skip to content

Commit 406fe7e

Browse files
committed
Rollup merge of rust-lang#34764 - pnkfelix:attrs-on-generic-formals, r=eddyb
First step for rust-lang#34761
2 parents 259d1fc + 3a9b7be commit 406fe7e

14 files changed

+389
-14
lines changed

src/libsyntax/ast.rs

+2
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ impl fmt::Debug for Lifetime {
121121
/// A lifetime definition, e.g. `'a: 'b+'c+'d`
122122
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
123123
pub struct LifetimeDef {
124+
pub attrs: ThinVec<Attribute>,
124125
pub lifetime: Lifetime,
125126
pub bounds: Vec<Lifetime>
126127
}
@@ -370,6 +371,7 @@ pub type TyParamBounds = P<[TyParamBound]>;
370371

371372
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
372373
pub struct TyParam {
374+
pub attrs: ThinVec<Attribute>,
373375
pub ident: Ident,
374376
pub id: NodeId,
375377
pub bounds: TyParamBounds,

src/libsyntax/ext/build.rs

+6
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ pub trait AstBuilder {
7373
fn typaram(&self,
7474
span: Span,
7575
id: ast::Ident,
76+
attrs: Vec<ast::Attribute>,
7677
bounds: ast::TyParamBounds,
7778
default: Option<P<ast::Ty>>) -> ast::TyParam;
7879

@@ -83,6 +84,7 @@ pub trait AstBuilder {
8384
fn lifetime_def(&self,
8485
span: Span,
8586
name: ast::Name,
87+
attrs: Vec<ast::Attribute>,
8688
bounds: Vec<ast::Lifetime>)
8789
-> ast::LifetimeDef;
8890

@@ -452,11 +454,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
452454
fn typaram(&self,
453455
span: Span,
454456
id: ast::Ident,
457+
attrs: Vec<ast::Attribute>,
455458
bounds: ast::TyParamBounds,
456459
default: Option<P<ast::Ty>>) -> ast::TyParam {
457460
ast::TyParam {
458461
ident: id,
459462
id: ast::DUMMY_NODE_ID,
463+
attrs: attrs.into(),
460464
bounds: bounds,
461465
default: default,
462466
span: span
@@ -503,9 +507,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
503507
fn lifetime_def(&self,
504508
span: Span,
505509
name: ast::Name,
510+
attrs: Vec<ast::Attribute>,
506511
bounds: Vec<ast::Lifetime>)
507512
-> ast::LifetimeDef {
508513
ast::LifetimeDef {
514+
attrs: attrs.into(),
509515
lifetime: self.lifetime(span, name),
510516
bounds: bounds
511517
}

src/libsyntax/feature_gate.rs

+21
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,9 @@ declare_features! (
303303
// Used to identify the `compiler_builtins` crate
304304
// rustc internal
305305
(active, compiler_builtins, "1.13.0", None),
306+
307+
// Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
308+
(active, generic_param_attrs, "1.11.0", Some(34761)),
306309
);
307310

308311
declare_features! (
@@ -1220,6 +1223,24 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
12201223

12211224
visit::walk_vis(self, vis)
12221225
}
1226+
1227+
fn visit_generics(&mut self, g: &ast::Generics) {
1228+
for t in &g.ty_params {
1229+
if !t.attrs.is_empty() {
1230+
gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
1231+
"attributes on type parameter bindings are experimental");
1232+
}
1233+
}
1234+
visit::walk_generics(self, g)
1235+
}
1236+
1237+
fn visit_lifetime_def(&mut self, lifetime_def: &ast::LifetimeDef) {
1238+
if !lifetime_def.attrs.is_empty() {
1239+
gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
1240+
"attributes on lifetime bindings are experimental");
1241+
}
1242+
visit::walk_lifetime_def(self, lifetime_def)
1243+
}
12231244
}
12241245

12251246
pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {

src/libsyntax/fold.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -662,8 +662,13 @@ pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T)
662662
}
663663

664664
pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
665-
let TyParam {id, ident, bounds, default, span} = tp;
665+
let TyParam {attrs, id, ident, bounds, default, span} = tp;
666+
let attrs: Vec<_> = attrs.into();
666667
TyParam {
668+
attrs: attrs.into_iter()
669+
.flat_map(|x| fld.fold_attribute(x).into_iter())
670+
.collect::<Vec<_>>()
671+
.into(),
667672
id: fld.new_id(id),
668673
ident: ident,
669674
bounds: fld.fold_bounds(bounds),
@@ -687,7 +692,12 @@ pub fn noop_fold_lifetime<T: Folder>(l: Lifetime, fld: &mut T) -> Lifetime {
687692

688693
pub fn noop_fold_lifetime_def<T: Folder>(l: LifetimeDef, fld: &mut T)
689694
-> LifetimeDef {
695+
let attrs: Vec<_> = l.attrs.into();
690696
LifetimeDef {
697+
attrs: attrs.into_iter()
698+
.flat_map(|x| fld.fold_attribute(x).into_iter())
699+
.collect::<Vec<_>>()
700+
.into(),
691701
lifetime: fld.fold_lifetime(l.lifetime),
692702
bounds: fld.fold_lifetimes(l.bounds),
693703
}

src/libsyntax/parse/parser.rs

+53-9
Original file line numberDiff line numberDiff line change
@@ -1179,7 +1179,7 @@ impl<'a> Parser<'a> {
11791179
let lo = self.span.lo;
11801180

11811181
let (name, node) = if self.eat_keyword(keywords::Type) {
1182-
let TyParam {ident, bounds, default, ..} = self.parse_ty_param()?;
1182+
let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?;
11831183
self.expect(&token::Semi)?;
11841184
(ident, TraitItemKind::Type(bounds, default))
11851185
} else if self.is_const_item() {
@@ -1910,10 +1910,22 @@ impl<'a> Parser<'a> {
19101910

19111911
/// Parses `lifetime_defs = [ lifetime_defs { ',' lifetime_defs } ]` where `lifetime_def =
19121912
/// lifetime [':' lifetimes]`
1913-
pub fn parse_lifetime_defs(&mut self) -> PResult<'a, Vec<ast::LifetimeDef>> {
1914-
1913+
///
1914+
/// If `followed_by_ty_params` is None, then we are in a context
1915+
/// where only lifetime parameters are allowed, and thus we should
1916+
/// error if we encounter attributes after the bound lifetimes.
1917+
///
1918+
/// If `followed_by_ty_params` is Some(r), then there may be type
1919+
/// parameter bindings after the lifetimes, so we should pass
1920+
/// along the parsed attributes to be attached to the first such
1921+
/// type parmeter.
1922+
pub fn parse_lifetime_defs(&mut self,
1923+
followed_by_ty_params: Option<&mut Vec<ast::Attribute>>)
1924+
-> PResult<'a, Vec<ast::LifetimeDef>>
1925+
{
19151926
let mut res = Vec::new();
19161927
loop {
1928+
let attrs = self.parse_outer_attributes()?;
19171929
match self.token {
19181930
token::Lifetime(_) => {
19191931
let lifetime = self.parse_lifetime()?;
@@ -1923,11 +1935,20 @@ impl<'a> Parser<'a> {
19231935
} else {
19241936
Vec::new()
19251937
};
1926-
res.push(ast::LifetimeDef { lifetime: lifetime,
1938+
res.push(ast::LifetimeDef { attrs: attrs.into(),
1939+
lifetime: lifetime,
19271940
bounds: bounds });
19281941
}
19291942

19301943
_ => {
1944+
if let Some(recv) = followed_by_ty_params {
1945+
assert!(recv.is_empty());
1946+
*recv = attrs;
1947+
} else {
1948+
let msg = "trailing attribute after lifetime parameters";
1949+
return Err(self.fatal(msg));
1950+
}
1951+
debug!("parse_lifetime_defs ret {:?}", res);
19311952
return Ok(res);
19321953
}
19331954
}
@@ -4228,7 +4249,7 @@ impl<'a> Parser<'a> {
42284249
}
42294250

42304251
/// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?
4231-
fn parse_ty_param(&mut self) -> PResult<'a, TyParam> {
4252+
fn parse_ty_param(&mut self, preceding_attrs: Vec<ast::Attribute>) -> PResult<'a, TyParam> {
42324253
let span = self.span;
42334254
let ident = self.parse_ident()?;
42344255

@@ -4242,6 +4263,7 @@ impl<'a> Parser<'a> {
42424263
};
42434264

42444265
Ok(TyParam {
4266+
attrs: preceding_attrs.into(),
42454267
ident: ident,
42464268
id: ast::DUMMY_NODE_ID,
42474269
bounds: bounds,
@@ -4262,11 +4284,27 @@ impl<'a> Parser<'a> {
42624284
let span_lo = self.span.lo;
42634285

42644286
if self.eat(&token::Lt) {
4265-
let lifetime_defs = self.parse_lifetime_defs()?;
4287+
// Upon encountering attribute in generics list, we do not
4288+
// know if it is attached to lifetime or to type param.
4289+
//
4290+
// Solution: 1. eagerly parse attributes in tandem with
4291+
// lifetime defs, 2. store last set of parsed (and unused)
4292+
// attributes in `attrs`, and 3. pass in those attributes
4293+
// when parsing formal type param after lifetime defs.
4294+
let mut attrs = vec![];
4295+
let lifetime_defs = self.parse_lifetime_defs(Some(&mut attrs))?;
42664296
let mut seen_default = false;
4297+
let mut post_lifetime_attrs = Some(attrs);
42674298
let ty_params = self.parse_seq_to_gt(Some(token::Comma), |p| {
42684299
p.forbid_lifetime()?;
4269-
let ty_param = p.parse_ty_param()?;
4300+
// Move out of `post_lifetime_attrs` if present. O/w
4301+
// not first type param: parse attributes anew.
4302+
let attrs = match post_lifetime_attrs.as_mut() {
4303+
None => p.parse_outer_attributes()?,
4304+
Some(attrs) => mem::replace(attrs, vec![]),
4305+
};
4306+
post_lifetime_attrs = None;
4307+
let ty_param = p.parse_ty_param(attrs)?;
42704308
if ty_param.default.is_some() {
42714309
seen_default = true;
42724310
} else if seen_default {
@@ -4276,6 +4314,12 @@ impl<'a> Parser<'a> {
42764314
}
42774315
Ok(ty_param)
42784316
})?;
4317+
if let Some(attrs) = post_lifetime_attrs {
4318+
if !attrs.is_empty() {
4319+
self.span_err(attrs[0].span,
4320+
"trailing attribute after lifetime parameters");
4321+
}
4322+
}
42794323
Ok(ast::Generics {
42804324
lifetimes: lifetime_defs,
42814325
ty_params: ty_params,
@@ -4423,7 +4467,7 @@ impl<'a> Parser<'a> {
44234467
let bound_lifetimes = if self.eat_keyword(keywords::For) {
44244468
// Higher ranked constraint.
44254469
self.expect(&token::Lt)?;
4426-
let lifetime_defs = self.parse_lifetime_defs()?;
4470+
let lifetime_defs = self.parse_lifetime_defs(None)?;
44274471
self.expect_gt()?;
44284472
lifetime_defs
44294473
} else {
@@ -4991,7 +5035,7 @@ impl<'a> Parser<'a> {
49915035
fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<ast::LifetimeDef>> {
49925036
if self.eat_keyword(keywords::For) {
49935037
self.expect(&token::Lt)?;
4994-
let lifetime_defs = self.parse_lifetime_defs()?;
5038+
let lifetime_defs = self.parse_lifetime_defs(None)?;
49955039
self.expect_gt()?;
49965040
Ok(lifetime_defs)
49975041
} else {

src/libsyntax/visit.rs

+2
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ pub fn walk_lifetime<V: Visitor>(visitor: &mut V, lifetime: &Lifetime) {
201201
pub fn walk_lifetime_def<V: Visitor>(visitor: &mut V, lifetime_def: &LifetimeDef) {
202202
visitor.visit_lifetime(&lifetime_def.lifetime);
203203
walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
204+
walk_list!(visitor, visit_attribute, &*lifetime_def.attrs);
204205
}
205206

206207
pub fn walk_poly_trait_ref<V>(visitor: &mut V, trait_ref: &PolyTraitRef, _: &TraitBoundModifier)
@@ -474,6 +475,7 @@ pub fn walk_generics<V: Visitor>(visitor: &mut V, generics: &Generics) {
474475
visitor.visit_ident(param.span, param.ident);
475476
walk_list!(visitor, visit_ty_param_bound, &param.bounds);
476477
walk_list!(visitor, visit_ty, &param.default);
478+
walk_list!(visitor, visit_attribute, &*param.attrs);
477479
}
478480
walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
479481
for predicate in &generics.where_clause.predicates {

src/libsyntax_ext/deriving/generic/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ impl<'a> TraitDef<'a> {
536536
bounds.push((*declared_bound).clone());
537537
}
538538

539-
cx.typaram(self.span, ty_param.ident, P::from_vec(bounds), None)
539+
cx.typaram(self.span, ty_param.ident, vec![], P::from_vec(bounds), None)
540540
}));
541541

542542
// and similarly for where clauses

src/libsyntax_ext/deriving/generic/ty.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ impl<'a> Ty<'a> {
194194
fn mk_ty_param(cx: &ExtCtxt,
195195
span: Span,
196196
name: &str,
197+
attrs: &[ast::Attribute],
197198
bounds: &[Path],
198199
self_ident: Ident,
199200
self_generics: &Generics)
@@ -204,7 +205,7 @@ fn mk_ty_param(cx: &ExtCtxt,
204205
cx.typarambound(path)
205206
})
206207
.collect();
207-
cx.typaram(span, cx.ident_of(name), bounds, None)
208+
cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None)
208209
}
209210

210211
fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>, span: Span)
@@ -246,15 +247,15 @@ impl<'a> LifetimeBounds<'a> {
246247
let bounds = bounds.iter()
247248
.map(|b| cx.lifetime(span, cx.ident_of(*b).name))
248249
.collect();
249-
cx.lifetime_def(span, cx.ident_of(*lt).name, bounds)
250+
cx.lifetime_def(span, cx.ident_of(*lt).name, vec![], bounds)
250251
})
251252
.collect();
252253
let ty_params = self.bounds
253254
.iter()
254255
.map(|t| {
255256
match *t {
256257
(ref name, ref bounds) => {
257-
mk_ty_param(cx, span, *name, bounds, self_ty, self_generics)
258+
mk_ty_param(cx, span, *name, &[], bounds, self_ty, self_generics)
258259
}
259260
}
260261
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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 ensures that attributes on formals in generic parameter
12+
// lists are included when we are checking for unstable attributes.
13+
//
14+
// Note that feature(generic_param_attrs) *is* enabled here. We are
15+
// checking feature-gating of the attributes themselves, not the
16+
// capability to parse such attributes in that context.
17+
18+
#![feature(generic_param_attrs)]
19+
#![allow(dead_code)]
20+
21+
struct StLt<#[lt_struct] 'a>(&'a u32);
22+
//~^ ERROR The attribute `lt_struct` is currently unknown to the compiler
23+
struct StTy<#[ty_struct] I>(I);
24+
//~^ ERROR The attribute `ty_struct` is currently unknown to the compiler
25+
26+
enum EnLt<#[lt_enum] 'b> { A(&'b u32), B }
27+
//~^ ERROR The attribute `lt_enum` is currently unknown to the compiler
28+
enum EnTy<#[ty_enum] J> { A(J), B }
29+
//~^ ERROR The attribute `ty_enum` is currently unknown to the compiler
30+
31+
trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
32+
//~^ ERROR The attribute `lt_trait` is currently unknown to the compiler
33+
trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); }
34+
//~^ ERROR The attribute `ty_trait` is currently unknown to the compiler
35+
36+
type TyLt<#[lt_type] 'd> = &'d u32;
37+
//~^ ERROR The attribute `lt_type` is currently unknown to the compiler
38+
type TyTy<#[ty_type] L> = (L, );
39+
//~^ ERROR The attribute `ty_type` is currently unknown to the compiler
40+
41+
impl<#[lt_inherent] 'e> StLt<'e> { }
42+
//~^ ERROR The attribute `lt_inherent` is currently unknown to the compiler
43+
impl<#[ty_inherent] M> StTy<M> { }
44+
//~^ ERROR The attribute `ty_inherent` is currently unknown to the compiler
45+
46+
impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
47+
//~^ ERROR The attribute `lt_impl_for` is currently unknown to the compiler
48+
fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } }
49+
}
50+
impl<#[ty_impl_for] N> TrTy<N> for StTy<N> {
51+
//~^ ERROR The attribute `ty_impl_for` is currently unknown to the compiler
52+
fn foo(&self, _: N) { }
53+
}
54+
55+
fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
56+
//~^ ERROR The attribute `lt_fn` is currently unknown to the compiler
57+
fn f_ty<#[ty_fn] O>(_: O) { }
58+
//~^ ERROR The attribute `ty_fn` is currently unknown to the compiler
59+
60+
impl<I> StTy<I> {
61+
fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
62+
//~^ ERROR The attribute `lt_meth` is currently unknown to the compiler
63+
fn m_ty<#[ty_meth] P>(_: P) { }
64+
//~^ ERROR The attribute `ty_meth` is currently unknown to the compiler
65+
}
66+
67+
fn hof_lt<Q>(_: Q)
68+
where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
69+
//~^ ERROR The attribute `lt_hof` is currently unknown to the compiler
70+
{
71+
}
72+
73+
fn main() {
74+
75+
}

0 commit comments

Comments
 (0)