Change:
This is a tracking issue for the RFC " expanding to multiple attributes" (rust-lang/rfcs). Steps: [x] Implement the RFC ( is doing this) [x] Adjust documentation (issue filed against ) [x] Stabilization PR (merged, ) [ ] Fix the lint: [stabilization-guide]: [doc-guide]: Unresolved questions: None
Implementation in
Setting earliest date for stabilization proposal: 2018-11-22 (11 days from now).
merge Originally proposed in RFC , implemented in , and in nightly since ~ the 12th October, allows users to specify multiple attributes in where and are the attributes to expand should hold. The benefit of is ergonomics but also readability and maintainability; you avoid having to specify several times. This can be particularly beneficial if is long and non-trivial. The next version is 1.32 which goes into beta the 7th of December; It is quite possible that this will slip into 1.33 however depending on how long the review process takes. Tests Users are now permitted to write for example: The semantics of these are to expand to for example on if should hold (4th example). If zero attributes are given, e.g. then the lint will be emitted. This behaviour is not witnessed in the current nightly compiler; that is OK since it's a minor issue but it will need to be fixed in the stabilization PR. See Users are not permitted to write: More than one trailing comma, e.g. Zero attributes and no comma, e.g. An empty , e.g. ; this is proposed in This stabilization is forward compatible with that RFC. None cc can you make the stabilization PR + resolve the minor FIXME in it? Also cc who reviewed the implementation.
Team member has proposed to merge this. The next step is review by the rest of the tagged teams: [x] [x] [x] [x] [x] [ ] [x] [x] [x] [x] No concerns currently listed. Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See for info about what commands tagged team members can give me.
I wouldn't call the implementation of the lint a minor fix. The first time I tried, I bailed when I hit a set of cases I couldn't get something the lint infrastructure wanted. The lint is also the least value add of the RFC and I propose stabilizing it separately if doing so doesn't break backwards compatibility.
Warn by default lints can always be later so if you think it is non-trivial to implement in the stabilization PR, I wouldn't mind deferring that to the future; as you say, it is indeed the least value-add. However, if you do manage to fix it in the stabilization PR, that would be nice (but not required, imo).
:bell: This is now entering its final comment period, as per the . :bell:
The final comment period, with a disposition to merge, as per the , is now complete.
Up for writing the stabilization PR?
I don't and haven't had motivation pertaining to Rustlang at the moment, sorry. Eventually it'll return.
r?
Stabilization has gone through and documentation issue has been filed against the reference; what remains is to fix the lint which will do in a separate PR. After that this issue can be closed.

Discussion:
/// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> { <del> if !attr.check_name(sym::cfg_attr) { </del> <ins> if attr.path != sym::cfg_attr { </ins> return vec![attr]; } <del> if attr.tokens.len() == 0 { </del> <ins> if attr.tokens.is_empty() { </ins> self.sess.span_diagnostic .struct_span_err( attr.span,

<https://doc.rust-lang.org/reference/conditional-compilation.html #the-cfg_attr-attribute>") .emit(); <del> return Vec::new(); </del> <ins> return vec![]; </ins> } let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| {

Ok(result) => result, Err(mut e) => { e.emit(); <del> return Vec::new(); </del> <ins> return vec![]; </ins> } }; <del> // Check feature gate and lint on zero attributes in source. Even if the feature is gated, // we still compute as if it wasn't, since the emitted error will stop compilation further // along the compilation. if expanded_attrs.len() == 0 { // FIXME: Emit unused attribute lint here. </del> <ins> // Lint on zero attributes in source. if expanded_attrs.is_empty() { return vec![attr]; </ins> } <ins> // At this point we know the attribute is considered used. attr::mark_used(&attr); </ins> if attr::cfg_matches(&cfg_predicate, self.sess, self.features) { // We call `process_cfg_attr` recursively in case there's a // `cfg_attr` inside of another `cfg_attr`. E.g.

})) .collect() } else { <del> Vec::new() </del> <ins> vec![] </ins> } }

<ins> // Check that `#[cfg_attr($PREDICATE,)]` triggers the `unused_attribute` lint. // compile-flags: --cfg TRUE #![deny(unused)] #[cfg_attr(FALSE,)] //~ ERROR unused attribute fn _f() {} #[cfg_attr(TRUE,)] //~ ERROR unused attribute fn _g() {} fn main() {} </ins>

<ins> error: unused attribute --> $DIR/cfg-attr-empty-is-unused.rs:7:1 | LL | #[cfg_attr(FALSE,)] | ^^^^^^^^^^^^^^^^^^^ | note: lint level defined here --> $DIR/cfg-attr-empty-is-unused.rs:5:9 | LL | #![deny(unused)] |         ^^^^^^ = note: #[deny(unused_attributes)] implied by #[deny(unused)] error: unused attribute --> $DIR/cfg-attr-empty-is-unused.rs:10:1 | LL | #[cfg_attr(TRUE,)] | ^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors </ins>