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;
use crate::symbol::{Symbol, kw, sym};
use crate::tokenstream::TokenTree;
-use errors::{DiagnosticBuilder, Handler};
+use errors::{Applicability, DiagnosticBuilder, Handler};
use rustc_data_structures::fx::FxHashMap;
use rustc_target::spec::abi::Abi;
use syntax_pos::{Span, DUMMY_SP};
// 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),
+
+ // Allows calling constructor functions in `const fn`
+ // FIXME Create issue
+ (active, const_constructor, "1.37.0", Some(61456), None),
+
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
"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))),
+
// FIXME: #14408 whitelist docs since rustdoc looks at them
(
sym::doc,
Normal,
template!(
Word,
- List: r#"/*opt*/ since = "version", /*opt*/ note = "reason"#,
+ List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
NameValueStr: "reason"
),
Ungated
match attr.parse_meta(self.context.parse_sess) {
Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) {
+ let error_msg = format!("malformed `{}` attribute input", name);
let mut msg = "attribute must be of the form ".to_owned();
+ let mut suggestions = vec![];
let mut first = true;
if template.word {
first = false;
- msg.push_str(&format!("`#[{}{}]`", name, ""));
+ let code = format!("#[{}]", name);
+ msg.push_str(&format!("`{}`", &code));
+ suggestions.push(code);
}
if let Some(descr) = template.list {
if !first {
msg.push_str(" or ");
}
first = false;
- msg.push_str(&format!("`#[{}({})]`", name, descr));
+ let code = format!("#[{}({})]", name, descr);
+ msg.push_str(&format!("`{}`", &code));
+ suggestions.push(code);
}
if let Some(descr) = template.name_value_str {
if !first {
msg.push_str(" or ");
}
- msg.push_str(&format!("`#[{} = \"{}\"]`", name, descr));
+ let code = format!("#[{} = \"{}\"]", name, descr);
+ msg.push_str(&format!("`{}`", &code));
+ suggestions.push(code);
}
if should_warn(name) {
self.context.parse_sess.buffer_lint(
&msg,
);
} else {
- self.context.parse_sess.span_diagnostic.span_err(meta.span, &msg);
+ self.context.parse_sess.span_diagnostic.struct_span_err(meta.span, &error_msg)
+ .span_suggestions(
+ meta.span,
+ if suggestions.len() == 1 {
+ "must be of the form"
+ } else {
+ "the following are the possible correct uses"
+ },
+ suggestions.into_iter(),
+ Applicability::HasPlaceholders,
+ ).emit();
}
}
Err(mut err) => err.emit(),
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) {
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();
+ None => 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();
+ }
}
}
}
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)
}
}
let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed");
if let Some(reason) = reason {
err.span_note(span, reason);
+ } else {
+ err.span_label(span, "feature has been removed");
}
err.emit();
}
None => continue,
};
+ let bad_input = |span| {
+ struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input")
+ };
+
for mi in list {
let name = match mi.ident() {
Some(ident) if mi.is_word() => ident.name,
- _ => {
- span_err!(span_handler, mi.span(), E0556,
- "malformed feature, expected just one word");
+ Some(ident) => {
+ bad_input(mi.span()).span_suggestion(
+ mi.span(),
+ "expected just one word",
+ format!("{}", ident.name),
+ Applicability::MaybeIncorrect,
+ ).emit();
+ continue
+ }
+ None => {
+ bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit();
continue
}
};