Rollup merge of #34764 - pnkfelix:attrs-on-generic-formals, r=eddyb
First step for #34761
This commit is contained in:
commit
406fe7e3c2
@ -121,6 +121,7 @@ impl fmt::Debug for Lifetime {
|
||||
/// A lifetime definition, e.g. `'a: 'b+'c+'d`
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub struct LifetimeDef {
|
||||
pub attrs: ThinVec<Attribute>,
|
||||
pub lifetime: Lifetime,
|
||||
pub bounds: Vec<Lifetime>
|
||||
}
|
||||
@ -370,6 +371,7 @@ pub type TyParamBounds = P<[TyParamBound]>;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub struct TyParam {
|
||||
pub attrs: ThinVec<Attribute>,
|
||||
pub ident: Ident,
|
||||
pub id: NodeId,
|
||||
pub bounds: TyParamBounds,
|
||||
|
@ -73,6 +73,7 @@ pub trait AstBuilder {
|
||||
fn typaram(&self,
|
||||
span: Span,
|
||||
id: ast::Ident,
|
||||
attrs: Vec<ast::Attribute>,
|
||||
bounds: ast::TyParamBounds,
|
||||
default: Option<P<ast::Ty>>) -> ast::TyParam;
|
||||
|
||||
@ -83,6 +84,7 @@ pub trait AstBuilder {
|
||||
fn lifetime_def(&self,
|
||||
span: Span,
|
||||
name: ast::Name,
|
||||
attrs: Vec<ast::Attribute>,
|
||||
bounds: Vec<ast::Lifetime>)
|
||||
-> ast::LifetimeDef;
|
||||
|
||||
@ -452,11 +454,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||
fn typaram(&self,
|
||||
span: Span,
|
||||
id: ast::Ident,
|
||||
attrs: Vec<ast::Attribute>,
|
||||
bounds: ast::TyParamBounds,
|
||||
default: Option<P<ast::Ty>>) -> ast::TyParam {
|
||||
ast::TyParam {
|
||||
ident: id,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
attrs: attrs.into(),
|
||||
bounds: bounds,
|
||||
default: default,
|
||||
span: span
|
||||
@ -503,9 +507,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||
fn lifetime_def(&self,
|
||||
span: Span,
|
||||
name: ast::Name,
|
||||
attrs: Vec<ast::Attribute>,
|
||||
bounds: Vec<ast::Lifetime>)
|
||||
-> ast::LifetimeDef {
|
||||
ast::LifetimeDef {
|
||||
attrs: attrs.into(),
|
||||
lifetime: self.lifetime(span, name),
|
||||
bounds: bounds
|
||||
}
|
||||
|
@ -303,6 +303,9 @@ declare_features! (
|
||||
// Used to identify the `compiler_builtins` crate
|
||||
// rustc internal
|
||||
(active, compiler_builtins, "1.13.0", None),
|
||||
|
||||
// Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
|
||||
(active, generic_param_attrs, "1.11.0", Some(34761)),
|
||||
);
|
||||
|
||||
declare_features! (
|
||||
@ -1220,6 +1223,24 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
|
||||
|
||||
visit::walk_vis(self, vis)
|
||||
}
|
||||
|
||||
fn visit_generics(&mut self, g: &ast::Generics) {
|
||||
for t in &g.ty_params {
|
||||
if !t.attrs.is_empty() {
|
||||
gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
|
||||
"attributes on type parameter bindings are experimental");
|
||||
}
|
||||
}
|
||||
visit::walk_generics(self, g)
|
||||
}
|
||||
|
||||
fn visit_lifetime_def(&mut self, lifetime_def: &ast::LifetimeDef) {
|
||||
if !lifetime_def.attrs.is_empty() {
|
||||
gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
|
||||
"attributes on lifetime bindings are experimental");
|
||||
}
|
||||
visit::walk_lifetime_def(self, lifetime_def)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
|
||||
|
@ -662,8 +662,13 @@ pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T)
|
||||
}
|
||||
|
||||
pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
|
||||
let TyParam {id, ident, bounds, default, span} = tp;
|
||||
let TyParam {attrs, id, ident, bounds, default, span} = tp;
|
||||
let attrs: Vec<_> = attrs.into();
|
||||
TyParam {
|
||||
attrs: attrs.into_iter()
|
||||
.flat_map(|x| fld.fold_attribute(x).into_iter())
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
id: fld.new_id(id),
|
||||
ident: ident,
|
||||
bounds: fld.fold_bounds(bounds),
|
||||
@ -687,7 +692,12 @@ pub fn noop_fold_lifetime<T: Folder>(l: Lifetime, fld: &mut T) -> Lifetime {
|
||||
|
||||
pub fn noop_fold_lifetime_def<T: Folder>(l: LifetimeDef, fld: &mut T)
|
||||
-> LifetimeDef {
|
||||
let attrs: Vec<_> = l.attrs.into();
|
||||
LifetimeDef {
|
||||
attrs: attrs.into_iter()
|
||||
.flat_map(|x| fld.fold_attribute(x).into_iter())
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
lifetime: fld.fold_lifetime(l.lifetime),
|
||||
bounds: fld.fold_lifetimes(l.bounds),
|
||||
}
|
||||
|
@ -1179,7 +1179,7 @@ impl<'a> Parser<'a> {
|
||||
let lo = self.span.lo;
|
||||
|
||||
let (name, node) = if self.eat_keyword(keywords::Type) {
|
||||
let TyParam {ident, bounds, default, ..} = self.parse_ty_param()?;
|
||||
let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?;
|
||||
self.expect(&token::Semi)?;
|
||||
(ident, TraitItemKind::Type(bounds, default))
|
||||
} else if self.is_const_item() {
|
||||
@ -1910,10 +1910,22 @@ impl<'a> Parser<'a> {
|
||||
|
||||
/// Parses `lifetime_defs = [ lifetime_defs { ',' lifetime_defs } ]` where `lifetime_def =
|
||||
/// lifetime [':' lifetimes]`
|
||||
pub fn parse_lifetime_defs(&mut self) -> PResult<'a, Vec<ast::LifetimeDef>> {
|
||||
|
||||
///
|
||||
/// If `followed_by_ty_params` is None, then we are in a context
|
||||
/// where only lifetime parameters are allowed, and thus we should
|
||||
/// error if we encounter attributes after the bound lifetimes.
|
||||
///
|
||||
/// If `followed_by_ty_params` is Some(r), then there may be type
|
||||
/// parameter bindings after the lifetimes, so we should pass
|
||||
/// along the parsed attributes to be attached to the first such
|
||||
/// type parmeter.
|
||||
pub fn parse_lifetime_defs(&mut self,
|
||||
followed_by_ty_params: Option<&mut Vec<ast::Attribute>>)
|
||||
-> PResult<'a, Vec<ast::LifetimeDef>>
|
||||
{
|
||||
let mut res = Vec::new();
|
||||
loop {
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
match self.token {
|
||||
token::Lifetime(_) => {
|
||||
let lifetime = self.parse_lifetime()?;
|
||||
@ -1923,11 +1935,20 @@ impl<'a> Parser<'a> {
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
res.push(ast::LifetimeDef { lifetime: lifetime,
|
||||
res.push(ast::LifetimeDef { attrs: attrs.into(),
|
||||
lifetime: lifetime,
|
||||
bounds: bounds });
|
||||
}
|
||||
|
||||
_ => {
|
||||
if let Some(recv) = followed_by_ty_params {
|
||||
assert!(recv.is_empty());
|
||||
*recv = attrs;
|
||||
} else {
|
||||
let msg = "trailing attribute after lifetime parameters";
|
||||
return Err(self.fatal(msg));
|
||||
}
|
||||
debug!("parse_lifetime_defs ret {:?}", res);
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
@ -4228,7 +4249,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
/// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?
|
||||
fn parse_ty_param(&mut self) -> PResult<'a, TyParam> {
|
||||
fn parse_ty_param(&mut self, preceding_attrs: Vec<ast::Attribute>) -> PResult<'a, TyParam> {
|
||||
let span = self.span;
|
||||
let ident = self.parse_ident()?;
|
||||
|
||||
@ -4242,6 +4263,7 @@ impl<'a> Parser<'a> {
|
||||
};
|
||||
|
||||
Ok(TyParam {
|
||||
attrs: preceding_attrs.into(),
|
||||
ident: ident,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
bounds: bounds,
|
||||
@ -4262,11 +4284,27 @@ impl<'a> Parser<'a> {
|
||||
let span_lo = self.span.lo;
|
||||
|
||||
if self.eat(&token::Lt) {
|
||||
let lifetime_defs = self.parse_lifetime_defs()?;
|
||||
// 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()?;
|
||||
let ty_param = p.parse_ty_param()?;
|
||||
// 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![]),
|
||||
};
|
||||
post_lifetime_attrs = None;
|
||||
let ty_param = p.parse_ty_param(attrs)?;
|
||||
if ty_param.default.is_some() {
|
||||
seen_default = true;
|
||||
} else if seen_default {
|
||||
@ -4276,6 +4314,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,
|
||||
@ -4423,7 +4467,7 @@ impl<'a> Parser<'a> {
|
||||
let bound_lifetimes = if self.eat_keyword(keywords::For) {
|
||||
// Higher ranked constraint.
|
||||
self.expect(&token::Lt)?;
|
||||
let lifetime_defs = self.parse_lifetime_defs()?;
|
||||
let lifetime_defs = self.parse_lifetime_defs(None)?;
|
||||
self.expect_gt()?;
|
||||
lifetime_defs
|
||||
} else {
|
||||
@ -4991,7 +5035,7 @@ impl<'a> Parser<'a> {
|
||||
fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<ast::LifetimeDef>> {
|
||||
if self.eat_keyword(keywords::For) {
|
||||
self.expect(&token::Lt)?;
|
||||
let lifetime_defs = self.parse_lifetime_defs()?;
|
||||
let lifetime_defs = self.parse_lifetime_defs(None)?;
|
||||
self.expect_gt()?;
|
||||
Ok(lifetime_defs)
|
||||
} else {
|
||||
|
@ -201,6 +201,7 @@ pub fn walk_lifetime<V: Visitor>(visitor: &mut V, lifetime: &Lifetime) {
|
||||
pub fn walk_lifetime_def<V: Visitor>(visitor: &mut V, lifetime_def: &LifetimeDef) {
|
||||
visitor.visit_lifetime(&lifetime_def.lifetime);
|
||||
walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
|
||||
walk_list!(visitor, visit_attribute, &*lifetime_def.attrs);
|
||||
}
|
||||
|
||||
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) {
|
||||
visitor.visit_ident(param.span, param.ident);
|
||||
walk_list!(visitor, visit_ty_param_bound, ¶m.bounds);
|
||||
walk_list!(visitor, visit_ty, ¶m.default);
|
||||
walk_list!(visitor, visit_attribute, &*param.attrs);
|
||||
}
|
||||
walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
|
||||
for predicate in &generics.where_clause.predicates {
|
||||
|
@ -536,7 +536,7 @@ impl<'a> TraitDef<'a> {
|
||||
bounds.push((*declared_bound).clone());
|
||||
}
|
||||
|
||||
cx.typaram(self.span, ty_param.ident, P::from_vec(bounds), None)
|
||||
cx.typaram(self.span, ty_param.ident, vec![], P::from_vec(bounds), None)
|
||||
}));
|
||||
|
||||
// and similarly for where clauses
|
||||
|
@ -194,6 +194,7 @@ impl<'a> Ty<'a> {
|
||||
fn mk_ty_param(cx: &ExtCtxt,
|
||||
span: Span,
|
||||
name: &str,
|
||||
attrs: &[ast::Attribute],
|
||||
bounds: &[Path],
|
||||
self_ident: Ident,
|
||||
self_generics: &Generics)
|
||||
@ -204,7 +205,7 @@ fn mk_ty_param(cx: &ExtCtxt,
|
||||
cx.typarambound(path)
|
||||
})
|
||||
.collect();
|
||||
cx.typaram(span, cx.ident_of(name), bounds, None)
|
||||
cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None)
|
||||
}
|
||||
|
||||
fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>, span: Span)
|
||||
@ -246,7 +247,7 @@ impl<'a> LifetimeBounds<'a> {
|
||||
let bounds = bounds.iter()
|
||||
.map(|b| cx.lifetime(span, cx.ident_of(*b).name))
|
||||
.collect();
|
||||
cx.lifetime_def(span, cx.ident_of(*lt).name, bounds)
|
||||
cx.lifetime_def(span, cx.ident_of(*lt).name, vec![], bounds)
|
||||
})
|
||||
.collect();
|
||||
let ty_params = self.bounds
|
||||
@ -254,7 +255,7 @@ impl<'a> LifetimeBounds<'a> {
|
||||
.map(|t| {
|
||||
match *t {
|
||||
(ref name, ref bounds) => {
|
||||
mk_ty_param(cx, span, *name, bounds, self_ty, self_generics)
|
||||
mk_ty_param(cx, span, *name, &[], bounds, self_ty, self_generics)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
75
src/test/compile-fail/attr-on-generic-formals-are-visited.rs
Normal file
75
src/test/compile-fail/attr-on-generic-formals-are-visited.rs
Normal file
@ -0,0 +1,75 @@
|
||||
// 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 ensures that attributes on formals in generic parameter
|
||||
// lists are included when we are checking for unstable attributes.
|
||||
//
|
||||
// Note that feature(generic_param_attrs) *is* enabled here. We are
|
||||
// checking feature-gating of the attributes themselves, not the
|
||||
// capability to parse such attributes in that context.
|
||||
|
||||
#![feature(generic_param_attrs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
struct StLt<#[lt_struct] 'a>(&'a u32);
|
||||
//~^ ERROR The attribute `lt_struct` is currently unknown to the compiler
|
||||
struct StTy<#[ty_struct] I>(I);
|
||||
//~^ ERROR The attribute `ty_struct` is currently unknown to the compiler
|
||||
|
||||
enum EnLt<#[lt_enum] 'b> { A(&'b u32), B }
|
||||
//~^ ERROR The attribute `lt_enum` is currently unknown to the compiler
|
||||
enum EnTy<#[ty_enum] J> { A(J), B }
|
||||
//~^ ERROR The attribute `ty_enum` is currently unknown to the compiler
|
||||
|
||||
trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
|
||||
//~^ ERROR The attribute `lt_trait` is currently unknown to the compiler
|
||||
trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); }
|
||||
//~^ ERROR The attribute `ty_trait` is currently unknown to the compiler
|
||||
|
||||
type TyLt<#[lt_type] 'd> = &'d u32;
|
||||
//~^ ERROR The attribute `lt_type` is currently unknown to the compiler
|
||||
type TyTy<#[ty_type] L> = (L, );
|
||||
//~^ ERROR The attribute `ty_type` is currently unknown to the compiler
|
||||
|
||||
impl<#[lt_inherent] 'e> StLt<'e> { }
|
||||
//~^ ERROR The attribute `lt_inherent` is currently unknown to the compiler
|
||||
impl<#[ty_inherent] M> StTy<M> { }
|
||||
//~^ ERROR The attribute `ty_inherent` is currently unknown to the compiler
|
||||
|
||||
impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
|
||||
//~^ ERROR The attribute `lt_impl_for` is currently unknown to the compiler
|
||||
fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } }
|
||||
}
|
||||
impl<#[ty_impl_for] N> TrTy<N> for StTy<N> {
|
||||
//~^ ERROR The attribute `ty_impl_for` is currently unknown to the compiler
|
||||
fn foo(&self, _: N) { }
|
||||
}
|
||||
|
||||
fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
|
||||
//~^ ERROR The attribute `lt_fn` is currently unknown to the compiler
|
||||
fn f_ty<#[ty_fn] O>(_: O) { }
|
||||
//~^ ERROR The attribute `ty_fn` is currently unknown to the compiler
|
||||
|
||||
impl<I> StTy<I> {
|
||||
fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
|
||||
//~^ ERROR The attribute `lt_meth` is currently unknown to the compiler
|
||||
fn m_ty<#[ty_meth] P>(_: P) { }
|
||||
//~^ ERROR The attribute `ty_meth` is currently unknown to the compiler
|
||||
}
|
||||
|
||||
fn hof_lt<Q>(_: Q)
|
||||
where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
|
||||
//~^ ERROR The attribute `lt_hof` is currently unknown to the compiler
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
// 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 ensures that attributes on formals in generic parameter
|
||||
// lists are rejected if feature(generic_param_attrs) is not enabled.
|
||||
//
|
||||
// (We are prefixing all tested features with `rustc_`, to ensure that
|
||||
// the attributes themselves won't be rejected by the compiler when
|
||||
// using `rustc_attrs` feature. There is a separate compile-fail/ test
|
||||
// ensuring that the attribute feature-gating works in this context.)
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
struct StLt<#[rustc_lt_struct] 'a>(&'a u32);
|
||||
//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
|
||||
struct StTy<#[rustc_ty_struct] I>(I);
|
||||
//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
|
||||
|
||||
enum EnLt<#[rustc_lt_enum] 'b> { A(&'b u32), B }
|
||||
//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
|
||||
enum EnTy<#[rustc_ty_enum] J> { A(J), B }
|
||||
//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
|
||||
|
||||
trait TrLt<#[rustc_lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
|
||||
//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
|
||||
trait TrTy<#[rustc_ty_trait] K> { fn foo(&self, _: K); }
|
||||
//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
|
||||
|
||||
type TyLt<#[rustc_lt_type] 'd> = &'d u32;
|
||||
//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
|
||||
type TyTy<#[rustc_ty_type] L> = (L, );
|
||||
//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
|
||||
|
||||
impl<#[rustc_lt_inherent] 'e> StLt<'e> { }
|
||||
//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
|
||||
impl<#[rustc_ty_inherent] M> StTy<M> { }
|
||||
//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
|
||||
|
||||
impl<#[rustc_lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
|
||||
//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
|
||||
fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } }
|
||||
}
|
||||
impl<#[rustc_ty_impl_for] N> TrTy<N> for StTy<N> {
|
||||
//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
|
||||
fn foo(&self, _: N) { }
|
||||
}
|
||||
|
||||
fn f_lt<#[rustc_lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
|
||||
//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
|
||||
fn f_ty<#[rustc_ty_fn] O>(_: O) { }
|
||||
//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
|
||||
|
||||
impl<I> StTy<I> {
|
||||
fn m_lt<#[rustc_lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
|
||||
//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
|
||||
fn m_ty<#[rustc_ty_meth] P>(_: P) { }
|
||||
//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761)
|
||||
}
|
||||
|
||||
fn hof_lt<Q>(_: Q)
|
||||
where Q: for <#[rustc_lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
|
||||
//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761)
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
26
src/test/compile-fail/attrs-with-no-formal-in-generics-1.rs
Normal file
26
src/test/compile-fail/attrs-with-no-formal-in-generics-1.rs
Normal 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() {
|
||||
|
||||
}
|
26
src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs
Normal file
26
src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs
Normal 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() {
|
||||
|
||||
}
|
26
src/test/compile-fail/attrs-with-no-formal-in-generics-3.rs
Normal file
26
src/test/compile-fail/attrs-with-no-formal-in-generics-3.rs
Normal 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() {
|
||||
|
||||
}
|
60
src/test/run-pass/attr-on-generic-formals.rs
Normal file
60
src/test/run-pass/attr-on-generic-formals.rs
Normal file
@ -0,0 +1,60 @@
|
||||
// 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 ensures we can attach attributes to the formals in all
|
||||
// places where generic parameter lists occur, assuming appropriate
|
||||
// feature gates are enabled.
|
||||
//
|
||||
// (We are prefixing all tested features with `rustc_`, to ensure that
|
||||
// the attributes themselves won't be rejected by the compiler when
|
||||
// using `rustc_attrs` feature. There is a separate compile-fail/ test
|
||||
// ensuring that the attribute feature-gating works in this context.)
|
||||
|
||||
#![feature(generic_param_attrs, rustc_attrs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
struct StLt<#[rustc_lt_struct] 'a>(&'a u32);
|
||||
struct StTy<#[rustc_ty_struct] I>(I);
|
||||
|
||||
enum EnLt<#[rustc_lt_enum] 'b> { A(&'b u32), B }
|
||||
enum EnTy<#[rustc_ty_enum] J> { A(J), B }
|
||||
|
||||
trait TrLt<#[rustc_lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
|
||||
trait TrTy<#[rustc_ty_trait] K> { fn foo(&self, _: K); }
|
||||
|
||||
type TyLt<#[rustc_lt_type] 'd> = &'d u32;
|
||||
type TyTy<#[rustc_ty_type] L> = (L, );
|
||||
|
||||
impl<#[rustc_lt_inherent] 'e> StLt<'e> { }
|
||||
impl<#[rustc_ty_inherent] M> StTy<M> { }
|
||||
|
||||
impl<#[rustc_lt_impl_for] 'f> TrLt<'f> for StLt<'f> {
|
||||
fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } }
|
||||
}
|
||||
impl<#[rustc_ty_impl_for] N> TrTy<N> for StTy<N> {
|
||||
fn foo(&self, _: N) { }
|
||||
}
|
||||
|
||||
fn f_lt<#[rustc_lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } }
|
||||
fn f_ty<#[rustc_ty_fn] O>(_: O) { }
|
||||
|
||||
impl<I> StTy<I> {
|
||||
fn m_lt<#[rustc_lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } }
|
||||
fn m_ty<#[rustc_ty_meth] P>(_: P) { }
|
||||
}
|
||||
|
||||
fn hof_lt<Q>(_: Q)
|
||||
where Q: for <#[rustc_lt_hof] 'i> Fn(&'i [u32]) -> &'i u32
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user