Skip to content

Commit

Permalink
Rollup merge of rust-lang#51283 - kennytm:fix-51279-preempt-the-warni…
Browse files Browse the repository at this point in the history
…ng-song-and-dance, r=nikomatsakis

Deny #[cfg] and #[cfg_attr] on generic parameters.

Fix rust-lang#51279.

Attributes on generic parameters are not expanded, meaning `#[cfg]`, `#[cfg_attr]` and attribute proc macros are entirely ignored on them.

This PR makes using the first two attributes an error, because if they are correctly expanded will affect the AST and change code behavior.

I'm beta-nominating this, because generic parameter attributes are stabilizing in 1.27, and if we did not reserve their usage, we may never be able to repurpose the meaning of these attributes in the Rust 2015 edition.
  • Loading branch information
kennytm authored Jun 7, 2018
2 parents 0bc15ed + c9cb806 commit 26a9d58
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 3 deletions.
20 changes: 18 additions & 2 deletions src/libsyntax/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub use self::IntType::*;
use ast;
use ast::{AttrId, Attribute, Name, Ident, Path, PathSegment};
use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind};
use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind, GenericParam};
use codemap::{BytePos, Spanned, respan, dummy_spanned};
use syntax_pos::Span;
use errors::{Applicability, Handler};
Expand Down Expand Up @@ -1444,6 +1444,22 @@ impl HasAttrs for Stmt {
}
}

impl HasAttrs for GenericParam {
fn attrs(&self) -> &[ast::Attribute] {
match self {
GenericParam::Lifetime(lifetime) => lifetime.attrs(),
GenericParam::Type(ty) => ty.attrs(),
}
}

fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
match self {
GenericParam::Lifetime(lifetime) => GenericParam::Lifetime(lifetime.map_attrs(f)),
GenericParam::Type(ty) => GenericParam::Type(ty.map_attrs(f)),
}
}
}

macro_rules! derive_has_attrs {
($($ty:path),*) => { $(
impl HasAttrs for $ty {
Expand All @@ -1463,5 +1479,5 @@ 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::LifetimeDef, ast::TyParam
}
16 changes: 16 additions & 0 deletions src/libsyntax/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,22 @@ impl<'a> StripUnconfigured<'a> {
pattern
})
}

// deny #[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) {
for attr in param.attrs() {
let offending_attr = if attr.check_name("cfg") {
"cfg"
} else if attr.check_name("cfg_attr") {
"cfg_attr"
} else {
continue;
};
let msg = format!("#[{}] cannot be applied on a generic parameter", offending_attr);
self.sess.span_diagnostic.span_err(attr.span, &msg);
}
}
}

impl<'a> fold::Folder for StripUnconfigured<'a> {
Expand Down
5 changes: 5 additions & 0 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,11 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
}
}

fn fold_generic_param(&mut self, param: ast::GenericParam) -> ast::GenericParam {
self.cfg.disallow_cfg_on_generic_param(&param);
noop_fold_generic_param(param, self)
}

fn fold_attribute(&mut self, at: ast::Attribute) -> Option<ast::Attribute> {
// turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
// contents="file contents")]` attributes
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ declare_features! (
// allow `'_` placeholder lifetimes
(accepted, underscore_lifetimes, "1.26.0", Some(44524), None),
// Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
(accepted, generic_param_attrs, "1.26.0", Some(48848), None),
(accepted, generic_param_attrs, "1.27.0", Some(48848), None),
// Allows cfg(target_feature = "...").
(accepted, cfg_target_feature, "1.27.0", Some(29717), None),
// Allows #[target_feature(...)]
Expand Down
34 changes: 34 additions & 0 deletions src/test/ui/issue-51279.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2018 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.

pub struct X<#[cfg(none)] 'a, #[cfg(none)] T>(&'a T);
//~^ ERROR #[cfg] cannot be applied on a generic parameter
//~^^ ERROR #[cfg] cannot be applied on a generic parameter

impl<#[cfg(none)] 'a, #[cfg(none)] T> X<'a, T> {}
//~^ ERROR #[cfg] cannot be applied on a generic parameter
//~^^ ERROR #[cfg] cannot be applied on a generic parameter

pub fn f<#[cfg(none)] 'a, #[cfg(none)] T>(_: &'a T) {}
//~^ ERROR #[cfg] cannot be applied on a generic parameter
//~^^ ERROR #[cfg] cannot be applied on a generic parameter

#[cfg(none)]
pub struct Y<#[cfg(none)] T>(T); // shouldn't care when the entire item is stripped out

struct M<T>(*const T);

unsafe impl<#[cfg_attr(none, may_dangle)] T> Drop for M<T> {
//~^ ERROR #[cfg_attr] cannot be applied on a generic parameter
fn drop(&mut self) {}
}

type Z<#[ignored] 'a, #[cfg(none)] T> = X<'a, T>;
//~^ ERROR #[cfg] cannot be applied on a generic parameter
50 changes: 50 additions & 0 deletions src/test/ui/issue-51279.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
error: #[cfg] cannot be applied on a generic parameter
--> $DIR/issue-51279.rs:11:14
|
LL | pub struct X<#[cfg(none)] 'a, #[cfg(none)] T>(&'a T);
| ^^^^^^^^^^^^

error: #[cfg] cannot be applied on a generic parameter
--> $DIR/issue-51279.rs:11:31
|
LL | pub struct X<#[cfg(none)] 'a, #[cfg(none)] T>(&'a T);
| ^^^^^^^^^^^^

error: #[cfg] cannot be applied on a generic parameter
--> $DIR/issue-51279.rs:15:6
|
LL | impl<#[cfg(none)] 'a, #[cfg(none)] T> X<'a, T> {}
| ^^^^^^^^^^^^

error: #[cfg] cannot be applied on a generic parameter
--> $DIR/issue-51279.rs:15:23
|
LL | impl<#[cfg(none)] 'a, #[cfg(none)] T> X<'a, T> {}
| ^^^^^^^^^^^^

error: #[cfg] cannot be applied on a generic parameter
--> $DIR/issue-51279.rs:19:10
|
LL | pub fn f<#[cfg(none)] 'a, #[cfg(none)] T>(_: &'a T) {}
| ^^^^^^^^^^^^

error: #[cfg] cannot be applied on a generic parameter
--> $DIR/issue-51279.rs:19:27
|
LL | pub fn f<#[cfg(none)] 'a, #[cfg(none)] T>(_: &'a T) {}
| ^^^^^^^^^^^^

error: #[cfg_attr] cannot be applied on a generic parameter
--> $DIR/issue-51279.rs:28:13
|
LL | unsafe impl<#[cfg_attr(none, may_dangle)] T> Drop for M<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: #[cfg] cannot be applied on a generic parameter
--> $DIR/issue-51279.rs:33:23
|
LL | type Z<#[ignored] 'a, #[cfg(none)] T> = X<'a, T>;
| ^^^^^^^^^^^^

error: aborting due to 8 previous errors

0 comments on commit 26a9d58

Please sign in to comment.