diff options
| author | bors <bors@rust-lang.org> | 2019-06-12 07:38:01 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-06-12 07:38:01 +0000 |
| commit | 3f511ade5b0bc42028e42b81392feec770d90ead (patch) | |
| tree | cb5c0d96ce58721918115a689274280c0de8e722 /src/libsyntax | |
| parent | c4797fa4f4a696b183b3aa1517ee22c78d0f5d7a (diff) | |
| parent | 1eaaf440d5173f090d6e937f4b4cffec6c038984 (diff) | |
| download | rust-3f511ade5b0bc42028e42b81392feec770d90ead.tar.gz rust-3f511ade5b0bc42028e42b81392feec770d90ead.zip | |
Auto merge of #60669 - c410-f3r:attrs-fn, r=petrochenkov
Allow attributes in formal function parameters Implements https://github.com/rust-lang/rust/issues/60406. This is my first contribution to the compiler and since this is a large and complex project, I am not fully aware of the consequences of the changes I have made. **TODO** - [x] Forbid some built-in attributes. - [x] Expand cfg/cfg_attr
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/attr/mod.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/config.rs | 9 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 15 | ||||
| -rw-r--r-- | src/libsyntax/mut_visit.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/parse/attr.rs | 11 | ||||
| -rw-r--r-- | src/libsyntax/parse/diagnostics.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax/parse/lexer/mod.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/parse/mod.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 80 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 3 |
13 files changed, 109 insertions, 39 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 02fbcb14fa5..68cb8c8574d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1770,6 +1770,7 @@ pub struct InlineAsm { /// E.g., `bar: usize` as in `fn foo(bar: usize)`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Arg { + pub attrs: ThinVec<Attribute>, pub ty: P<Ty>, pub pat: P<Pat>, pub id: NodeId, @@ -1817,7 +1818,7 @@ impl Arg { } } - pub fn from_self(eself: ExplicitSelf, eself_ident: Ident) -> Arg { + pub fn from_self(attrs: ThinVec<Attribute>, eself: ExplicitSelf, eself_ident: Ident) -> Arg { let span = eself.span.to(eself_ident.span); let infer_ty = P(Ty { id: DUMMY_NODE_ID, @@ -1825,6 +1826,7 @@ impl Arg { span, }); let arg = |mutbl, ty| Arg { + attrs, pat: P(Pat { id: DUMMY_NODE_ID, node: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None), diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index d7e43f645df..436620ae729 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -723,7 +723,7 @@ macro_rules! derive_has_attrs { derive_has_attrs! { Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm, - ast::Field, ast::FieldPat, ast::Variant_ + ast::Field, ast::FieldPat, ast::Variant_, ast::Arg } pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 6123e95ccf8..1cc13ac7878 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -298,6 +298,10 @@ impl<'a> StripUnconfigured<'a> { } } + pub fn configure_fn_decl(&mut self, fn_decl: &mut ast::FnDecl) { + fn_decl.inputs.flat_map_in_place(|arg| self.configure(arg)); + } + /// Denies `#[cfg]` on generic parameters until we decide what to do with it. /// See issue #51279. pub fn disallow_cfg_on_generic_param(&mut self, param: &ast::GenericParam) { @@ -364,6 +368,11 @@ impl<'a> MutVisitor for StripUnconfigured<'a> { self.configure_pat(pat); noop_visit_pat(pat, self) } + + fn visit_fn_decl(&mut self, mut fn_decl: &mut P<ast::FnDecl>) { + self.configure_fn_decl(&mut fn_decl); + noop_visit_fn_decl(fn_decl, self); + } } fn is_cfg(attr: &ast::Attribute) -> bool { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 2a03e49996b..9d4bf7d518d 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -963,9 +963,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn arg(&self, span: Span, ident: ast::Ident, ty: P<ast::Ty>) -> ast::Arg { let arg_pat = self.pat_ident(span, ident); ast::Arg { - ty, + attrs: ThinVec::default(), + id: ast::DUMMY_NODE_ID, pat: arg_pat, - id: ast::DUMMY_NODE_ID + ty, } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 084d4fd3820..3fa96c60bff 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1578,6 +1578,11 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { *id = self.cx.resolver.next_node_id() } } + + fn visit_fn_decl(&mut self, mut fn_decl: &mut P<ast::FnDecl>) { + self.cfg.configure_fn_decl(&mut fn_decl); + noop_visit_fn_decl(fn_decl, self); + } } pub struct ExpansionConfig<'feat> { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 044c4b18905..004323301a2 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -557,6 +557,9 @@ declare_features! ( // Allows the user of associated type bounds. (active, associated_type_bounds, "1.34.0", Some(52662), None), + // Attributes on formal function params + (active, param_attrs, "1.36.0", Some(60406), None), + // Allows calling constructor functions in `const fn` // FIXME Create issue (active, const_constructor, "1.37.0", Some(61456), None), @@ -2511,6 +2514,18 @@ pub fn check_crate(krate: &ast::Crate, parse_sess: sess, plugin_attributes, }; + + sess + .param_attr_spans + .borrow() + .iter() + .for_each(|span| gate_feature!( + &ctx, + param_attrs, + *span, + "attributes on function parameters are unstable" + )); + let visitor = &mut PostExpansionVisitor { context: &ctx, builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP, diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 2889f8edfc6..02e2c96868d 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -568,8 +568,9 @@ pub fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arg<T: MutVisitor>(Arg { id, pat, ty }: &mut Arg, vis: &mut T) { +pub fn noop_visit_arg<T: MutVisitor>(Arg { attrs, id, pat, ty }: &mut Arg, vis: &mut T) { vis.visit_id(id); + visit_thin_attrs(attrs, vis); vis.visit_pat(pat); vis.visit_ty(ty); } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 77a87e26e60..b28d48b9445 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -18,6 +18,14 @@ const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ permitted in this context"; impl<'a> Parser<'a> { + crate fn parse_arg_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> { + let attrs = self.parse_outer_attributes()?; + attrs.iter().for_each(|a| + self.sess.param_attr_spans.borrow_mut().push(a.span) + ); + Ok(attrs) + } + /// Parse attributes that appear before an item crate fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> { let mut attrs: Vec<ast::Attribute> = Vec::new(); @@ -35,7 +43,8 @@ impl<'a> Parser<'a> { }; let inner_parse_policy = InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason }; - attrs.push(self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?); + let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; + attrs.push(attr); just_parsed_doc_comment = false; } token::DocComment(s) => { diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 9d2ac5b4b51..60544cca877 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -28,7 +28,7 @@ crate fn dummy_arg(ident: Ident) -> Arg { span: ident.span, id: ast::DUMMY_NODE_ID }; - Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID } + Arg { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat, ty: P(ty) } } pub enum Error { @@ -1074,11 +1074,11 @@ impl<'a> Parser<'a> { Err(err) } - crate fn eat_incorrect_doc_comment(&mut self, applied_to: &str) { + crate fn eat_incorrect_doc_comment_for_arg_type(&mut self) { if let token::DocComment(_) = self.token.kind { let mut err = self.diagnostic().struct_span_err( self.token.span, - &format!("documentation comments cannot be applied to {}", applied_to), + "documentation comments cannot be applied to a function parameter's type", ); err.span_label(self.token.span, "doc comments are not allowed here"); err.emit(); @@ -1095,7 +1095,7 @@ impl<'a> Parser<'a> { self.bump(); let mut err = self.diagnostic().struct_span_err( sp, - &format!("attributes cannot be applied to {}", applied_to), + "attributes cannot be applied to a function parameter's type", ); err.span_label(sp, "attributes are not allowed here"); err.emit(); diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 9df2898696e..1c44155150c 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1490,6 +1490,7 @@ mod tests { buffered_lints: Lock::new(vec![]), edition: Edition::from_session(), ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), + param_attr_spans: Lock::new(Vec::new()), } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index dd96c63ab0e..ba5d1d009d1 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -54,6 +54,7 @@ pub struct ParseSess { /// operation token that followed it, but that the parser cannot identify without further /// analysis. pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>, + pub param_attr_spans: Lock<Vec<Span>> } impl ParseSess { @@ -79,6 +80,7 @@ impl ParseSess { buffered_lints: Lock::new(vec![]), edition: Edition::from_session(), ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), + param_attr_spans: Lock::new(Vec::new()), } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d9eba3bbadb..b6388f08e73 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1188,7 +1188,8 @@ impl<'a> Parser<'a> { // definition... // We don't allow argument names to be left off in edition 2018. - p.parse_arg_general(p.token.span.rust_2018(), true, false) + let is_name_required = p.token.span.rust_2018(); + p.parse_arg_general(true, false, |_| is_name_required) })?; generics.where_clause = self.parse_where_clause()?; @@ -1487,26 +1488,31 @@ impl<'a> Parser<'a> { /// Skips unexpected attributes and doc comments in this position and emits an appropriate /// error. /// This version of parse arg doesn't necessarily require identifier names. - fn parse_arg_general( + fn parse_arg_general<F>( &mut self, - require_name: bool, is_trait_item: bool, allow_c_variadic: bool, - ) -> PResult<'a, Arg> { - if let Ok(Some(arg)) = self.parse_self_arg() { + is_name_required: F, + ) -> PResult<'a, Arg> + where + F: Fn(&token::Token) -> bool + { + let attrs = self.parse_arg_attributes()?; + if let Ok(Some(mut arg)) = self.parse_self_arg() { + arg.attrs = attrs.into(); return self.recover_bad_self_arg(arg, is_trait_item); } - let (pat, ty) = if require_name || self.is_named_argument() { - debug!("parse_arg_general parse_pat (require_name:{})", require_name); - self.eat_incorrect_doc_comment("method arguments"); - let pat = self.parse_pat(Some("argument name"))?; + let is_name_required = is_name_required(&self.token); + let (pat, ty) = if is_name_required || self.is_named_argument() { + debug!("parse_arg_general parse_pat (is_name_required:{})", is_name_required); + let pat = self.parse_pat(Some("argument name"))?; if let Err(mut err) = self.expect(&token::Colon) { if let Some(ident) = self.argument_without_type( &mut err, pat, - require_name, + is_name_required, is_trait_item, ) { err.emit(); @@ -1516,12 +1522,12 @@ impl<'a> Parser<'a> { } } - self.eat_incorrect_doc_comment("a method argument's type"); + self.eat_incorrect_doc_comment_for_arg_type(); (pat, self.parse_ty_common(true, true, allow_c_variadic)?) } else { debug!("parse_arg_general ident_to_pat"); let parser_snapshot_before_ty = self.clone(); - self.eat_incorrect_doc_comment("a method argument's type"); + self.eat_incorrect_doc_comment_for_arg_type(); let mut ty = self.parse_ty_common(true, true, allow_c_variadic); if ty.is_ok() && self.token != token::Comma && self.token != token::CloseDelim(token::Paren) { @@ -1554,11 +1560,12 @@ impl<'a> Parser<'a> { } }; - Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID }) + Ok(Arg { attrs: attrs.into(), id: ast::DUMMY_NODE_ID, pat, ty }) } /// Parses an argument in a lambda header (e.g., `|arg, arg|`). fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> { + let attrs = self.parse_arg_attributes()?; let pat = self.parse_pat(Some("argument name"))?; let t = if self.eat(&token::Colon) { self.parse_ty()? @@ -1570,6 +1577,7 @@ impl<'a> Parser<'a> { }) }; Ok(Arg { + attrs: attrs.into(), ty: t, pat, id: ast::DUMMY_NODE_ID @@ -5413,15 +5421,19 @@ impl<'a> Parser<'a> { &token::CloseDelim(token::Paren), SeqSep::trailing_allowed(token::Comma), |p| { - // If the argument is a C-variadic argument we should not - // enforce named arguments. - let enforce_named_args = if p.token == token::DotDotDot { - false - } else { - named_args - }; - match p.parse_arg_general(enforce_named_args, false, - allow_c_variadic) { + let do_not_enforce_named_arguments_for_c_variadic = + |token: &token::Token| -> bool { + if token == &token::DotDotDot { + false + } else { + named_args + } + }; + match p.parse_arg_general( + false, + allow_c_variadic, + do_not_enforce_named_arguments_for_c_variadic + ) { Ok(arg) => { if let TyKind::CVarArgs = arg.ty.node { c_variadic = true; @@ -5466,7 +5478,6 @@ impl<'a> Parser<'a> { /// Parses the argument list and result type of a function declaration. fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P<FnDecl>> { - let (args, c_variadic) = self.parse_fn_args(true, allow_c_variadic)?; let ret_ty = self.parse_ret_ty(true)?; @@ -5478,6 +5489,8 @@ impl<'a> Parser<'a> { } /// Returns the parsed optional self argument and whether a self shortcut was used. + /// + /// See `parse_self_arg_with_attrs` to collect attributes. fn parse_self_arg(&mut self) -> PResult<'a, Option<Arg>> { let expect_ident = |this: &mut Self| match this.token.kind { // Preserve hygienic context. @@ -5583,7 +5596,18 @@ impl<'a> Parser<'a> { }; let eself = source_map::respan(eself_lo.to(eself_hi), eself); - Ok(Some(Arg::from_self(eself, eself_ident))) + Ok(Some(Arg::from_self(ThinVec::default(), eself, eself_ident))) + } + + /// Returns the parsed optional self argument with attributes and whether a self + /// shortcut was used. + fn parse_self_arg_with_attrs(&mut self) -> PResult<'a, Option<Arg>> { + let attrs = self.parse_arg_attributes()?; + let arg_opt = self.parse_self_arg()?; + Ok(arg_opt.map(|mut arg| { + arg.attrs = attrs.into(); + arg + })) } /// Parses the parameter list and result type of a function that may have a `self` parameter. @@ -5593,7 +5617,7 @@ impl<'a> Parser<'a> { self.expect(&token::OpenDelim(token::Paren))?; // Parse optional self argument. - let self_arg = self.parse_self_arg()?; + let self_arg = self.parse_self_arg_with_attrs()?; // Parse the rest of the function parameter list. let sep = SeqSep::trailing_allowed(token::Comma); @@ -5867,7 +5891,7 @@ impl<'a> Parser<'a> { let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; let decl = self.parse_fn_decl_with_self(|p| { - p.parse_arg_general(true, true, false) + p.parse_arg_general(true, false, |_| true) })?; generics.where_clause = self.parse_where_clause()?; *at_end = true; @@ -7443,7 +7467,7 @@ impl<'a> Parser<'a> { } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) { let ident = self.parse_ident().unwrap(); self.bump(); // `(` - let kw_name = if let Ok(Some(_)) = self.parse_self_arg() { + let kw_name = if let Ok(Some(_)) = self.parse_self_arg_with_attrs() { "method" } else { "function" @@ -7494,7 +7518,7 @@ impl<'a> Parser<'a> { self.eat_to_tokens(&[&token::Gt]); self.bump(); // `>` let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) { - if let Ok(Some(_)) = self.parse_self_arg() { + if let Ok(Some(_)) = self.parse_self_arg_with_attrs() { ("fn", "method", false) } else { ("fn", "function", false) diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 24b0c372471..8132024416a 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -550,8 +550,9 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FunctionR pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &'a FnDecl) { for argument in &function_declaration.inputs { + walk_list!(visitor, visit_attribute, argument.attrs.iter()); visitor.visit_pat(&argument.pat); - visitor.visit_ty(&argument.ty) + visitor.visit_ty(&argument.ty); } visitor.visit_fn_ret_ty(&function_declaration.output) } |
