use AttributeType::*;
use AttributeGate::*;
-use crate::ast::{self, NodeId, GenericParam, GenericParamKind, PatKind, RangeEnd};
+use crate::ast::{
+ self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
+ PatKind, RangeEnd,
+};
use crate::attr;
use crate::early_buffered_lints::BufferedEarlyLintId;
use crate::source_map::Spanned;
// Allows using `#[optimize(X)]`.
(active, optimize_attribute, "1.34.0", Some(54882), None),
- // Allows using `#[repr(align(X))]` on enums.
- (active, repr_align_enum, "1.34.0", Some(57996), None),
-
// Allows using C-variadics.
(active, c_variadic, "1.34.0", Some(44930), None),
+ // 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`
+ // FIXME Create issue
+ (active, const_constructor, "1.37.0", Some(61456), None),
+
+ // #[repr(transparent)] on enums.
+ (active, transparent_enums, "1.37.0", Some(60405), None),
+
+ // #[repr(transparent)] on unions.
+ (active, transparent_unions, "1.37.0", Some(60405), None),
+
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
(accepted, extern_crate_self, "1.34.0", Some(56409), None),
// Allows arbitrary delimited token streams in non-macro attributes.
(accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None),
+ // Allows using `#[repr(align(X))]` on enums with equivalent semantics
+ // to wrapping an enum in a wrapper struct with `#[repr(align(X))]`.
+ (accepted, repr_align_enum, "1.37.0", Some(57996), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
"internal implementation detail",
cfg_fn!(rustc_attrs))),
+ (sym::rustc_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable,
+ sym::rustc_attrs,
+ "internal implementation detail",
+ cfg_fn!(rustc_attrs))),
+
+ (sym::rustc_dummy, Normal, template!(Word /* doesn't matter*/), Gated(Stability::Unstable,
+ sym::rustc_attrs,
+ "used by the test suite",
+ cfg_fn!(rustc_attrs))),
+
// FIXME: #14408 whitelist docs since rustdoc looks at them
(
sym::doc,
self.builtin_attributes.get(&ident.name).map(|a| *a)
});
- // check for gated attributes
+ // Check for gated attributes.
self.context.check_attribute(attr, attr_info, false);
if attr.check_name(sym::doc) {
}
match attr_info {
- Some(&(name, _, template, _)) => self.check_builtin_attribute(
- attr,
- name,
- template
- ),
- None => if let Some(TokenTree::Token(_, token::Eq)) = attr.tokens.trees().next() {
- // All key-value attributes are restricted to meta-item syntax.
- attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok();
+ // `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
+ Some(&(name, _, template, _)) if name != sym::rustc_dummy =>
+ self.check_builtin_attribute(attr, name, template),
+ _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() {
+ if token == token::Eq {
+ // All key-value attributes are restricted to meta-item syntax.
+ attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok();
+ }
}
}
}
}
}
- ast::ItemKind::Enum(..) => {
- for attr in attr::filter_by_name(&i.attrs[..], sym::repr) {
- for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
- if item.check_name(sym::align) {
- gate_feature_post!(&self, repr_align_enum, attr.span,
- "`#[repr(align(x))]` on enums is experimental");
- }
- }
- }
- }
-
ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => {
if polarity == ast::ImplPolarity::Negative {
gate_feature_post!(&self, optin_builtin_traits,
fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
if let ast::TyKind::Never = output_ty.node {
- // Do nothing
+ // Do nothing.
} else {
self.visit_ty(output_ty)
}
}
_ => {}
}
- visit::walk_expr(self, e);
+ visit::walk_expr(self, e)
}
fn visit_arm(&mut self, arm: &'a ast::Arm) {
gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
}
- visit::walk_fn(self, fn_kind, fn_decl, span);
+ visit::walk_fn(self, fn_kind, fn_decl, span)
}
fn visit_generic_param(&mut self, param: &'a GenericParam) {
- if let GenericParamKind::Const { .. } = param.kind {
- gate_feature_post!(&self, const_generics, param.ident.span,
- "const generics are unstable");
+ match param.kind {
+ GenericParamKind::Const { .. } =>
+ gate_feature_post!(&self, const_generics, param.ident.span,
+ "const generics are unstable"),
+ _ => {}
}
- visit::walk_generic_param(self, param);
+ visit::walk_generic_param(self, param)
+ }
+
+ fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
+ match constraint.kind {
+ AssocTyConstraintKind::Bound { .. } =>
+ gate_feature_post!(&self, associated_type_bounds, constraint.span,
+ "associated type bounds are unstable"),
+ _ => {}
+ }
+ visit::walk_assoc_ty_constraint(self, constraint)
}
fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
}
_ => {}
}
- visit::walk_trait_item(self, ti);
+ visit::walk_trait_item(self, ti)
}
fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
}
_ => {}
}
- visit::walk_impl_item(self, ii);
+ visit::walk_impl_item(self, ii)
}
fn visit_vis(&mut self, vis: &'a ast::Visibility) {
gate_feature_post!(&self, crate_visibility_modifier, vis.span,
"`crate` visibility modifier is experimental");
}
- visit::walk_vis(self, vis);
+ visit::walk_vis(self, vis)
}
}
parse_sess: sess,
plugin_attributes,
};
+
+ sess
+ .param_attr_spans
+ .borrow()
+ .iter()
+ .for_each(|span| gate_feature!(
+ &ctx,
+ param_attrs,
+ *span,
+ "attributes on function parameters are unstable"
+ ));
+
let visitor = &mut PostExpansionVisitor {
context: &ctx,
builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP,