// was set. This is most important for knowing when a particular feature became
// stable (active).
//
-// NB: The featureck.py script parses this information directly out of the source
-// so take care when modifying it.
+// NB: tools/tidy/src/features.rs parses this information directly out of the
+// source, so take care when modifying it.
declare_features! (
(active, asm, "1.0.0", Some(29722)),
// #[doc(cfg(...))]
(active, doc_cfg, "1.21.0", Some(43781)),
+
+ // allow `#[must_use]` on functions (RFC 1940)
+ (active, fn_must_use, "1.21.0", Some(43302)),
);
declare_features! (
}
macro_rules! gate_feature_fn {
- ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
- let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
+ ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
+ let (cx, has_feature, span,
+ name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level);
let has_feature: bool = has_feature(&$cx.features);
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
if !has_feature && !span.allows_unstable() {
- emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
+ leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level)
+ .emit();
}
}}
}
macro_rules! gate_feature {
($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
- gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain)
- }
+ gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
+ stringify!($feature), $explain, GateStrength::Hard)
+ };
+ ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {
+ gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
+ stringify!($feature), $explain, $level)
+ };
}
impl<'a> Context<'a> {
for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
if name == n {
if let Gated(_, name, desc, ref has_feature) = *gateage {
- gate_feature_fn!(self, has_feature, attr.span, name, desc);
+ gate_feature_fn!(self, has_feature, attr.span, name, desc, GateStrength::Hard);
}
debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
return;
Library(Option<u32>)
}
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum GateStrength {
+ /// A hard error. (Most feature gates should use this.)
+ Hard,
+ /// Only a warning. (Use this only as backwards-compatibility demands.)
+ Soft,
+}
+
pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
explain: &str) {
feature_err(sess, feature, span, issue, explain).emit();
}
pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
- explain: &str) -> DiagnosticBuilder<'a> {
+ explain: &str) -> DiagnosticBuilder<'a> {
+ leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard)
+}
+
+fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
+ explain: &str, level: GateStrength) -> DiagnosticBuilder<'a> {
let diag = &sess.span_diagnostic;
let issue = match issue {
GateIssue::Library(lib) => lib,
};
- let mut err = if let Some(n) = issue {
- diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
+ let explanation = if let Some(n) = issue {
+ format!("{} (see issue #{})", explain, n)
} else {
- diag.struct_span_err(span, explain)
+ explain.to_owned()
+ };
+
+ let mut err = match level {
+ GateStrength::Hard => diag.struct_span_err(span, &explanation),
+ GateStrength::Soft => diag.struct_span_warn(span, &explanation),
};
// #23973: do not suggest `#![feature(...)]` if we are in beta/stable
feature));
}
+ // If we're on stable and only emitting a "soft" warning, add a note to
+ // clarify that the feature isn't "on" (rather than being on but
+ // warning-worthy).
+ if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft {
+ err.help("a nightly build of the compiler is required to enable this feature");
+ }
+
err
+
}
const EXPLAIN_BOX_SYNTAX: &'static str =
if !span.allows_unstable() {
gate_feature!(cx.context, $feature, span, $explain)
}
+ }};
+ ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
+ let (cx, span) = ($cx, $span);
+ if !span.allows_unstable() {
+ gate_feature!(cx.context, $feature, span, $explain, $level)
+ }
}}
}
fn visit_item(&mut self, i: &'a ast::Item) {
match i.node {
ast::ItemKind::ExternCrate(_) => {
- if attr::contains_name(&i.attrs[..], "macro_reexport") {
- gate_feature_post!(&self, macro_reexport, i.span,
+ if let Some(attr) = attr::find_by_name(&i.attrs[..], "macro_reexport") {
+ gate_feature_post!(&self, macro_reexport, attr.span,
"macros reexports are experimental \
and possibly buggy");
}
function may change over time, for now \
a top-level `fn main()` is required");
}
+ if let Some(attr) = attr::find_by_name(&i.attrs[..], "must_use") {
+ gate_feature_post!(&self, fn_must_use, attr.span,
+ "`#[must_use]` on functions is experimental",
+ GateStrength::Soft);
+ }
}
ast::ItemKind::Struct(..) => {
- if attr::contains_name(&i.attrs[..], "simd") {
- gate_feature_post!(&self, simd, i.span,
+ if let Some(attr) = attr::find_by_name(&i.attrs[..], "simd") {
+ gate_feature_post!(&self, simd, attr.span,
"SIMD types are experimental and possibly buggy");
- self.context.parse_sess.span_diagnostic.span_warn(i.span,
+ self.context.parse_sess.span_diagnostic.span_warn(attr.span,
"the `#[simd]` attribute \
is deprecated, use \
`#[repr(simd)]` instead");
}
- for attr in &i.attrs {
- if attr.path == "repr" {
- for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
- if item.check_name("simd") {
- gate_feature_post!(&self, repr_simd, i.span,
- "SIMD types are experimental \
- and possibly buggy");
-
- }
- if item.check_name("align") {
- gate_feature_post!(&self, repr_align, i.span,
- "the struct `#[repr(align(u16))]` attribute \
- is experimental");
- }
+ if let Some(attr) = attr::find_by_name(&i.attrs[..], "repr") {
+ for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
+ if item.check_name("simd") {
+ gate_feature_post!(&self, repr_simd, attr.span,
+ "SIMD types are experimental and possibly buggy");
+ }
+ if item.check_name("align") {
+ gate_feature_post!(&self, repr_align, attr.span,
+ "the struct `#[repr(align(u16))]` attribute \
+ is experimental");
}
}
}
and possibly buggy");
}
- ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => {
+ ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, ref impl_items) => {
if polarity == ast::ImplPolarity::Negative {
gate_feature_post!(&self, optin_builtin_traits,
i.span,
i.span,
"specialization is unstable");
}
+
+ for impl_item in impl_items {
+ if let ast::ImplItemKind::Method(..) = impl_item.node {
+ if let Some(attr) = attr::find_by_name(&impl_item.attrs[..], "must_use") {
+ gate_feature_post!(&self, fn_must_use, attr.span,
+ "`#[must_use]` on methods is experimental",
+ GateStrength::Soft);
+ }
+ }
+ }
}
ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {