Skip to content

Commit

Permalink
Rollup merge of rust-lang#64010 - c410-f3r:stabilize-attrs-fn, r=Centril
Browse files Browse the repository at this point in the history
Stabilize `param_attrs` in Rust 1.39.0

# Stabilization proposal

I propose that we stabilize `#![feature(param_attrs)]`.

Tracking issue: rust-lang#60406
Version: 1.39 (2019-09-26 => beta, 2019-11-07 => stable).

## What is stabilized

It is now possible to add outer attributes like `#[cfg(..)]` on formal parameters of functions, closures, and function pointer types. For example:

```rust
fn len(
    #[cfg(windows)] slice: &[u16],
    #[cfg(not(windows))] slice: &[u8],
) -> usize {
    slice.len()
}
```

## What isn't stabilized

* Documentation comments like `/// Doc` on parameters.

* Code expansion of a user-defined `#[proc_macro_attribute]` macro used on parameters.

* Built-in attributes other than `cfg`, `cfg_attr`, `allow`, `warn`, `deny`, and `forbid`. Currently, only the lints `unused_variables` and `unused_mut` have effect and may be controlled on parameters.

## Motivation

The chief motivations for stabilizing `param_attrs` include:

* Finer conditional compilation with `#[cfg(..)]` and linting control of variables.

* Richer macro DSLs created by users.

* External tools and compiler internals can take advantage of the additional information that the parameters provide.

For more examples, see the [RFC][rfc motivation].

## Reference guide

In the grammar of function and function pointer, the grammar of variadic tails (`...`) and parameters are changed respectively from:

```rust
FnParam = { pat:Pat ":" }? ty:Type;
VaradicTail = "...";
```

into:

```rust
FnParam = OuterAttr* { pat:Pat ":" }? ty:Type;
VaradicTail = OuterAttr* "...";
```

The grammar of a closure parameter is changed from:

```rust
ClosureParam = pat:Pat { ":" ty:Type }?;
```

into:

```rust
ClosureParam = OuterAttr* pat:Pat { ":" ty:Type }?;
```

More generally, where there's a list of formal (value) parameters separated or terminated by `,` and delimited by `(` and `)`. Each parameter in that list may optionally be prefixed by `OuterAttr+`.

Note that in all cases, `OuterAttr*` applies to the whole parameter and not just the pattern. This distinction matters in pretty printing and in turn for macros.

## History

* On 2018-10-15, @Robbepop proposes [RFC 2565][rfc], "Attributes in formal function parameter position".

* On 2019-04-30, [RFC 2565][rfc] is merged and the tracking issue is made.

