mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-28 09:44:08 +00:00
syntax: struct field attributes and cfg
This commit is contained in:
parent
8f62c29200
commit
7972c1905b
@ -538,6 +538,7 @@ pub struct FieldPat {
|
|||||||
/// The pattern the field is destructured to
|
/// The pattern the field is destructured to
|
||||||
pub pat: P<Pat>,
|
pub pat: P<Pat>,
|
||||||
pub is_shorthand: bool,
|
pub is_shorthand: bool,
|
||||||
|
pub attrs: ThinVec<Attribute>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
||||||
@ -815,6 +816,7 @@ pub struct Field {
|
|||||||
pub expr: P<Expr>,
|
pub expr: P<Expr>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub is_shorthand: bool,
|
pub is_shorthand: bool,
|
||||||
|
pub attrs: ThinVec<Attribute>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type SpannedIdent = Spanned<Ident>;
|
pub type SpannedIdent = Spanned<Ident>;
|
||||||
|
@ -18,7 +18,7 @@ use ast;
|
|||||||
use ast::{AttrId, Attribute, Name};
|
use ast::{AttrId, Attribute, Name};
|
||||||
use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
|
use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
|
||||||
use ast::{Lit, Expr, Item, Local, Stmt, StmtKind};
|
use ast::{Lit, Expr, Item, Local, Stmt, StmtKind};
|
||||||
use codemap::{spanned, dummy_spanned, mk_sp};
|
use codemap::{Spanned, spanned, dummy_spanned, mk_sp};
|
||||||
use syntax_pos::{Span, BytePos, DUMMY_SP};
|
use syntax_pos::{Span, BytePos, DUMMY_SP};
|
||||||
use errors::Handler;
|
use errors::Handler;
|
||||||
use feature_gate::{Features, GatedCfg};
|
use feature_gate::{Features, GatedCfg};
|
||||||
@ -959,6 +959,13 @@ pub trait HasAttrs: Sized {
|
|||||||
fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self;
|
fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: HasAttrs> HasAttrs for Spanned<T> {
|
||||||
|
fn attrs(&self) -> &[ast::Attribute] { self.node.attrs() }
|
||||||
|
fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self {
|
||||||
|
Spanned { node: self.node.map_attrs(f), span: self.span }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl HasAttrs for Vec<Attribute> {
|
impl HasAttrs for Vec<Attribute> {
|
||||||
fn attrs(&self) -> &[Attribute] {
|
fn attrs(&self) -> &[Attribute] {
|
||||||
&self
|
&self
|
||||||
@ -1012,26 +1019,31 @@ impl HasAttrs for StmtKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! derive_has_attrs_from_field {
|
impl HasAttrs for Stmt {
|
||||||
($($ty:path),*) => { derive_has_attrs_from_field!($($ty: .attrs),*); };
|
fn attrs(&self) -> &[ast::Attribute] { self.node.attrs() }
|
||||||
($($ty:path : $(.$field:ident)*),*) => { $(
|
fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self {
|
||||||
|
Stmt { id: self.id, node: self.node.map_attrs(f), span: self.span }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! derive_has_attrs {
|
||||||
|
($($ty:path),*) => { $(
|
||||||
impl HasAttrs for $ty {
|
impl HasAttrs for $ty {
|
||||||
fn attrs(&self) -> &[Attribute] {
|
fn attrs(&self) -> &[Attribute] {
|
||||||
self $(.$field)* .attrs()
|
&self.attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_attrs<F>(mut self, f: F) -> Self
|
fn map_attrs<F>(mut self, f: F) -> Self
|
||||||
where F: FnOnce(Vec<Attribute>) -> Vec<Attribute>,
|
where F: FnOnce(Vec<Attribute>) -> Vec<Attribute>,
|
||||||
{
|
{
|
||||||
self $(.$field)* = self $(.$field)* .map_attrs(f);
|
self.attrs = self.attrs.map_attrs(f);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)* }
|
)* }
|
||||||
}
|
}
|
||||||
|
|
||||||
derive_has_attrs_from_field! {
|
derive_has_attrs! {
|
||||||
Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm
|
Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm,
|
||||||
|
ast::Field, ast::FieldPat, ast::Variant_
|
||||||
}
|
}
|
||||||
|
|
||||||
derive_has_attrs_from_field! { Stmt: .node, ast::Variant: .node.attrs }
|
|
||||||
|
@ -221,11 +221,21 @@ impl<'a> StripUnconfigured<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure_expr_kind(&mut self, expr_kind: ast::ExprKind) -> ast::ExprKind {
|
pub fn configure_expr_kind(&mut self, expr_kind: ast::ExprKind) -> ast::ExprKind {
|
||||||
if let ast::ExprKind::Match(m, arms) = expr_kind {
|
match expr_kind {
|
||||||
|
ast::ExprKind::Match(m, arms) => {
|
||||||
let arms = arms.into_iter().filter_map(|a| self.configure(a)).collect();
|
let arms = arms.into_iter().filter_map(|a| self.configure(a)).collect();
|
||||||
ast::ExprKind::Match(m, arms)
|
ast::ExprKind::Match(m, arms)
|
||||||
} else {
|
}
|
||||||
expr_kind
|
ast::ExprKind::Struct(path, fields, base) => {
|
||||||
|
let fields = fields.into_iter()
|
||||||
|
.filter_map(|field| {
|
||||||
|
self.visit_struct_field_attrs(field.attrs());
|
||||||
|
self.configure(field)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
ast::ExprKind::Struct(path, fields, base)
|
||||||
|
}
|
||||||
|
_ => expr_kind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,6 +260,51 @@ impl<'a> StripUnconfigured<'a> {
|
|||||||
pub fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option<ast::Stmt> {
|
pub fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option<ast::Stmt> {
|
||||||
self.configure(stmt)
|
self.configure(stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn configure_struct_expr_field(&mut self, field: ast::Field) -> Option<ast::Field> {
|
||||||
|
if !self.features.map(|features| features.struct_field_attributes).unwrap_or(true) {
|
||||||
|
if !field.attrs.is_empty() {
|
||||||
|
let mut err = feature_err(&self.sess,
|
||||||
|
"struct_field_attributes",
|
||||||
|
field.span,
|
||||||
|
GateIssue::Language,
|
||||||
|
"attributes on struct literal fields are unstable");
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.configure(field)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn configure_pat(&mut self, pattern: P<ast::Pat>) -> P<ast::Pat> {
|
||||||
|
pattern.map(|mut pattern| {
|
||||||
|
if let ast::PatKind::Struct(path, fields, etc) = pattern.node {
|
||||||
|
let fields = fields.into_iter()
|
||||||
|
.filter_map(|field| {
|
||||||
|
self.visit_struct_field_attrs(field.attrs());
|
||||||
|
self.configure(field)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
pattern.node = ast::PatKind::Struct(path, fields, etc);
|
||||||
|
}
|
||||||
|
pattern
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_struct_field_attrs(&mut self, attrs: &[ast::Attribute]) {
|
||||||
|
// flag the offending attributes
|
||||||
|
for attr in attrs.iter() {
|
||||||
|
if !self.features.map(|features| features.struct_field_attributes).unwrap_or(true) {
|
||||||
|
let mut err = feature_err(
|
||||||
|
&self.sess,
|
||||||
|
"struct_field_attributes",
|
||||||
|
attr.span,
|
||||||
|
GateIssue::Language,
|
||||||
|
"attributes on struct pattern or literal fields are unstable");
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fold::Folder for StripUnconfigured<'a> {
|
impl<'a> fold::Folder for StripUnconfigured<'a> {
|
||||||
@ -299,6 +354,10 @@ impl<'a> fold::Folder for StripUnconfigured<'a> {
|
|||||||
// Interpolated AST will get configured once the surrounding tokens are parsed.
|
// Interpolated AST will get configured once the surrounding tokens are parsed.
|
||||||
mac
|
mac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold_pat(&mut self, pattern: P<ast::Pat>) -> P<ast::Pat> {
|
||||||
|
fold::noop_fold_pat(self.configure_pat(pattern), self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_cfg(attr: &ast::Attribute) -> bool {
|
fn is_cfg(attr: &ast::Attribute) -> bool {
|
||||||
|
@ -699,7 +699,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||||||
self.expr(b.span, ast::ExprKind::Block(b))
|
self.expr(b.span, ast::ExprKind::Block(b))
|
||||||
}
|
}
|
||||||
fn field_imm(&self, span: Span, name: Ident, e: P<ast::Expr>) -> ast::Field {
|
fn field_imm(&self, span: Span, name: Ident, e: P<ast::Expr>) -> ast::Field {
|
||||||
ast::Field { ident: respan(span, name), expr: e, span: span, is_shorthand: false }
|
ast::Field {
|
||||||
|
ident: respan(span, name),
|
||||||
|
expr: e,
|
||||||
|
span: span,
|
||||||
|
is_shorthand: false,
|
||||||
|
attrs: ast::ThinVec::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn expr_struct(&self, span: Span, path: ast::Path, fields: Vec<ast::Field>) -> P<ast::Expr> {
|
fn expr_struct(&self, span: Span, path: ast::Path, fields: Vec<ast::Field>) -> P<ast::Expr> {
|
||||||
self.expr(span, ast::ExprKind::Struct(path, fields, None))
|
self.expr(span, ast::ExprKind::Struct(path, fields, None))
|
||||||
|
@ -679,6 +679,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
|
fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
|
||||||
|
let pat = self.cfg.configure_pat(pat);
|
||||||
match pat.node {
|
match pat.node {
|
||||||
PatKind::Mac(_) => {}
|
PatKind::Mac(_) => {}
|
||||||
_ => return noop_fold_pat(pat, self),
|
_ => return noop_fold_pat(pat, self),
|
||||||
|
@ -327,6 +327,9 @@ declare_features! (
|
|||||||
|
|
||||||
// The `unadjusted` ABI. Perma unstable.
|
// The `unadjusted` ABI. Perma unstable.
|
||||||
(active, abi_unadjusted, "1.16.0", None),
|
(active, abi_unadjusted, "1.16.0", None),
|
||||||
|
|
||||||
|
// Allows attributes on struct literal fields.
|
||||||
|
(active, struct_field_attributes, "1.16.0", Some(38814)),
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_features! (
|
declare_features! (
|
||||||
|
@ -830,6 +830,7 @@ pub fn noop_fold_field<T: Folder>(f: Field, folder: &mut T) -> Field {
|
|||||||
expr: folder.fold_expr(f.expr),
|
expr: folder.fold_expr(f.expr),
|
||||||
span: folder.new_span(f.span),
|
span: folder.new_span(f.span),
|
||||||
is_shorthand: f.is_shorthand,
|
is_shorthand: f.is_shorthand,
|
||||||
|
attrs: fold_thin_attrs(f.attrs, folder),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1089,6 +1090,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
|
|||||||
ident: folder.fold_ident(f.node.ident),
|
ident: folder.fold_ident(f.node.ident),
|
||||||
pat: folder.fold_pat(f.node.pat),
|
pat: folder.fold_pat(f.node.pat),
|
||||||
is_shorthand: f.node.is_shorthand,
|
is_shorthand: f.node.is_shorthand,
|
||||||
|
attrs: fold_attrs(f.node.attrs.into(), folder).into()
|
||||||
}}
|
}}
|
||||||
});
|
});
|
||||||
PatKind::Struct(pth, fs, etc)
|
PatKind::Struct(pth, fs, etc)
|
||||||
|
@ -1946,6 +1946,7 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
/// Parse ident (COLON expr)?
|
/// Parse ident (COLON expr)?
|
||||||
pub fn parse_field(&mut self) -> PResult<'a, Field> {
|
pub fn parse_field(&mut self) -> PResult<'a, Field> {
|
||||||
|
let attrs = self.parse_outer_attributes()?;
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
let hi;
|
let hi;
|
||||||
|
|
||||||
@ -1968,6 +1969,7 @@ impl<'a> Parser<'a> {
|
|||||||
span: mk_sp(lo, expr.span.hi),
|
span: mk_sp(lo, expr.span.hi),
|
||||||
expr: expr,
|
expr: expr,
|
||||||
is_shorthand: is_shorthand,
|
is_shorthand: is_shorthand,
|
||||||
|
attrs: attrs.into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3436,6 +3438,7 @@ impl<'a> Parser<'a> {
|
|||||||
if self.check(&token::CloseDelim(token::Brace)) { break }
|
if self.check(&token::CloseDelim(token::Brace)) { break }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let attrs = self.parse_outer_attributes()?;
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
let hi;
|
let hi;
|
||||||
|
|
||||||
@ -3493,9 +3496,13 @@ impl<'a> Parser<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fields.push(codemap::Spanned { span: mk_sp(lo, hi),
|
fields.push(codemap::Spanned { span: mk_sp(lo, hi),
|
||||||
node: ast::FieldPat { ident: fieldname,
|
node: ast::FieldPat {
|
||||||
|
ident: fieldname,
|
||||||
pat: subpat,
|
pat: subpat,
|
||||||
is_shorthand: is_shorthand }});
|
is_shorthand: is_shorthand,
|
||||||
|
attrs: attrs.into(),
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return Ok((fields, etc));
|
return Ok((fields, etc));
|
||||||
}
|
}
|
||||||
|
@ -427,6 +427,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
|||||||
PatKind::Struct(ref path, ref fields, _) => {
|
PatKind::Struct(ref path, ref fields, _) => {
|
||||||
visitor.visit_path(path, pattern.id);
|
visitor.visit_path(path, pattern.id);
|
||||||
for field in fields {
|
for field in fields {
|
||||||
|
walk_list!(visitor, visit_attribute, field.node.attrs.iter());
|
||||||
visitor.visit_ident(field.span, field.node.ident);
|
visitor.visit_ident(field.span, field.node.ident);
|
||||||
visitor.visit_pat(&field.node.pat)
|
visitor.visit_pat(&field.node.pat)
|
||||||
}
|
}
|
||||||
@ -659,6 +660,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
|||||||
ExprKind::Struct(ref path, ref fields, ref optional_base) => {
|
ExprKind::Struct(ref path, ref fields, ref optional_base) => {
|
||||||
visitor.visit_path(path, expression.id);
|
visitor.visit_path(path, expression.id);
|
||||||
for field in fields {
|
for field in fields {
|
||||||
|
walk_list!(visitor, visit_attribute, field.attrs.iter());
|
||||||
visitor.visit_ident(field.ident.span, field.ident.node);
|
visitor.visit_ident(field.ident.span, field.ident.node);
|
||||||
visitor.visit_expr(&field.expr)
|
visitor.visit_expr(&field.expr)
|
||||||
}
|
}
|
||||||
|
@ -1550,6 +1550,7 @@ impl<'a> TraitDef<'a> {
|
|||||||
ident: ident.unwrap(),
|
ident: ident.unwrap(),
|
||||||
pat: pat,
|
pat: pat,
|
||||||
is_shorthand: false,
|
is_shorthand: false,
|
||||||
|
attrs: ast::ThinVec::new(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
20
src/test/compile-fail/struct-field-attr-feature-gate.rs
Normal file
20
src/test/compile-fail/struct-field-attr-feature-gate.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
present: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo = Foo { #[cfg(all())] present: () };
|
||||||
|
//~^ ERROR attributes on struct pattern or literal fields are unstable
|
||||||
|
let Foo { #[cfg(all())] present: () } = foo;
|
||||||
|
//~^ ERROR attributes on struct pattern or literal fields are unstable
|
||||||
|
}
|
30
src/test/compile-fail/struct-field-cfg.rs
Normal file
30
src/test/compile-fail/struct-field-cfg.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
#![feature(struct_field_attributes)]
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
present: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo = Foo { #[cfg(all())] present: () };
|
||||||
|
let _ = Foo { #[cfg(any())] present: () };
|
||||||
|
//~^ ERROR missing field `present` in initializer of `Foo`
|
||||||
|
let _ = Foo { present: (), #[cfg(any())] absent: () };
|
||||||
|
let _ = Foo { present: (), #[cfg(all())] absent: () };
|
||||||
|
//~^ ERROR struct `Foo` has no field named `absent`
|
||||||
|
let Foo { #[cfg(all())] present: () } = foo;
|
||||||
|
let Foo { #[cfg(any())] present: () } = foo;
|
||||||
|
//~^ ERROR pattern does not mention field `present`
|
||||||
|
let Foo { present: (), #[cfg(any())] absent: () } = foo;
|
||||||
|
let Foo { present: (), #[cfg(all())] absent: () } = foo;
|
||||||
|
//~^ ERROR struct `Foo` does not have a field named `absent`
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user