diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 076b6d17658..2389ed799cf 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -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}; @@ -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) -> Vec>(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 { @@ -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 } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 36911683a0e..33643789139 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -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> { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 83e7dd84cbf..29030783ca6 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -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(¶m); + noop_fold_generic_param(param, self) + } + fn fold_attribute(&mut self, at: ast::Attribute) -> Option { // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename", // contents="file contents")]` attributes diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9b84713b0f9..785aedd3f33 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -598,7 +598,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(...)] diff --git a/src/test/ui/issue-51279.rs b/src/test/ui/issue-51279.rs new file mode 100644 index 00000000000..4639d73e44d --- /dev/null +++ b/src/test/ui/issue-51279.rs @@ -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 or the MIT license +// , 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(*const T); + +unsafe impl<#[cfg_attr(none, may_dangle)] T> Drop for M { + //~^ 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 diff --git a/src/test/ui/issue-51279.stderr b/src/test/ui/issue-51279.stderr new file mode 100644 index 00000000000..38d5a5acc50 --- /dev/null +++ b/src/test/ui/issue-51279.stderr @@ -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 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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 +