* On 2019-06-12, a partial implementation was completed. The implementation was done in [rust-lang#60669][60669] by @c410-f3r and the PR was reviewed by @petrochenkov and @Centril.

* On 2019-07-29, [rust-lang#61238][61238] was fixed in [rust-lang#61856][61856]. The issue fixed was that lint attributes on function args had no effect. The PR was written by @c410-f3r and reviewed by @matthewjasper, @petrochenkov, and @oli-obk.

* On 2019-08-02, a bug [rust-lang#63210][63210] was filed wherein the attributes on formal parameters would not be passed to macros. The issue was about forgetting to call the relevant method in `fn print_arg` in the pretty printer. In [rust-lang#63212][63212], written by @Centril on 2019-08-02 and reviewed by @davidtwco, the issue aforementioned was fixed.

* This PR stabilizes `param_attrs`.

## Tests

* [On Rust 2018, attributes aren't permitted on function parameters without a pattern in trait definitions.](https://github.com/rust-lang/rust/blob/master/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs)

* [All attributes that should be allowed. This includes `cfg`, `cfg_attr`, and lints check attributes.](https://github.com/rust-lang/rust/blob/master/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs)

* [Built-in attributes, which should be forbidden, e.g., `#[test]`, are.](https://github.com/rust-lang/rust/blob/master/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs)

* [`cfg` and `cfg_attr` are properly evaluated.](https://github.com/rust-lang/rust/blob/master/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.rs)

* [`unused_mut`](https://github.com/rust-lang/rust/blob/46f405ec4d7c6bf16fc2eaafe7541019f1da2996/src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.rs) and [`unused_variables`](https://github.com/rust-lang/rust/blob/master/src/test/ui/lint/lint-unused-variables.rs) are correctly applied to parameter patterns.

* [Pretty printing takes formal parameter attributes into account.](https://github.com/rust-lang/rust/blob/master/src/test/ui/rfc-2565-param-attrs/param-attrs-pretty.rs)

## Possible future work

* Custom attributes inside function parameters aren't currently supported but it is something being worked on internally.

* Since documentation comments are syntactic sugar for `#[doc(...)]`, it is possible to allow literal `/// Foo` comments on function parameters.

[rfc motivation]: https://github.com/rust-lang/rfcs/blob/master/text/2565-formal-function-parameter-attributes.md#motivation
[rfc]: rust-lang/rfcs#2565
[60669]: rust-lang#60669
[61856]: rust-lang#61856
[63210]: rust-lang#63210
[61238]: rust-lang#61238
[63212]: rust-lang#63212

This report is a collaborative work with @Centril.
  • Loading branch information
Centril committed Sep 21, 2019
2 parents 5349e69 + 299d696 commit 8646c81
Show file tree
Hide file tree
Showing 23 changed files with 93 additions and 204 deletions.
27 changes: 0 additions & 27 deletions src/doc/unstable-book/src/language-features/param-attrs.md

This file was deleted.

2 changes: 2 additions & 0 deletions src/libsyntax/feature_gate/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ declare_features! (
(accepted, async_await, "1.39.0", Some(50547), None),
/// Allows mixing bind-by-move in patterns and references to those identifiers in guards.
(accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None),
/// Allows attributes in formal function parameters.
(accepted, param_attrs, "1.39.0", Some(60406), None),

// -------------------------------------------------------------------------
// feature-group-end: accepted features
Expand Down
3 changes: 0 additions & 3 deletions src/libsyntax/feature_gate/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,9 +489,6 @@ 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`.
(active, const_constructor, "1.37.0", Some(61456), None),

Expand Down
1 change: 0 additions & 1 deletion src/libsyntax/feature_gate/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,6 @@ pub fn check_crate(krate: &ast::Crate,
}
}

gate_all!(param_attrs, "attributes on function parameters are unstable");
gate_all!(let_chains, "`let` expressions in this position are experimental");
gate_all!(async_closure, "async closures are unstable");
gate_all!(yields, generators, "yield syntax is experimental");
Expand Down
7 changes: 0 additions & 7 deletions src/libsyntax/parse/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,6 @@ const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
permitted in this context";

impl<'a> Parser<'a> {
crate fn parse_param_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
let attrs = self.parse_outer_attributes()?;
self.sess.gated_spans.param_attrs.borrow_mut()
.extend(attrs.iter().map(|a| a.span));
Ok(attrs)
}

/// Parses 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();
Expand Down
2 changes: 0 additions & 2 deletions src/libsyntax/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ static_assert_size!(PResult<'_, bool>, 16);
/// used and should be feature gated accordingly in `check_crate`.
#[derive(Default)]
pub struct GatedSpans {
/// Spans collected for gating `param_attrs`, e.g. `fn foo(#[attr] x: u8) {}`.
pub param_attrs: Lock<Vec<Span>>,
/// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`.
pub let_chains: Lock<Vec<Span>>,
/// Spans collected for gating `async_closure`, e.g. `async || ..`.
Expand Down
4 changes: 2 additions & 2 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,7 @@ impl<'a> Parser<'a> {
is_name_required: impl Fn(&token::Token) -> bool,
) -> PResult<'a, Param> {
let lo = self.token.span;
let attrs = self.parse_param_attributes()?;
let attrs = self.parse_outer_attributes()?;
if let Some(mut param) = self.parse_self_param()? {
param.attrs = attrs.into();
return self.recover_bad_self_param(param, is_trait_item);
Expand Down Expand Up @@ -1362,7 +1362,7 @@ impl<'a> Parser<'a> {
/// Returns the parsed optional self parameter with attributes and whether a self
/// shortcut was used.
fn parse_self_parameter_with_attrs(&mut self) -> PResult<'a, Option<Param>> {
let attrs = self.parse_param_attributes()?;
let attrs = self.parse_outer_attributes()?;
let param_opt = self.parse_self_param()?;
Ok(param_opt.map(|mut param| {
param.attrs = attrs.into();
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/parse/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1176,7 +1176,7 @@ impl<'a> Parser<'a> {
/// Parses a parameter in a closure header (e.g., `|arg, arg|`).
fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
let lo = self.token.span;
let attrs = self.parse_param_attributes()?;
let attrs = self.parse_outer_attributes()?;
let pat = self.parse_pat(PARAM_EXPECTED)?;
let t = if self.eat(&token::Colon) {
self.parse_ty()?
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/lint/lint-unused-mut-variables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Exercise the unused_mut attribute in some positive and negative cases

#![deny(unused_mut)]
#![feature(async_closure, param_attrs)]
#![feature(async_closure)]

async fn baz_async(
mut a: i32,
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/lint/lint-unused-variables.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// compile-flags: --cfg something
// edition:2018

#![feature(async_closure, param_attrs)]
#![feature(async_closure)]
#![deny(unused_variables)]

async fn foo_async(
Expand Down
4 changes: 0 additions & 4 deletions src/test/ui/parser/fn-arg-doc-comment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@ pub fn f(
/// Comment
//~^ ERROR documentation comments cannot be applied to function parameters
//~| NOTE doc comments are not allowed here
//~| ERROR attributes on function parameters are unstable
//~| NOTE https://github.com/rust-lang/rust/issues/60406
id: u8,
/// Other
//~^ ERROR documentation comments cannot be applied to function parameters
//~| NOTE doc comments are not allowed here
//~| ERROR attributes on function parameters are unstable
//~| NOTE https://github.com/rust-lang/rust/issues/60406
a: u8,
) {}

Expand Down
33 changes: 7 additions & 26 deletions src/test/ui/parser/fn-arg-doc-comment.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: attributes cannot be applied to a function parameter's type
--> $DIR/fn-arg-doc-comment.rs:16:12
--> $DIR/fn-arg-doc-comment.rs:12:12
|
LL | fn bar(id: #[allow(dead_code)] i32) {}
| ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here
Expand All @@ -11,31 +11,13 @@ LL | /// Comment
| ^^^^^^^^^^^ doc comments are not allowed here

error: documentation comments cannot be applied to function parameters
--> $DIR/fn-arg-doc-comment.rs:8:5
--> $DIR/fn-arg-doc-comment.rs:6:5
|
LL | /// Other
| ^^^^^^^^^ doc comments are not allowed here

error[E0658]: attributes on function parameters are unstable
--> $DIR/fn-arg-doc-comment.rs:2:5
|
LL | /// Comment
| ^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/60406
= help: add `#![feature(param_attrs)]` to the crate attributes to enable

error[E0658]: attributes on function parameters are unstable
--> $DIR/fn-arg-doc-comment.rs:8:5
|
LL | /// Other
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/60406
= help: add `#![feature(param_attrs)]` to the crate attributes to enable

error[E0308]: mismatched types
--> $DIR/fn-arg-doc-comment.rs:22:7
--> $DIR/fn-arg-doc-comment.rs:18:7
|
LL | f("", "");
| ^^ expected u8, found reference
Expand All @@ -44,7 +26,7 @@ LL | f("", "");
found type `&'static str`

error[E0308]: mismatched types
--> $DIR/fn-arg-doc-comment.rs:22:11
--> $DIR/fn-arg-doc-comment.rs:18:11
|
LL | f("", "");
| ^^ expected u8, found reference
Expand All @@ -53,15 +35,14 @@ LL | f("", "");
found type `&'static str`

error[E0308]: mismatched types
--> $DIR/fn-arg-doc-comment.rs:29:9
--> $DIR/fn-arg-doc-comment.rs:25:9
|
LL | bar("");
| ^^ expected i32, found reference
|
= note: expected type `i32`
found type `&'static str`

error: aborting due to 8 previous errors
error: aborting due to 6 previous errors

Some errors have detailed explanations: E0308, E0658.
For more information about an error, try `rustc --explain E0308`.
For more information about this error, try `rustc --explain E0308`.
2 changes: 0 additions & 2 deletions src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// edition:2018

#![feature(param_attrs)]

trait Trait2015 { fn foo(#[allow(C)] i32); }
//~^ ERROR expected one of `:`, `@`, or `|`, found `)`

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: expected one of `:`, `@`, or `|`, found `)`
--> $DIR/param-attrs-2018.rs:5:41
--> $DIR/param-attrs-2018.rs:3:41
|
LL | trait Trait2015 { fn foo(#[allow(C)] i32); }
| ^ expected one of `:`, `@`, or `|` here
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// compile-flags: --cfg something

#![deny(unused_mut)]
#![feature(param_attrs)]

extern "C" {
fn ffi(
Expand Down
2 changes: 0 additions & 2 deletions src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![feature(param_attrs)]

extern "C" {
fn ffi(
/// Foo
Expand Down
Loading

0 comments on commit 8646c81

Please sign in to comment.