From 02fe7f604221673557914d4479c98005e6a01e22 Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Mon, 10 Sep 2018 16:44:43 -0700 Subject: [PATCH 1/9] rfc: cfg_attr-multipe-attrs - init --- text/0000-cfg_attr-multiple-attrs.md | 117 +++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 text/0000-cfg_attr-multiple-attrs.md diff --git a/text/0000-cfg_attr-multiple-attrs.md b/text/0000-cfg_attr-multiple-attrs.md new file mode 100644 index 00000000000..a41871261c0 --- /dev/null +++ b/text/0000-cfg_attr-multiple-attrs.md @@ -0,0 +1,117 @@ +- Feature Name: cfg_attr_multi +- Start Date: 2018-09-10 +- RFC PR: +- Rust Issue: + +# Summary +[summary]: #summary + +Change `cfg_attr` to allow multiple attributes after the configuration +predicate, instead of just one. When the configuration predicate is true, +replace the attribute with all following attributes. + +# Motivation +[motivation]: #motivation + +Simply put, ergonomics and intent. When you have multiple attributes you +configure away behind the same predicate today, you need to duplicate the entire +predicate. And then when you read code that does this, you have to check the +entire predicates with each other to make sure they're the same. By allowing +multiple attributes, it removes that duplication and shows explicitly that the +author wanted those attributes configured behind the same predicate. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +The `cfg_attr` attribute takes a configuration predicate and then a list of +attributes that will be in effect when the predicate is true. + +For an example of multiple attributes, say we want to have two attribute macros +(`sparkles` and `crackles`), but only when `feature = "magic"` is enabled. We +can write this as + +```rust,igore +#[cfg_attr(feature = "magic", sparkles, crackles)] +fn bewitched() {} +``` + +When the feature flag is enable, it is equivalent to: + +```rust,ignore +#[sparkles] +#[crackles] +fn bewitche() {} +``` + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +This replaces what's in the Conditional Compilation Chapter for the `cfg_attr` +attribute. It explains both current and new behavior, mainly because the +current reference material needs improvement. + +## `cfg_attr` Attribute + +The `cfg_attr` attribute conditionally includes attributes based on a +configuration predicate. + +It is written as `cfg_attr` followed by `(`, a comma separated metaitem +sequence, and then `)` The metaitem sequence contains two or more metaitems. +The first is a conditional predicate. The rest are metaitems that are also +attributes. + +When the configuration predicate is true, this attribute expands out to be an +attribute for each attribute metaitem. For example, the following module will +either be found at `linux.rs` or `windows.rs` based on the target. + +```rust,ignore +#[cfg_attr(linux, path = "linux.rs")] +#[cfg_attr(windows, path = "windows.rs")] +mod os; +``` + +For an example of multiple attributes, say we want to have two attribute macros, +but only when `feature = "magic"` is enabled. We can write this as + +```rust,igore +#[cfg_attr(feature = "magic", sparkles, crackles)] +fn bewitched() {} +``` + +When the feature flag is enable, it is equivalent to: + +```rust,ignore +#[sparkles] +#[crackles] +fn bewitche() {} +``` + +Note: The `cfg_attr` can expand to another `cfg_attr`. For example, +`#[cfg_attr(linux, cfg_attr(feature = "multithreaded", some_other_attribute))` +is valid. This example would be equivalent to +`#[cfg_attr(and(linux, feaure ="multithreaded"), some_other_attribute)]`. + +# Drawbacks +[drawbacks]: #drawbacks + +It's another thing that has to be learned. Though even there, it's just learning +that the attribute takes 1+, and not just 1 attribute. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +There are no other alternatives. + +By not doing this, conditionally including attributes is slightly less +ergonomic than it can be. + +# Prior art +[prior-art]: #prior-art + +I cannot think of any prior art specifically, but changing something from taking +one of something to one or more of something is pretty common. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +None. From dee2fd94de472afba85106cbc6d1e94f103ebd67 Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Tue, 11 Sep 2018 13:32:15 -0700 Subject: [PATCH 2/9] rfc: cfg_attr-multipe-attrs - fix typos and grammar --- text/0000-cfg_attr-multiple-attrs.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/text/0000-cfg_attr-multiple-attrs.md b/text/0000-cfg_attr-multiple-attrs.md index a41871261c0..ecac7078358 100644 --- a/text/0000-cfg_attr-multiple-attrs.md +++ b/text/0000-cfg_attr-multiple-attrs.md @@ -17,7 +17,7 @@ Simply put, ergonomics and intent. When you have multiple attributes you configure away behind the same predicate today, you need to duplicate the entire predicate. And then when you read code that does this, you have to check the entire predicates with each other to make sure they're the same. By allowing -multiple attributes, it removes that duplication and shows explicitly that the +multiple attributes it removes that duplication and shows explicitly that the author wanted those attributes configured behind the same predicate. # Guide-level explanation @@ -28,14 +28,14 @@ attributes that will be in effect when the predicate is true. For an example of multiple attributes, say we want to have two attribute macros (`sparkles` and `crackles`), but only when `feature = "magic"` is enabled. We -can write this as +can write this as: ```rust,igore #[cfg_attr(feature = "magic", sparkles, crackles)] fn bewitched() {} ``` -When the feature flag is enable, it is equivalent to: +When the feature flag is enabled, it is equivalent to: ```rust,ignore #[sparkles] @@ -71,7 +71,7 @@ mod os; ``` For an example of multiple attributes, say we want to have two attribute macros, -but only when `feature = "magic"` is enabled. We can write this as +but only when `feature = "magic"` is enabled. We can write this as: ```rust,igore #[cfg_attr(feature = "magic", sparkles, crackles)] From ad8ba5ef666a3719cd7968445ee199cc389dbf78 Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Tue, 11 Sep 2018 15:16:51 -0700 Subject: [PATCH 3/9] rfc: cfg_attr-multiple-attrs - [attr, attr, ...] alternative --- text/0000-cfg_attr-multiple-attrs.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/text/0000-cfg_attr-multiple-attrs.md b/text/0000-cfg_attr-multiple-attrs.md index ecac7078358..4dcd2cf003c 100644 --- a/text/0000-cfg_attr-multiple-attrs.md +++ b/text/0000-cfg_attr-multiple-attrs.md @@ -100,10 +100,16 @@ that the attribute takes 1+, and not just 1 attribute. # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives -There are no other alternatives. - -By not doing this, conditionally including attributes is slightly less -ergonomic than it can be. +We could require that multiple attributes must be within in a delimiter to make +it so that it's always two arguments at the top level. E.g., +`#[cfg_attr(predicate, [attr, attr])]`. While this could increase clarity, it +mostly seems like it would just add noise. In the multiline case, it already +reads pretty clear with the predicate on the first line and each attribute +indented. + +The default alternative of not doing this is a possibility. It would just mean +that conditionally including attributes is slightly less ergonomic than it +could be. # Prior art [prior-art]: #prior-art From 3739313f84a12822fd9f176261ca9f2f3a9771ba Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Thu, 13 Sep 2018 12:21:56 -0700 Subject: [PATCH 4/9] rfc: cfg_attr-multiple-attrs - Describe future attribute syntax restriction --- text/0000-cfg_attr-multiple-attrs.md | 37 +++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/text/0000-cfg_attr-multiple-attrs.md b/text/0000-cfg_attr-multiple-attrs.md index 4dcd2cf003c..7018f501f45 100644 --- a/text/0000-cfg_attr-multiple-attrs.md +++ b/text/0000-cfg_attr-multiple-attrs.md @@ -78,7 +78,7 @@ but only when `feature = "magic"` is enabled. We can write this as: fn bewitched() {} ``` -When the feature flag is enable, it is equivalent to: +When the feature flag is enabled, the attribute expands to: ```rust,ignore #[sparkles] @@ -91,12 +91,40 @@ Note: The `cfg_attr` can expand to another `cfg_attr`. For example, is valid. This example would be equivalent to `#[cfg_attr(and(linux, feaure ="multithreaded"), some_other_attribute)]`. +## Attribute Syntax Opportunity Cost + +This would be the first place attributes would be allowed in a comma-separated +list. As such, it adds a restriction that attributes cannot have a non-delimited +comma. + +Today, an attribute can look like: + +* `name`, +* ``name(`TokenStream`)`` +* ``name = `TokenTree` `` + +where `TokenStream` is a sequence of tokens that only has the restriction that +delimiters match and `TokenTree` is a single identifer, literal, punctuation +mark, or a delimited `TokenStream`. + +With this RFC accepted, the following cannot ever be parsed as attributes: + +* `name, option` +* `name = some, options` + +Arguably, we could allow `(name, option)`, but we shouldn't. + +This restriction is also useful if we want to put multiple attributes in a +single `#[]` container, which has been suggested, but this RFC will not tackle. + # Drawbacks [drawbacks]: #drawbacks It's another thing that has to be learned. Though even there, it's just learning that the attribute takes 1+, and not just 1 attribute. +It restricts the future allowable syntaxes for attributes. + # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives @@ -111,6 +139,13 @@ The default alternative of not doing this is a possibility. It would just mean that conditionally including attributes is slightly less ergonomic than it could be. +We could change attribute container syntax to allow multiple attributes and then +state that `cfg_attr` takes the attribute container syntax without the `#[]` +part. While this could be a good final state, it's a more ambitious change that +has more drawbacks. There are legitimate reasons we'd want `cfg_attr` to take +multiple attributes but not the attribute container. As such, I would like to +go with the conservative change first. + # Prior art [prior-art]: #prior-art From ac4c2c511d0f08e335335ce6c44ada395af25e70 Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Thu, 13 Sep 2018 13:25:16 -0700 Subject: [PATCH 5/9] rfc: cfg_attr-multiple-attrs - Allow zero attributes in list --- text/0000-cfg_attr-multiple-attrs.md | 31 ++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/text/0000-cfg_attr-multiple-attrs.md b/text/0000-cfg_attr-multiple-attrs.md index 7018f501f45..45c7f3b9e16 100644 --- a/text/0000-cfg_attr-multiple-attrs.md +++ b/text/0000-cfg_attr-multiple-attrs.md @@ -35,7 +35,7 @@ can write this as: fn bewitched() {} ``` -When the feature flag is enabled, it is equivalent to: +When the feature flag is enabled, it expands to: ```rust,ignore #[sparkles] @@ -43,12 +43,15 @@ When the feature flag is enabled, it is equivalent to: fn bewitche() {} ``` +The list of attributes may be empty, but will warn if the actual source code +contains an empty list. + # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -This replaces what's in the Conditional Compilation Chapter for the `cfg_attr` -attribute. It explains both current and new behavior, mainly because the -current reference material needs improvement. +The next section replaces what's in the Conditional Compilation Chapter for the +`cfg_attr` attribute. It explains both current and new behavior, mainly because +the current reference material needs improvement. ## `cfg_attr` Attribute @@ -56,9 +59,16 @@ The `cfg_attr` attribute conditionally includes attributes based on a configuration predicate. It is written as `cfg_attr` followed by `(`, a comma separated metaitem -sequence, and then `)` The metaitem sequence contains two or more metaitems. +sequence, and then `)` The metaitem sequence contains one or more metaitems. The first is a conditional predicate. The rest are metaitems that are also -attributes. +attributes. Trailing commas are permitted. The following list are all allowed: + +* `cfg_attr(predicate, attr)` +* `cfg_attr(predicate, attr_1, attr_2)` +* `cfg_attr(predicate, attr,)` +* `cfg_attr(preciate, attr_1, attr_2,)` +* `cfg_attr(predicate)` +* `cfg_attr(predicate,)` When the configuration predicate is true, this attribute expands out to be an attribute for each attribute metaitem. For example, the following module will @@ -91,6 +101,11 @@ Note: The `cfg_attr` can expand to another `cfg_attr`. For example, is valid. This example would be equivalent to `#[cfg_attr(and(linux, feaure ="multithreaded"), some_other_attribute)]`. +## Warning When Zero Attributes + +This RFC allows `#[cfg_attr(predicate)]`. This is so that macros can generate +it. Having it in the source text emits a warning. + ## Attribute Syntax Opportunity Cost This would be the first place attributes would be allowed in a comma-separated @@ -146,6 +161,10 @@ has more drawbacks. There are legitimate reasons we'd want `cfg_attr` to take multiple attributes but not the attribute container. As such, I would like to go with the conservative change first. +The original draft of this RFC only allowed one or more attributes and did not +allow the trailing comma. Because it helps macros and fits the rest of the +language, it now allows those. + # Prior art [prior-art]: #prior-art From 4314792d2b17333982365e7271fdc0a9b72159d2 Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Thu, 13 Sep 2018 22:31:30 -0700 Subject: [PATCH 6/9] rfc: cfg_attr-multiple-attrs - preciate -> predicate --- text/0000-cfg_attr-multiple-attrs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-cfg_attr-multiple-attrs.md b/text/0000-cfg_attr-multiple-attrs.md index 45c7f3b9e16..ad362364c71 100644 --- a/text/0000-cfg_attr-multiple-attrs.md +++ b/text/0000-cfg_attr-multiple-attrs.md @@ -66,7 +66,7 @@ attributes. Trailing commas are permitted. The following list are all allowed: * `cfg_attr(predicate, attr)` * `cfg_attr(predicate, attr_1, attr_2)` * `cfg_attr(predicate, attr,)` -* `cfg_attr(preciate, attr_1, attr_2,)` +* `cfg_attr(predicate, attr_1, attr_2,)` * `cfg_attr(predicate)` * `cfg_attr(predicate,)` From b97b58f2cde8f4e805ca2ba7a0b849c34e5af4ae Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Wed, 26 Sep 2018 12:19:57 -0700 Subject: [PATCH 7/9] rfc: cfg_attr-multiple-attrs - Disallow `cfg_attr(predicate)` --- text/0000-cfg_attr-multiple-attrs.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/text/0000-cfg_attr-multiple-attrs.md b/text/0000-cfg_attr-multiple-attrs.md index ad362364c71..5a877518bb8 100644 --- a/text/0000-cfg_attr-multiple-attrs.md +++ b/text/0000-cfg_attr-multiple-attrs.md @@ -61,15 +61,18 @@ configuration predicate. It is written as `cfg_attr` followed by `(`, a comma separated metaitem sequence, and then `)` The metaitem sequence contains one or more metaitems. The first is a conditional predicate. The rest are metaitems that are also -attributes. Trailing commas are permitted. The following list are all allowed: +attributes. Trailing commas after attributes are permitted. The following list +are all allowed: * `cfg_attr(predicate, attr)` * `cfg_attr(predicate, attr_1, attr_2)` * `cfg_attr(predicate, attr,)` * `cfg_attr(predicate, attr_1, attr_2,)` -* `cfg_attr(predicate)` * `cfg_attr(predicate,)` +> Note: `cfg_attr(predicate)` is not allowed. That comma is semantically +> distinct from the commas following attributes, so we require it. + When the configuration predicate is true, this attribute expands out to be an attribute for each attribute metaitem. For example, the following module will either be found at `linux.rs` or `windows.rs` based on the target. From 0379244283a4edda98f9c1dd40c71b1aaee24b19 Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Fri, 28 Sep 2018 22:27:26 -0700 Subject: [PATCH 8/9] rfc: cfg_attr-multiple-attrs: Emit unused_attributes warning specifically --- text/0000-cfg_attr-multiple-attrs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-cfg_attr-multiple-attrs.md b/text/0000-cfg_attr-multiple-attrs.md index 5a877518bb8..dd92cb16360 100644 --- a/text/0000-cfg_attr-multiple-attrs.md +++ b/text/0000-cfg_attr-multiple-attrs.md @@ -107,7 +107,7 @@ is valid. This example would be equivalent to ## Warning When Zero Attributes This RFC allows `#[cfg_attr(predicate)]`. This is so that macros can generate -it. Having it in the source text emits a warning. +it. Having it in the source text emits an `unused_attributes` warning. ## Attribute Syntax Opportunity Cost From 5534887f79c06075561689cda4b8e11c4a5c4c08 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 7 Oct 2018 04:46:42 +0200 Subject: [PATCH 9/9] RFC 2539 --- ...tr-multiple-attrs.md => 2539-cfg_attr-multiple-attrs.md} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename text/{0000-cfg_attr-multiple-attrs.md => 2539-cfg_attr-multiple-attrs.md} (96%) diff --git a/text/0000-cfg_attr-multiple-attrs.md b/text/2539-cfg_attr-multiple-attrs.md similarity index 96% rename from text/0000-cfg_attr-multiple-attrs.md rename to text/2539-cfg_attr-multiple-attrs.md index dd92cb16360..38d0218a4cc 100644 --- a/text/0000-cfg_attr-multiple-attrs.md +++ b/text/2539-cfg_attr-multiple-attrs.md @@ -1,7 +1,7 @@ -- Feature Name: cfg_attr_multi +- Feature Name: `cfg_attr_multi` - Start Date: 2018-09-10 -- RFC PR: -- Rust Issue: +- RFC PR: [rust-lang/rfcs#2539](https://github.com/rust-lang/rfcs/pull/2539) +- Rust Issue: [rust-lang/rust#54881](https://github.com/rust-lang/rust/issues/54881) # Summary [summary]: #summary