// don't have any lint names (`#[level(reason = "foo")]`)
if let ast::LitKind::Str(rationale, _) = name_value.kind {
if !self.sess.features_untracked().lint_reasons {
- feature_gate::emit_feature_err(
+ feature_gate::feature_err(
&self.sess.parse_sess,
sym::lint_reasons,
item.span,
- feature_gate::GateIssue::Language,
"lint reasons are experimental"
- );
+ )
+ .emit();
}
reason = Some(rationale);
} else {
use crate::middle::privacy::AccessLevels;
use crate::session::{DiagnosticMessageId, Session};
use errors::DiagnosticBuilder;
+use rustc_feature::GateIssue;
use syntax::symbol::{Symbol, sym};
use syntax_pos::{Span, MultiSpan};
use syntax::ast::{Attribute, CRATE_NODE_ID};
use syntax::errors::Applicability;
-use syntax::feature_gate::{GateIssue, emit_feature_err};
+use syntax::feature_gate::{feature_err, feature_err_issue};
use syntax::attr::{self, Stability, Deprecation, RustcDeprecation};
use crate::ty::{self, TyCtxt};
use crate::util::nodemap::{FxHashSet, FxHashMap};
if is_soft {
soft_handler(lint::builtin::SOFT_UNSTABLE, span, &msg)
} else {
- emit_feature_err(
- &sess.parse_sess, feature, span, GateIssue::Library(issue), &msg
- );
+ feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg)
+ .emit();
}
}
}
let ty = self.tcx.type_of(def_id);
if adt_def.has_dtor(self.tcx) {
- emit_feature_err(&self.tcx.sess.parse_sess,
- sym::untagged_unions, item.span, GateIssue::Language,
- "unions with `Drop` implementations are unstable");
+ feature_err(
+ &self.tcx.sess.parse_sess, sym::untagged_unions, item.span,
+ "unions with `Drop` implementations are unstable"
+ )
+ .emit();
} else {
let param_env = self.tcx.param_env(def_id);
if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
- emit_feature_err(&self.tcx.sess.parse_sess,
- sym::untagged_unions, item.span, GateIssue::Language,
- "unions with non-`Copy` fields are unstable");
+ feature_err(
+ &self.tcx.sess.parse_sess, sym::untagged_unions, item.span,
+ "unions with non-`Copy` fields are unstable"
+ )
+ .emit();
}
}
}
}
impl Feature {
- // FIXME(Centril): privatize again.
- pub fn issue(&self) -> Option<NonZeroU32> {
+ fn issue(&self) -> Option<NonZeroU32> {
self.issue.and_then(|i| NonZeroU32::new(i))
}
}
}
}
+fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
+ if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
+ // FIXME (#28244): enforce that active features have issue numbers
+ // assert!(info.issue().is_some())
+ info.issue()
+ } else {
+ // search in Accepted, Removed, or Stable Removed features
+ let found = ACCEPTED_FEATURES
+ .iter()
+ .chain(REMOVED_FEATURES)
+ .chain(STABLE_REMOVED_FEATURES)
+ .find(|t| t.name == feature);
+ match found {
+ Some(found) => found.issue(),
+ None => panic!("feature `{}` is not declared anywhere", feature),
+ }
+ }
+}
+
+pub enum GateIssue {
+ Language,
+ Library(Option<NonZeroU32>)
+}
+
+pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZeroU32> {
+ match issue {
+ GateIssue::Language => find_lang_feature_issue(feature),
+ GateIssue::Library(lib) => lib,
+ }
+}
+
pub use accepted::ACCEPTED_FEATURES;
pub use active::{ACTIVE_FEATURES, Features, INCOMPLETE_FEATURES};
pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
use rustc_target::spec::abi::Abi;
use syntax::attr;
use syntax::source_map::Span;
-use syntax::feature_gate::{self, GateIssue};
+use syntax::feature_gate::feature_err;
use syntax::symbol::{kw, sym, Symbol};
use syntax::{span_err, struct_span_err};
}
}
if lib.cfg.is_some() && !self.tcx.features().link_cfg {
- feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
- sym::link_cfg,
- span.unwrap(),
- GateIssue::Language,
- "is unstable");
+ feature_err(&self.tcx.sess.parse_sess, sym::link_cfg, span.unwrap(), "is unstable")
+ .emit();
}
if lib.kind == cstore::NativeStaticNobundle &&
- !self.tcx.features().static_nobundle {
- feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
- sym::static_nobundle,
- span.unwrap_or_else(|| syntax_pos::DUMMY_SP),
- GateIssue::Language,
- "kind=\"static-nobundle\" is unstable");
+ !self.tcx.features().static_nobundle
+ {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::static_nobundle,
+ span.unwrap_or_else(|| syntax_pos::DUMMY_SP),
+ "kind=\"static-nobundle\" is unstable"
+ )
+ .emit();
}
if lib.kind == cstore::NativeRawDylib &&
!self.tcx.features().raw_dylib {
- feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
- sym::raw_dylib,
- span.unwrap_or_else(|| syntax_pos::DUMMY_SP),
- GateIssue::Language,
- "kind=\"raw-dylib\" is unstable");
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::raw_dylib,
+ span.unwrap_or_else(|| syntax_pos::DUMMY_SP),
+ "kind=\"raw-dylib\" is unstable"
+ )
+ .emit();
}
self.libs.push(lib);
}
use rustc::mir::BorrowKind;
use rustc::session::config::nightly_options;
use rustc::ty::TyCtxt;
-use syntax::feature_gate::{emit_feature_err, GateIssue};
+use syntax::feature_gate::feature_err;
use syntax::symbol::sym;
use syntax_pos::{Span, Symbol};
}
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- emit_feature_err(
+ feature_err(
&item.tcx.sess.parse_sess,
sym::const_panic,
span,
- GateIssue::Language,
&format!("panicking in {}s is unstable", item.const_kind()),
- );
+ )
+ .emit();
}
}
}
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- emit_feature_err(
+ feature_err(
&item.tcx.sess.parse_sess,
sym::const_compare_raw_pointers,
span,
- GateIssue::Language,
&format!("comparing raw pointers inside {}", item.const_kind()),
- );
+ )
+ .emit();
}
}
}
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- emit_feature_err(
- &item.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
- span, GateIssue::Language,
+ feature_err(
+ &item.tcx.sess.parse_sess, sym::const_raw_ptr_deref, span,
&format!(
"dereferencing raw pointers in {}s is unstable",
item.const_kind(),
),
- );
+ )
+ .emit();
}
}
}
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- emit_feature_err(
- &item.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast,
- span, GateIssue::Language,
+ feature_err(
+ &item.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast, span,
&format!(
"casting pointers to integers in {}s is unstable",
item.const_kind(),
),
- );
+ )
+ .emit();
}
}
}
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- emit_feature_err(
- &item.tcx.sess.parse_sess, sym::const_transmute,
- span, GateIssue::Language,
- &format!("The use of std::mem::transmute() \
- is gated in {}s", item.const_kind()));
+ feature_err(
+ &item.tcx.sess.parse_sess, sym::const_transmute, span,
+ &format!("The use of std::mem::transmute() is gated in {}s", item.const_kind())
+ )
+ .emit();
}
}
}
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- emit_feature_err(
- &item.tcx.sess.parse_sess, sym::const_fn_union,
- span, GateIssue::Language,
+ feature_err(
+ &item.tcx.sess.parse_sess, sym::const_fn_union, span,
"unions in const fn are unstable",
- );
+ )
+ .emit();
}
}
use crate::validate_attr;
use rustc_feature::Features;
use syntax::attr::HasAttrs;
-use syntax::feature_gate::{feature_err, get_features, GateIssue};
+use syntax::feature_gate::{feature_err, get_features};
use syntax::attr;
use syntax::ast;
use syntax::edition::Edition;
let mut err = feature_err(self.sess,
sym::stmt_expr_attributes,
attr.span,
- GateIssue::Language,
"attributes on expressions are experimental");
if attr.is_doc_comment() {
use rustc::ty::query::Providers;
use rustc_feature::Features;
use syntax::ast::Mutability;
-use syntax::feature_gate::{emit_feature_err, GateIssue};
+use syntax::feature_gate::feature_err;
use syntax::span_err;
use syntax_pos::{sym, Span};
use rustc_error_codes::*;
| NonConstExpr::Match(hir::MatchSource::Normal)
| NonConstExpr::Match(hir::MatchSource::IfDesugar { .. })
| NonConstExpr::Match(hir::MatchSource::IfLetDesugar { .. })
- => emit_feature_err(
- &self.tcx.sess.parse_sess,
- sym::const_if_match,
- span,
- GateIssue::Language,
- &msg
- ),
+ => feature_err(&self.tcx.sess.parse_sess, sym::const_if_match, span, &msg).emit(),
_ => span_err!(self.tcx.sess, span, E0744, "{}", msg),
}
use syntax::ast::{self, NodeId, Ident};
use syntax::attr::{self, StabilityLevel};
use syntax::edition::Edition;
-use syntax::feature_gate::{emit_feature_err, GateIssue};
+use syntax::feature_gate::feature_err;
use syntax::print::pprust;
use syntax_expand::base::{self, InvocationRes, Indeterminate};
use syntax_expand::base::SyntaxExtension;
segment.ident.as_str().starts_with("rustc") {
let msg =
"attributes starting with `rustc` are reserved for use by the `rustc` compiler";
- emit_feature_err(
- &self.session.parse_sess,
- sym::rustc_attrs,
- segment.ident.span,
- GateIssue::Language,
- msg,
- );
+ feature_err(&self.session.parse_sess, sym::rustc_attrs, segment.ident.span, msg)
+ .emit();
}
}
use smallvec::SmallVec;
use syntax::ast;
use syntax::errors::pluralize;
-use syntax::feature_gate::{GateIssue, emit_feature_err};
+use syntax::feature_gate::feature_err;
use syntax::util::lev_distance::find_best_match_for_name;
use syntax::symbol::sym;
use syntax_pos::{DUMMY_SP, Span, MultiSpan};
} else {
"parenthetical notation is only stable when used with `Fn`-family traits"
};
- emit_feature_err(&self.tcx().sess.parse_sess, sym::unboxed_closures,
- span, GateIssue::Language, msg);
+ feature_err(&self.tcx().sess.parse_sess, sym::unboxed_closures, span, msg).emit();
}
self.create_substs_for_ast_path(span,
}
if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
- feature_gate::emit_feature_err(
+ feature_gate::feature_err(
&self.tcx.sess.parse_sess,
sym::unsized_tuple_coercion,
self.cause.span,
- feature_gate::GateIssue::Language,
"unsized tuple coercion is not stable enough for use and is subject to change",
- );
+ )
+ .emit();
}
Ok(coercion)
use syntax_pos::hygiene::DesugaringKind;
use syntax::ast;
use syntax::attr;
-use syntax::feature_gate::{GateIssue, emit_feature_err};
+use syntax::feature_gate::feature_err;
use syntax::source_map::{DUMMY_SP, original_sp};
use syntax::symbol::{kw, sym, Ident};
use syntax::util::parser::ExprPrecedence;
if adt.is_enum() {
if !tcx.features().transparent_enums {
- emit_feature_err(
+ feature_err(
&tcx.sess.parse_sess,
sym::transparent_enums,
sp,
- GateIssue::Language,
"transparent enums are unstable",
- );
+ )
+ .emit();
}
if adt.variants.len() != 1 {
bad_variant_count(tcx, adt, sp, def_id);
}
if adt.is_union() && !tcx.features().transparent_unions {
- emit_feature_err(&tcx.sess.parse_sess,
- sym::transparent_unions,
- sp,
- GateIssue::Language,
- "transparent unions are unstable");
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::transparent_unions,
+ sp,
+ "transparent unions are unstable",
+ )
+ .emit();
}
// For each field, figure out if it's known to be a ZST and align(1)
let repr_type_ty = def.repr.discr_type().to_ty(tcx);
if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
if !tcx.features().repr128 {
- emit_feature_err(&tcx.sess.parse_sess,
- sym::repr128,
- sp,
- GateIssue::Language,
- "repr with 128-bit type is unstable");
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::repr128,
+ sp,
+ "repr with 128-bit type is unstable",
+ )
+ .emit();
}
}
use rustc::infer::opaque_types::may_define_opaque_type;
use syntax::ast;
-use syntax::feature_gate::{self, GateIssue};
+use syntax::feature_gate;
use syntax_pos::Span;
use syntax::symbol::sym;
use errors::DiagnosticBuilder;
&fcx.tcx.sess.parse_sess,
sym::arbitrary_self_types,
span,
- GateIssue::Language,
&format!(
"`{}` cannot be used as the type of `self` without \
the `arbitrary_self_types` feature",
receiver_ty,
),
- ).help(HELP_FOR_SELF_TYPE)
+ )
+ .help(HELP_FOR_SELF_TYPE)
.emit();
} else {
// Report error; would not have worked with `arbitrary_self_types`.
_ => None,
};
if let Some(unsupported_type) = err {
- feature_gate::emit_feature_err(
+ feature_gate::feature_err(
&tcx.sess.parse_sess,
sym::const_compare_raw_pointers,
hir_ty.span,
- feature_gate::GateIssue::Language,
&format!(
"using {} as const generic parameters is unstable",
unsupported_type
),
- );
+ )
+ .emit();
};
}
if ty::search_for_structural_match_violation(
None => true,
};
if !allowed && id.is_local() {
- feature_gate::emit_feature_err(
+ feature_gate::feature_err(
&tcx.sess.parse_sess,
feature_gate.unwrap(),
item.span(),
- feature_gate::GateIssue::Language,
&format!("the target feature `{}` is currently unstable", feature),
- );
+ )
+ .emit();
}
Some(Symbol::intern(feature))
}));
use super::{mark_used, MetaItemKind};
use crate::ast::{self, Attribute, MetaItem, NestedMetaItem};
-use crate::feature_gate::{emit_feature_err, GateIssue};
+use crate::feature_gate::feature_err;
use crate::print::pprust;
use crate::sess::ParseSess;
let (cfg, feature, has_feature) = gated_cfg;
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
let explain = format!("`cfg({})` is experimental and subject to change", cfg);
- emit_feature_err(sess, *feature, cfg_span, GateIssue::Language, &explain);
+ feature_err(sess, *feature, cfg_span, &explain).emit()
}
}
use rustc_feature::{ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
use rustc_feature::{Features, Feature, State as FeatureState, UnstableFeatures};
+use rustc_feature::{find_feature_issue, GateIssue};
use crate::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId};
use crate::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
use rustc_error_codes::*;
-use std::num::NonZeroU32;
-
macro_rules! gate_feature_fn {
($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
let (cx, has_feature, span,
PostExpansionVisitor { parse_sess, features }.visit_attribute(attr)
}
-fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
- if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
- // FIXME (#28244): enforce that active features have issue numbers
- // assert!(info.issue().is_some())
- info.issue()
- } else {
- // search in Accepted, Removed, or Stable Removed features
- let found = ACCEPTED_FEATURES
- .iter()
- .chain(REMOVED_FEATURES)
- .chain(STABLE_REMOVED_FEATURES)
- .find(|t| t.name == feature);
- match found {
- Some(found) => found.issue(),
- None => panic!("feature `{}` is not declared anywhere", feature),
- }
- }
-}
-
-pub enum GateIssue {
- Language,
- Library(Option<NonZeroU32>)
-}
-
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum GateStrength {
/// A hard error. (Most feature gates should use this.)
Soft,
}
-pub fn emit_feature_err(
- sess: &ParseSess,
+pub fn feature_err<'a>(
+ sess: &'a ParseSess,
feature: Symbol,
- span: Span,
- issue: GateIssue,
+ span: impl Into<MultiSpan>,
explain: &str,
-) {
- feature_err(sess, feature, span, issue, explain).emit();
+) -> DiagnosticBuilder<'a> {
+ feature_err_issue(sess, feature, span, GateIssue::Language, explain)
}
-pub fn feature_err<'a, S: Into<MultiSpan>>(
+pub fn feature_err_issue<'a>(
sess: &'a ParseSess,
feature: Symbol,
- span: S,
+ span: impl Into<MultiSpan>,
issue: GateIssue,
explain: &str,
) -> DiagnosticBuilder<'a> {
leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard)
}
-fn leveled_feature_err<'a, S: Into<MultiSpan>>(
+fn leveled_feature_err<'a>(
sess: &'a ParseSess,
feature: Symbol,
- span: S,
+ span: impl Into<MultiSpan>,
issue: GateIssue,
explain: &str,
level: GateStrength,
) -> DiagnosticBuilder<'a> {
let diag = &sess.span_diagnostic;
- let issue = match issue {
- GateIssue::Language => find_lang_feature_issue(feature),
- GateIssue::Library(lib) => lib,
- };
-
let mut err = match level {
GateStrength::Hard => {
diag.struct_span_err_with_code(span, explain, stringify_error_code!(E0658))
GateStrength::Soft => diag.struct_span_warn(span, explain),
};
- if let Some(n) = issue {
+ if let Some(n) = find_feature_issue(feature, issue) {
err.note(&format!(
"for more information, see https://github.com/rust-lang/rust/issues/{}",
n,
self.parse_sess,
sym::arbitrary_enum_discriminant,
discriminant_spans.clone(),
- crate::feature_gate::GateIssue::Language,
"custom discriminant values are not allowed in enums with tuple or struct variants",
);
for sp in discriminant_spans {
pub mod entry;
pub mod feature_gate {
mod check;
- pub use check::{
- check_crate, check_attribute, get_features, feature_err, emit_feature_err,
- GateIssue,
- };
+ pub use check::{check_crate, check_attribute, get_features, feature_err, feature_err_issue};
}
pub mod mut_visit;
pub mod ptr;
use syntax::ast::{MacStmtStyle, StmtKind, ItemKind};
use syntax::attr::{self, HasAttrs, is_builtin_attr};
use syntax::source_map::respan;
-use syntax::feature_gate::{self, GateIssue, emit_feature_err};
+use syntax::feature_gate::{self, feature_err};
use syntax::mut_visit::*;
use syntax::print::pprust;
use syntax::ptr::P;
if self.cx.ecfg.proc_macro_hygiene() {
return
}
- emit_feature_err(
+ feature_err(
self.cx.parse_sess,
sym::proc_macro_hygiene,
span,
- GateIssue::Language,
&format!("custom attributes cannot be applied to {}", kind),
- );
+ )
+ .emit();
}
fn gate_proc_macro_input(&self, annotatable: &Annotatable) {
fn visit_item(&mut self, item: &'ast ast::Item) {
match &item.kind {
ast::ItemKind::Mod(module) if !module.inline => {
- emit_feature_err(
+ feature_err(
self.parse_sess,
sym::proc_macro_hygiene,
item.span,
- GateIssue::Language,
"non-inline modules in proc macro input are unstable",
- );
+ )
+ .emit();
}
_ => {}
}
if self.cx.ecfg.proc_macro_hygiene() {
return
}
- emit_feature_err(
+ feature_err(
self.cx.parse_sess,
sym::proc_macro_hygiene,
span,
- GateIssue::Language,
&format!("procedural macros cannot be expanded to {}", kind),
- );
+ )
+ .emit();
}
fn parse_ast_fragment(
if let Some(attr) = &attr {
if !self.cx.ecfg.custom_inner_attributes() &&
attr.style == ast::AttrStyle::Inner && !attr.has_name(sym::test) {
- emit_feature_err(&self.cx.parse_sess, sym::custom_inner_attributes,
- attr.span, GateIssue::Language,
- "non-builtin inner attributes are unstable");
+ feature_err(
+ &self.cx.parse_sess, sym::custom_inner_attributes, attr.span,
+ "non-builtin inner attributes are unstable"
+ )
+ .emit();
}
}
attr