Rollup merge of #66895 - Centril:rustc_feature, r=oli-obk
Feature gating *declarations* => new crate `rustc_feature` This PR moves the data-oriented parts of feature gating into its own crate, `rustc_feature`. The parts consist of some data types as well as `accepted`, `active`, `removed`, and `builtin_attrs`. Feature gate checking itself remains in `syntax::feature_gate::check`. The parts which define how to emit feature gate errors could probably be moved to `rustc_errors` or to the new `rustc_session` crate introduced in #66878. The visitor itself could probably be moved as a pass in `rustc_passes` depending on how the dependency edges work out. The PR also contains some drive-by cleanup of feature gate checking. As such, the PR probably best read commit-by-commit. r? @oli-obk cc @petrochenkov cc @Mark-Simulacrum
This commit is contained in:
commit
b772b5b19d
18
Cargo.lock
18
Cargo.lock
|
@ -3199,6 +3199,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fs_util",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
|
@ -3574,6 +3575,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_interface",
|
||||
"rustc_lint",
|
||||
"rustc_metadata",
|
||||
|
@ -3607,6 +3609,15 @@ dependencies = [
|
|||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_feature"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"lazy_static 1.3.0",
|
||||
"rustc_data_structures",
|
||||
"syntax_pos",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_fs_util"
|
||||
version = "0.0.0"
|
||||
|
@ -3682,6 +3693,7 @@ dependencies = [
|
|||
"rustc",
|
||||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_feature",
|
||||
"rustc_index",
|
||||
"rustc_target",
|
||||
"syntax",
|
||||
|
@ -3786,6 +3798,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_lexer",
|
||||
"rustc_target",
|
||||
"smallvec 1.0.0",
|
||||
|
@ -3802,6 +3815,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_index",
|
||||
"rustc_parse",
|
||||
"rustc_target",
|
||||
|
@ -3844,6 +3858,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_metadata",
|
||||
"smallvec 1.0.0",
|
||||
"syntax",
|
||||
|
@ -4442,6 +4457,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_index",
|
||||
"rustc_lexer",
|
||||
"rustc_macros",
|
||||
|
@ -4458,6 +4474,7 @@ dependencies = [
|
|||
"log",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_lexer",
|
||||
"rustc_parse",
|
||||
"serialize",
|
||||
|
@ -4475,6 +4492,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_parse",
|
||||
"rustc_target",
|
||||
"smallvec 1.0.0",
|
||||
|
|
|
@ -22,6 +22,7 @@ rustc-rayon = "0.3.0"
|
|||
rustc-rayon-core = "0.3.0"
|
||||
polonius-engine = "0.10.0"
|
||||
rustc_apfloat = { path = "../librustc_apfloat" }
|
||||
rustc_feature = { path = "../librustc_feature" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_macros = { path = "../librustc_macros" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
|
|
|
@ -101,7 +101,7 @@ macro_rules! arena_types {
|
|||
[few] resolve_lifetimes: rustc::middle::resolve_lifetime::ResolveLifetimes,
|
||||
[few] lint_levels: rustc::lint::LintLevelMap,
|
||||
[few] stability_index: rustc::middle::stability::Index<'tcx>,
|
||||
[few] features: syntax::feature_gate::Features,
|
||||
[few] features: rustc_feature::Features,
|
||||
[few] all_traits: Vec<rustc::hir::def_id::DefId>,
|
||||
[few] privacy_access_levels: rustc::middle::privacy::AccessLevels,
|
||||
[few] target_features_whitelist: rustc_data_structures::fx::FxHashMap<
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
use crate::ich::StableHashingContext;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::feature_gate;
|
||||
use syntax_pos::SourceFile;
|
||||
|
||||
use crate::hir::def_id::{DefId, CrateNum, CRATE_DEF_INDEX};
|
||||
|
@ -156,7 +155,7 @@ fn stable_normalized_pos(np: ::syntax_pos::NormalizedPos,
|
|||
}
|
||||
|
||||
|
||||
impl<'tcx> HashStable<StableHashingContext<'tcx>> for feature_gate::Features {
|
||||
impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
|
||||
fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
|
||||
// Unfortunately we cannot exhaustively list fields here, since the
|
||||
// struct is macro generated.
|
||||
|
|
|
@ -232,13 +232,13 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
// 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 {
|
||||
|
|
|
@ -13,11 +13,12 @@ use crate::ty::query::Providers;
|
|||
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};
|
||||
|
@ -512,9 +513,8 @@ pub fn report_unstable(
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -842,15 +842,19 @@ impl Visitor<'tcx> for Checker<'tcx> {
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1130,7 +1130,7 @@ rustc_queries! {
|
|||
desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) }
|
||||
}
|
||||
|
||||
query features_query(_: CrateNum) -> &'tcx feature_gate::Features {
|
||||
query features_query(_: CrateNum) -> &'tcx rustc_feature::Features {
|
||||
eval_always
|
||||
desc { "looking up enabled feature gates" }
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::session::{early_error, early_warn, Session};
|
|||
use crate::session::search_paths::SearchPath;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
|
||||
use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
|
||||
use rustc_target::spec::{Target, TargetTriple};
|
||||
|
@ -16,7 +17,6 @@ use syntax::ast;
|
|||
use syntax::source_map::{FileName, FilePathMapping};
|
||||
use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
|
||||
use syntax::symbol::{sym, Symbol};
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
|
||||
use errors::emitter::HumanReadableErrorType;
|
||||
use errors::{ColorConfig, FatalError, Handler};
|
||||
|
@ -2701,7 +2701,7 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
|
|||
|
||||
pub mod nightly_options {
|
||||
use getopts;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use super::{ErrorOutputType, OptionStability, RustcOptGroup};
|
||||
use crate::session::early_error;
|
||||
|
||||
|
@ -2850,9 +2850,9 @@ mod dep_tracking {
|
|||
use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
|
||||
Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
|
||||
SymbolManglingVersion};
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
|
||||
use syntax::edition::Edition;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
|
||||
pub trait DepTrackingHash {
|
||||
fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
|
||||
|
|
|
@ -21,7 +21,6 @@ use errors::emitter::{Emitter, EmitterWriter};
|
|||
use errors::emitter::HumanReadableErrorType;
|
||||
use errors::annotate_snippet_emitter_writer::{AnnotateSnippetEmitterWriter};
|
||||
use syntax::edition::Edition;
|
||||
use syntax::feature_gate;
|
||||
use errors::json::JsonEmitter;
|
||||
use syntax::source_map;
|
||||
use syntax::sess::ParseSess;
|
||||
|
@ -86,7 +85,7 @@ pub struct Session {
|
|||
/// `rustc_codegen_llvm::back::symbol_names` module for more information.
|
||||
pub crate_disambiguator: Once<CrateDisambiguator>,
|
||||
|
||||
features: Once<feature_gate::Features>,
|
||||
features: Once<rustc_feature::Features>,
|
||||
|
||||
/// The maximum recursion limit for potentially infinitely recursive
|
||||
/// operations such as auto-dereference and monomorphization.
|
||||
|
@ -470,11 +469,11 @@ impl Session {
|
|||
/// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents
|
||||
/// dependency tracking. Use tcx.features() instead.
|
||||
#[inline]
|
||||
pub fn features_untracked(&self) -> &feature_gate::Features {
|
||||
pub fn features_untracked(&self) -> &rustc_feature::Features {
|
||||
self.features.get()
|
||||
}
|
||||
|
||||
pub fn init_features(&self, features: feature_gate::Features) {
|
||||
pub fn init_features(&self, features: rustc_feature::Features) {
|
||||
self.features.set(features);
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,6 @@ use rustc_macros::HashStable;
|
|||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::source_map::MultiSpan;
|
||||
use syntax::feature_gate;
|
||||
use syntax::symbol::{Symbol, kw, sym};
|
||||
use syntax_pos::Span;
|
||||
use syntax::expand::allocator::AllocatorKind;
|
||||
|
@ -1312,7 +1311,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.cstore.allocator_kind()
|
||||
}
|
||||
|
||||
pub fn features(self) -> &'tcx feature_gate::Features {
|
||||
pub fn features(self) -> &'tcx rustc_feature::Features {
|
||||
self.features_query(LOCAL_CRATE)
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,6 @@ use std::any::type_name;
|
|||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use syntax::attr;
|
||||
use syntax::ast;
|
||||
use syntax::feature_gate;
|
||||
use syntax::symbol::Symbol;
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
@ -30,6 +30,7 @@ extern crate libc;
|
|||
#[macro_use] extern crate rustc;
|
||||
extern crate rustc_target;
|
||||
#[macro_use] extern crate rustc_data_structures;
|
||||
extern crate rustc_feature;
|
||||
extern crate rustc_index;
|
||||
extern crate rustc_incremental;
|
||||
extern crate rustc_codegen_utils;
|
||||
|
|
|
@ -6,7 +6,7 @@ use rustc::session::config::PrintRequest;
|
|||
use rustc_target::spec::{MergeFunctions, PanicStrategy};
|
||||
use libc::c_int;
|
||||
use std::ffi::CString;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use syntax::symbol::sym;
|
||||
|
||||
use std::str;
|
||||
|
|
|
@ -19,6 +19,7 @@ rustc_target = { path = "../librustc_target" }
|
|||
rustc_lint = { path = "../librustc_lint" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
errors = { path = "../librustc_errors", package = "rustc_errors" }
|
||||
rustc_feature = { path = "../librustc_feature" }
|
||||
rustc_metadata = { path = "../librustc_metadata" }
|
||||
rustc_mir = { path = "../librustc_mir" }
|
||||
rustc_parse = { path = "../librustc_parse" }
|
||||
|
|
|
@ -44,7 +44,7 @@ use errors::{PResult, registry::Registry};
|
|||
use rustc_interface::interface;
|
||||
use rustc_interface::util::get_codegen_sysroot;
|
||||
use rustc_data_structures::sync::SeqCst;
|
||||
|
||||
use rustc_feature::{find_gated_cfg, UnstableFeatures};
|
||||
use rustc_serialize::json::ToJson;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
@ -61,10 +61,9 @@ use std::str;
|
|||
use std::time::Instant;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::source_map::FileLoader;
|
||||
use syntax::feature_gate::{GatedCfg, UnstableFeatures};
|
||||
use syntax::symbol::sym;
|
||||
use syntax_pos::{DUMMY_SP, FileName};
|
||||
use syntax_pos::source_map::FileLoader;
|
||||
use syntax_pos::symbol::sym;
|
||||
use syntax_pos::FileName;
|
||||
|
||||
pub mod pretty;
|
||||
mod args;
|
||||
|
@ -684,12 +683,6 @@ impl RustcDefaultCalls {
|
|||
.is_nightly_build();
|
||||
|
||||
let mut cfgs = sess.parse_sess.config.iter().filter_map(|&(name, ref value)| {
|
||||
let gated_cfg = GatedCfg::gate(&ast::MetaItem {
|
||||
path: ast::Path::from_ident(ast::Ident::with_dummy_span(name)),
|
||||
kind: ast::MetaItemKind::Word,
|
||||
span: DUMMY_SP,
|
||||
});
|
||||
|
||||
// Note that crt-static is a specially recognized cfg
|
||||
// directive that's printed out here as part of
|
||||
// rust-lang/rust#37406, but in general the
|
||||
|
@ -700,10 +693,11 @@ impl RustcDefaultCalls {
|
|||
// through to build scripts.
|
||||
let value = value.as_ref().map(|s| s.as_str());
|
||||
let value = value.as_ref().map(|s| s.as_ref());
|
||||
if name != sym::target_feature || value != Some("crt-static") {
|
||||
if !allow_unstable_cfg && gated_cfg.is_some() {
|
||||
return None
|
||||
}
|
||||
if (name != sym::target_feature || value != Some("crt-static"))
|
||||
&& !allow_unstable_cfg
|
||||
&& find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(value) = value {
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
name = "rustc_feature"
|
||||
version = "0.0.0"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "rustc_feature"
|
||||
path = "lib.rs"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
lazy_static = "1.0.0"
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
|
@ -1,7 +1,7 @@
|
|||
//! List of the accepted feature gates.
|
||||
|
||||
use crate::symbol::sym;
|
||||
use super::{State, Feature};
|
||||
use syntax_pos::symbol::sym;
|
||||
|
||||
macro_rules! declare_features {
|
||||
($(
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
use super::{State, Feature};
|
||||
|
||||
use crate::edition::Edition;
|
||||
use crate::symbol::{Symbol, sym};
|
||||
|
||||
use syntax_pos::edition::Edition;
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::symbol::{Symbol, sym};
|
||||
|
||||
macro_rules! set {
|
||||
($field: ident) => {{
|
||||
|
@ -37,7 +36,7 @@ macro_rules! declare_features {
|
|||
),+];
|
||||
|
||||
/// A set of features to be used by later passes.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Features {
|
||||
/// `#![feature]` attrs for language features, for error reporting.
|
||||
pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
|
||||
|
@ -50,17 +49,7 @@ macro_rules! declare_features {
|
|||
}
|
||||
|
||||
impl Features {
|
||||
pub fn new() -> Features {
|
||||
Features {
|
||||
declared_lang_features: Vec::new(),
|
||||
declared_lib_features: Vec::new(),
|
||||
$($feature: false),+
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_feature_fields<F>(&self, mut f: F)
|
||||
where F: FnMut(&str, bool)
|
||||
{
|
||||
pub fn walk_feature_fields(&self, mut f: impl FnMut(&str, bool)) {
|
||||
$(f(stringify!($feature), self.$feature);)+
|
||||
}
|
||||
}
|
|
@ -3,17 +3,10 @@
|
|||
use AttributeType::*;
|
||||
use AttributeGate::*;
|
||||
|
||||
use super::check::{emit_feature_err, GateIssue};
|
||||
use super::check::{Stability, EXPLAIN_ALLOW_INTERNAL_UNSAFE, EXPLAIN_ALLOW_INTERNAL_UNSTABLE};
|
||||
use super::active::Features;
|
||||
use crate::{Features, Stability};
|
||||
|
||||
use crate::ast;
|
||||
use crate::attr::AttributeTemplate;
|
||||
use crate::sess::ParseSess;
|
||||
use crate::symbol::{Symbol, sym};
|
||||
|
||||
use syntax_pos::Span;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use syntax_pos::symbol::{Symbol, sym};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
type GateFn = fn(&Features) -> bool;
|
||||
|
@ -24,39 +17,19 @@ macro_rules! cfg_fn {
|
|||
}
|
||||
}
|
||||
|
||||
pub type GatedCfg = (Symbol, Symbol, GateFn);
|
||||
|
||||
/// `cfg(...)`'s that are feature gated.
|
||||
const GATED_CFGS: &[(Symbol, Symbol, GateFn)] = &[
|
||||
const GATED_CFGS: &[GatedCfg] = &[
|
||||
// (name in cfg, feature, function to check if the feature is enabled)
|
||||
(sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)),
|
||||
(sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
|
||||
(sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
|
||||
];
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GatedCfg {
|
||||
span: Span,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl GatedCfg {
|
||||
pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
|
||||
GATED_CFGS.iter()
|
||||
.position(|info| cfg.check_name(info.0))
|
||||
.map(|idx| {
|
||||
GatedCfg {
|
||||
span: cfg.span,
|
||||
index: idx
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
|
||||
let (cfg, feature, has_feature) = GATED_CFGS[self.index];
|
||||
if !has_feature(features) && !self.span.allows_unstable(feature) {
|
||||
let explain = format!("`cfg({})` is experimental and subject to change", cfg);
|
||||
emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
|
||||
}
|
||||
}
|
||||
/// Find a gated cfg determined by the `pred`icate which is given the cfg's name.
|
||||
pub fn find_gated_cfg(pred: impl Fn(Symbol) -> bool) -> Option<&'static GatedCfg> {
|
||||
GATED_CFGS.iter().find(|(cfg_sym, ..)| pred(*cfg_sym))
|
||||
}
|
||||
|
||||
// If you change this, please modify `src/doc/unstable-book` as well. You must
|
||||
|
@ -108,6 +81,21 @@ impl AttributeGate {
|
|||
}
|
||||
}
|
||||
|
||||
/// A template that the attribute input must match.
|
||||
/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct AttributeTemplate {
|
||||
pub word: bool,
|
||||
pub list: Option<&'static str>,
|
||||
pub name_value_str: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl AttributeTemplate {
|
||||
pub fn only_word() -> Self {
|
||||
Self { word: true, list: None, name_value_str: None }
|
||||
}
|
||||
}
|
||||
|
||||
/// A convenience macro for constructing attribute templates.
|
||||
/// E.g., `template!(Word, List: "description")` means that the attribute
|
||||
/// supports forms `#[attr]` and `#[attr(description)]`.
|
||||
|
@ -361,9 +349,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
gated!(
|
||||
allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
|
||||
EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
|
||||
"allow_internal_unstable side-steps feature gating and stability checks",
|
||||
),
|
||||
gated!(
|
||||
allow_internal_unsafe, Normal, template!(Word),
|
||||
"allow_internal_unsafe side-steps the unsafe_code lint",
|
||||
),
|
||||
gated!(allow_internal_unsafe, Normal, template!(Word), EXPLAIN_ALLOW_INTERNAL_UNSAFE),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes: Type system related:
|
||||
|
@ -587,14 +578,10 @@ pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> {
|
|||
BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect()
|
||||
}
|
||||
|
||||
pub fn is_builtin_attr_name(name: ast::Name) -> bool {
|
||||
pub fn is_builtin_attr_name(name: Symbol) -> bool {
|
||||
BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
|
||||
}
|
||||
|
||||
pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
|
||||
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).is_some()
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref BUILTIN_ATTRIBUTE_MAP: FxHashMap<Symbol, &'static BuiltinAttribute> = {
|
||||
let mut map = FxHashMap::default();
|
|
@ -0,0 +1,137 @@
|
|||
//! # Feature gates
|
||||
//!
|
||||
//! This crate declares the set of past and present unstable features in the compiler.
|
||||
//! Feature gate checking itself is done in `libsyntax/feature_gate/check.rs` at the moment.
|
||||
//!
|
||||
//! Features are enabled in programs via the crate-level attributes of
|
||||
//! `#![feature(...)]` with a comma-separated list of features.
|
||||
//!
|
||||
//! For the purpose of future feature-tracking, once a feature gate is added,
|
||||
//! even if it is stabilized or removed, *do not remove it*. Instead, move the
|
||||
//! symbol to the `accepted` or `removed` modules respectively.
|
||||
|
||||
mod accepted;
|
||||
mod removed;
|
||||
mod active;
|
||||
mod builtin_attrs;
|
||||
|
||||
use std::fmt;
|
||||
use std::num::NonZeroU32;
|
||||
use syntax_pos::{Span, edition::Edition, symbol::Symbol};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum State {
|
||||
Accepted,
|
||||
Active { set: fn(&mut Features, Span) },
|
||||
Removed { reason: Option<&'static str> },
|
||||
Stabilized { reason: Option<&'static str> },
|
||||
}
|
||||
|
||||
impl fmt::Debug for State {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
State::Accepted { .. } => write!(f, "accepted"),
|
||||
State::Active { .. } => write!(f, "active"),
|
||||
State::Removed { .. } => write!(f, "removed"),
|
||||
State::Stabilized { .. } => write!(f, "stabilized"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Feature {
|
||||
pub state: State,
|
||||
pub name: Symbol,
|
||||
pub since: &'static str,
|
||||
issue: Option<u32>, // FIXME: once #58732 is done make this an Option<NonZeroU32>
|
||||
pub edition: Option<Edition>,
|
||||
description: &'static str,
|
||||
}
|
||||
|
||||
impl Feature {
|
||||
fn issue(&self) -> Option<NonZeroU32> {
|
||||
self.issue.and_then(|i| NonZeroU32::new(i))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Stability {
|
||||
Unstable,
|
||||
// First argument is tracking issue link; second argument is an optional
|
||||
// help message, which defaults to "remove this attribute".
|
||||
Deprecated(&'static str, Option<&'static str>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Hash)]
|
||||
pub enum UnstableFeatures {
|
||||
/// Hard errors for unstable features are active, as on beta/stable channels.
|
||||
Disallow,
|
||||
/// Allow features to be activated, as on nightly.
|
||||
Allow,
|
||||
/// Errors are bypassed for bootstrapping. This is required any time
|
||||
/// during the build that feature-related lints are set to warn or above
|
||||
/// because the build turns on warnings-as-errors and uses lots of unstable
|
||||
/// features. As a result, this is always required for building Rust itself.
|
||||
Cheat
|
||||
}
|
||||
|
||||
impl UnstableFeatures {
|
||||
pub fn from_environment() -> UnstableFeatures {
|
||||
// `true` if this is a feature-staged build, i.e., on the beta or stable channel.
|
||||
let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
|
||||
// `true` if we should enable unstable features for bootstrapping.
|
||||
let bootstrap = std::env::var("RUSTC_BOOTSTRAP").is_ok();
|
||||
match (disable_unstable_features, bootstrap) {
|
||||
(_, true) => UnstableFeatures::Cheat,
|
||||
(true, _) => UnstableFeatures::Disallow,
|
||||
(false, _) => UnstableFeatures::Allow
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_nightly_build(&self) -> bool {
|
||||
match *self {
|
||||
UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
|
||||
UnstableFeatures::Disallow => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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};
|
||||
pub use builtin_attrs::{
|
||||
AttributeGate, AttributeTemplate, AttributeType, find_gated_cfg, GatedCfg,
|
||||
BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
|
||||
deprecated_attributes, is_builtin_attr_name,
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
//! List of the removed feature gates.
|
||||
|
||||
use crate::symbol::sym;
|
||||
use super::{State, Feature};
|
||||
use syntax_pos::symbol::sym;
|
||||
|
||||
macro_rules! declare_features {
|
||||
($(
|
|
@ -15,5 +15,6 @@ rustc_target = { path = "../librustc_target" }
|
|||
syntax = { path = "../libsyntax" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_feature = { path = "../librustc_feature" }
|
||||
rustc_index = { path = "../librustc_index" }
|
||||
rustc_error_codes = { path = "../librustc_error_codes" }
|
||||
|
|
|
@ -34,15 +34,15 @@ use lint::{LateContext, LintContext, LintArray};
|
|||
use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext};
|
||||
|
||||
use rustc::util::nodemap::FxHashSet;
|
||||
use rustc_feature::{AttributeGate, AttributeTemplate, AttributeType, deprecated_attributes};
|
||||
use rustc_feature::Stability;
|
||||
|
||||
use syntax::tokenstream::{TokenTree, TokenStream};
|
||||
use syntax::ast::{self, Expr};
|
||||
use syntax::ptr::P;
|
||||
use syntax::attr::{self, HasAttrs, AttributeTemplate};
|
||||
use syntax::attr::{self, HasAttrs};
|
||||
use syntax::source_map::Spanned;
|
||||
use syntax::edition::Edition;
|
||||
use syntax::feature_gate::{self, AttributeGate, AttributeType};
|
||||
use syntax::feature_gate::{Stability, deprecated_attributes};
|
||||
use syntax_pos::{BytePos, Span};
|
||||
use syntax::symbol::{Symbol, kw, sym};
|
||||
use syntax::errors::{Applicability, DiagnosticBuilder};
|
||||
|
@ -1850,7 +1850,7 @@ impl EarlyLintPass for IncompleteFeatures {
|
|||
features.declared_lang_features
|
||||
.iter().map(|(name, span, _)| (name, span))
|
||||
.chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
|
||||
.filter(|(name, _)| feature_gate::INCOMPLETE_FEATURES.iter().any(|f| name == &f))
|
||||
.filter(|(name, _)| rustc_feature::INCOMPLETE_FEATURES.iter().any(|f| name == &f))
|
||||
.for_each(|(name, &span)| {
|
||||
cx.struct_span_lint(
|
||||
INCOMPLETE_FEATURES,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use rustc::hir;
|
||||
use rustc::hir::def::{Res, DefKind};
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::lint;
|
||||
|
@ -7,19 +8,17 @@ use rustc::ty::adjustment;
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use lint::{LateContext, EarlyContext, LintContext, LintArray};
|
||||
use lint::{LintPass, EarlyLintPass, LateLintPass};
|
||||
use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::errors::{Applicability, pluralize};
|
||||
use syntax::feature_gate::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||
use syntax::print::pprust;
|
||||
use syntax::symbol::{kw, sym};
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax::util::parser;
|
||||
use syntax_pos::{Span, BytePos};
|
||||
|
||||
use rustc::hir;
|
||||
|
||||
use log::debug;
|
||||
|
||||
declare_lint! {
|
||||
|
|
|
@ -7,7 +7,7 @@ use rustc::util::nodemap::FxHashSet;
|
|||
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};
|
||||
|
||||
|
@ -158,27 +158,29 @@ impl Collector<'tcx> {
|
|||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use rustc::hir::def_id::DefId;
|
|||
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};
|
||||
|
||||
|
@ -222,13 +222,13 @@ impl NonConstOp for Panic {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,13 +240,13 @@ impl NonConstOp for RawPtrComparison {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,14 +258,14 @@ impl NonConstOp for RawPtrDeref {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,14 +277,14 @@ impl NonConstOp for RawPtrToIntCast {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,11 +334,11 @@ impl NonConstOp for Transmute {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,10 +355,10 @@ impl NonConstOp for UnionAccess {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ syntax_pos = { path = "../libsyntax_pos" }
|
|||
syntax = { path = "../libsyntax" }
|
||||
errors = { path = "../librustc_errors", package = "rustc_errors" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_feature = { path = "../librustc_feature" }
|
||||
rustc_lexer = { path = "../librustc_lexer" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
|
||||
|
|
|
@ -9,14 +9,9 @@
|
|||
//! [#64197]: https://github.com/rust-lang/rust/issues/64197
|
||||
|
||||
use crate::validate_attr;
|
||||
use rustc_feature::Features;
|
||||
use syntax::attr::HasAttrs;
|
||||
use syntax::feature_gate::{
|
||||
feature_err,
|
||||
EXPLAIN_STMT_ATTR_SYNTAX,
|
||||
Features,
|
||||
get_features,
|
||||
GateIssue,
|
||||
};
|
||||
use syntax::feature_gate::{feature_err, get_features};
|
||||
use syntax::attr;
|
||||
use syntax::ast;
|
||||
use syntax::edition::Edition;
|
||||
|
@ -52,7 +47,7 @@ pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition,
|
|||
} else { // the entire crate is unconfigured
|
||||
krate.attrs = Vec::new();
|
||||
krate.module.items = Vec::new();
|
||||
return (krate, Features::new());
|
||||
return (krate, Features::default());
|
||||
}
|
||||
|
||||
features = get_features(&sess.span_diagnostic, &krate.attrs, edition, allow_features);
|
||||
|
@ -217,8 +212,7 @@ impl<'a> StripUnconfigured<'a> {
|
|||
let mut err = feature_err(self.sess,
|
||||
sym::stmt_expr_attributes,
|
||||
attr.span,
|
||||
GateIssue::Language,
|
||||
EXPLAIN_STMT_ATTR_SYNTAX);
|
||||
"attributes on expressions are experimental");
|
||||
|
||||
if attr.is_doc_comment() {
|
||||
err.help("`///` is for documentation comments. For a plain comment, use `//`.");
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
//! Meta-syntax validation logic of attributes for post-expansion.
|
||||
|
||||
use errors::{PResult, Applicability};
|
||||
use syntax::ast::{self, Attribute, AttrKind, Ident, MetaItem};
|
||||
use syntax::attr::{AttributeTemplate, mk_name_value_item_str};
|
||||
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
|
||||
use syntax::ast::{self, Attribute, AttrKind, Ident, MetaItem, MetaItemKind};
|
||||
use syntax::attr::mk_name_value_item_str;
|
||||
use syntax::early_buffered_lints::BufferedEarlyLintId;
|
||||
use syntax::feature_gate::BUILTIN_ATTRIBUTE_MAP;
|
||||
use syntax::token;
|
||||
use syntax::tokenstream::TokenTree;
|
||||
use syntax::sess::ParseSess;
|
||||
|
@ -41,6 +41,16 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
|
|||
})
|
||||
}
|
||||
|
||||
/// Checks that the given meta-item is compatible with this `AttributeTemplate`.
|
||||
fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool {
|
||||
match meta {
|
||||
MetaItemKind::Word => template.word,
|
||||
MetaItemKind::List(..) => template.list.is_some(),
|
||||
MetaItemKind::NameValue(lit) if lit.kind.is_str() => template.name_value_str.is_some(),
|
||||
MetaItemKind::NameValue(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_builtin_attribute(
|
||||
sess: &ParseSess,
|
||||
attr: &Attribute,
|
||||
|
@ -57,7 +67,7 @@ pub fn check_builtin_attribute(
|
|||
name == sym::test || name == sym::bench;
|
||||
|
||||
match parse_meta(sess, attr) {
|
||||
Ok(meta) => if !should_skip(name) && !template.compatible(&meta.kind) {
|
||||
Ok(meta) => if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) {
|
||||
let error_msg = format!("malformed `{}` attribute input", name);
|
||||
let mut msg = "attribute must be of the form ".to_owned();
|
||||
let mut suggestions = vec![];
|
||||
|
|
|
@ -12,6 +12,7 @@ path = "lib.rs"
|
|||
log = "0.4"
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_feature = { path = "../librustc_feature" }
|
||||
rustc_index = { path = "../librustc_index" }
|
||||
rustc_parse = { path = "../librustc_parse" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
|
|
|
@ -14,7 +14,6 @@ use rustc_parse::validate_attr;
|
|||
use syntax::ast::*;
|
||||
use syntax::attr;
|
||||
use syntax::expand::is_proc_macro_attr;
|
||||
use syntax::feature_gate::is_builtin_attr;
|
||||
use syntax::print::pprust;
|
||||
use syntax::source_map::Spanned;
|
||||
use syntax::symbol::{kw, sym};
|
||||
|
@ -257,7 +256,7 @@ impl<'a> AstValidator<'a> {
|
|||
.flat_map(|i| i.attrs.as_ref())
|
||||
.filter(|attr| {
|
||||
let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
|
||||
!arr.contains(&attr.name_or_empty()) && is_builtin_attr(attr)
|
||||
!arr.contains(&attr.name_or_empty()) && attr::is_builtin_attr(attr)
|
||||
})
|
||||
.for_each(|attr| if attr.is_doc_comment() {
|
||||
let mut err = self.err_handler().struct_span_err(
|
||||
|
|
|
@ -13,8 +13,9 @@ use rustc::hir::map::Map;
|
|||
use rustc::hir;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::ty::query::Providers;
|
||||
use rustc_feature::Features;
|
||||
use syntax::ast::Mutability;
|
||||
use syntax::feature_gate::{emit_feature_err, Features, GateIssue};
|
||||
use syntax::feature_gate::feature_err;
|
||||
use syntax::span_err;
|
||||
use syntax_pos::{sym, Span};
|
||||
use rustc_error_codes::*;
|
||||
|
@ -140,13 +141,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
|
|||
| 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),
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ arena = { path = "../libarena" }
|
|||
errors = { path = "../librustc_errors", package = "rustc_errors" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_feature = { path = "../librustc_feature" }
|
||||
rustc_metadata = { path = "../librustc_metadata" }
|
||||
rustc_error_codes = { path = "../librustc_error_codes" }
|
||||
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
|
||||
|
|
|
@ -29,10 +29,8 @@ use errors::Applicability;
|
|||
|
||||
use syntax::ast::{Name, Ident};
|
||||
use syntax::attr;
|
||||
|
||||
use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
|
||||
use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind};
|
||||
use syntax::feature_gate::is_builtin_attr;
|
||||
use syntax::token::{self, Token};
|
||||
use syntax::print::pprust;
|
||||
use syntax::{span_err, struct_span_err};
|
||||
|
@ -1231,7 +1229,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
|
|||
}
|
||||
|
||||
fn visit_attribute(&mut self, attr: &'b ast::Attribute) {
|
||||
if !attr.is_doc_comment() && is_builtin_attr(attr) {
|
||||
if !attr.is_doc_comment() && attr::is_builtin_attr(attr) {
|
||||
self.r.builtin_attrs.push(
|
||||
(attr.get_normal_item().path.segments[0].ident, self.parent_scope)
|
||||
);
|
||||
|
|
|
@ -9,8 +9,8 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
|
|||
use rustc::session::Session;
|
||||
use rustc::ty::{self, DefIdTree};
|
||||
use rustc::util::nodemap::FxHashSet;
|
||||
use rustc_feature::BUILTIN_ATTRIBUTES;
|
||||
use syntax::ast::{self, Ident, Path};
|
||||
use syntax::feature_gate::BUILTIN_ATTRIBUTES;
|
||||
use syntax::source_map::SourceMap;
|
||||
use syntax::struct_span_err;
|
||||
use syntax::symbol::{Symbol, kw};
|
||||
|
|
|
@ -12,18 +12,18 @@ use rustc::middle::stability;
|
|||
use rustc::session::Session;
|
||||
use rustc::util::nodemap::FxHashSet;
|
||||
use rustc::{ty, lint, span_bug};
|
||||
use rustc_feature::is_builtin_attr_name;
|
||||
use syntax::ast::{self, NodeId, Ident};
|
||||
use syntax::attr::{self, StabilityLevel};
|
||||
use syntax::edition::Edition;
|
||||
use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name};
|
||||
use syntax::feature_gate::GateIssue;
|
||||
use syntax::feature_gate::feature_err;
|
||||
use syntax::print::pprust;
|
||||
use syntax::symbol::{Symbol, kw, sym};
|
||||
use syntax_expand::base::{self, InvocationRes, Indeterminate};
|
||||
use syntax_expand::base::SyntaxExtension;
|
||||
use syntax_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
|
||||
use syntax_expand::compile_declarative_macro;
|
||||
use syntax_pos::hygiene::{self, ExpnId, ExpnData, ExpnKind};
|
||||
use syntax_pos::symbol::{Symbol, kw, sym};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
use std::{mem, ptr};
|
||||
|
@ -346,13 +346,8 @@ impl<'a> Resolver<'a> {
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ use crate::require_c_abi_if_c_variadic;
|
|||
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};
|
||||
|
@ -914,8 +914,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
} 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,
|
||||
|
|
|
@ -644,11 +644,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
}
|
||||
|
||||
if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
|
||||
feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
|
||||
sym::unsized_tuple_coercion,
|
||||
self.cause.span,
|
||||
feature_gate::GateIssue::Language,
|
||||
feature_gate::EXPLAIN_UNSIZED_TUPLE_COERCION);
|
||||
feature_gate::feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
sym::unsized_tuple_coercion,
|
||||
self.cause.span,
|
||||
"unsized tuple coercion is not stable enough for use and is subject to change",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
Ok(coercion)
|
||||
|
|
|
@ -125,7 +125,7 @@ use syntax_pos::{self, BytePos, Span, MultiSpan};
|
|||
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;
|
||||
|
@ -2373,13 +2373,13 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
|
|||
|
||||
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);
|
||||
|
@ -2391,11 +2391,13 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
|
|||
}
|
||||
|
||||
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)
|
||||
|
@ -2452,11 +2454,13 @@ pub fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, vs: &'tcx [hir::Variant], i
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use rustc::middle::lang_items;
|
|||
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;
|
||||
|
@ -830,13 +830,13 @@ fn check_method_receiver<'fcx, 'tcx>(
|
|||
&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`.
|
||||
|
|
|
@ -1492,16 +1492,16 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
|||
_ => 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(
|
||||
|
@ -2520,13 +2520,13 @@ fn from_target_feature(
|
|||
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))
|
||||
}));
|
||||
|
|
|
@ -7,10 +7,10 @@ use std::mem;
|
|||
use std::fmt::{self, Write};
|
||||
use std::ops;
|
||||
|
||||
use rustc_feature::Features;
|
||||
use syntax::symbol::{Symbol, sym};
|
||||
use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, LitKind};
|
||||
use syntax::sess::ParseSess;
|
||||
use syntax::feature_gate::Features;
|
||||
|
||||
use syntax_pos::Span;
|
||||
|
||||
|
|
|
@ -12,12 +12,12 @@ use rustc::session::DiagnosticOutput;
|
|||
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
||||
use rustc_interface::interface;
|
||||
use rustc_driver::abort_on_err;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_resolve as resolve;
|
||||
|
||||
use syntax::ast::CRATE_NODE_ID;
|
||||
use syntax::source_map;
|
||||
use syntax::attr;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use errors::json::JsonEmitter;
|
||||
use syntax::symbol::sym;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::fs;
|
|||
use std::path::Path;
|
||||
use std::str;
|
||||
use errors;
|
||||
use crate::syntax::feature_gate::UnstableFeatures;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use crate::syntax::edition::Edition;
|
||||
use crate::html::markdown::{IdMap, ErrorCodes, Markdown, Playground};
|
||||
|
||||
|
|
|
@ -45,7 +45,6 @@ use errors;
|
|||
use serialize::json::{ToJson, Json, as_json};
|
||||
use syntax::ast;
|
||||
use syntax::edition::Edition;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use syntax::print::pprust;
|
||||
use syntax::source_map::FileName;
|
||||
use syntax::symbol::{Symbol, sym};
|
||||
|
@ -56,6 +55,7 @@ use rustc::middle::stability;
|
|||
use rustc::hir;
|
||||
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::flock;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
|
||||
use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, Mutability};
|
||||
use crate::config::RenderOptions;
|
||||
|
|
|
@ -24,6 +24,7 @@ extern crate env_logger;
|
|||
extern crate rustc;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_feature;
|
||||
extern crate rustc_error_codes;
|
||||
extern crate rustc_index;
|
||||
extern crate rustc_resolve;
|
||||
|
|
|
@ -6,7 +6,7 @@ use errors;
|
|||
use testing;
|
||||
use syntax::edition::Edition;
|
||||
use syntax::source_map::DUMMY_SP;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
|
||||
use crate::externalfiles::{LoadStringError, load_string};
|
||||
use crate::config::{Options, RenderOptions};
|
||||
|
|
|
@ -5,10 +5,10 @@ use rustc::hir;
|
|||
use rustc::lint as lint;
|
||||
use rustc::ty;
|
||||
use rustc_resolve::ParentScope;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use syntax;
|
||||
use syntax::ast::{self, Ident};
|
||||
use syntax_expand::base::SyntaxExtensionKind;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_interface::interface;
|
||||
use rustc_target::spec::TargetTriple;
|
||||
use rustc::hir;
|
||||
|
@ -9,7 +10,6 @@ use syntax::ast;
|
|||
use syntax::with_globals;
|
||||
use syntax::source_map::SourceMap;
|
||||
use syntax::edition::Edition;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
use std::panic;
|
||||
|
|
|
@ -18,6 +18,7 @@ lazy_static = "1.0.0"
|
|||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
errors = { path = "../librustc_errors", package = "rustc_errors" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_feature = { path = "../librustc_feature" }
|
||||
rustc_index = { path = "../librustc_index" }
|
||||
rustc_lexer = { path = "../librustc_lexer" }
|
||||
rustc_macros = { path = "../librustc_macros" }
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
//! Parsing and validation of builtin attributes
|
||||
|
||||
use super::{mark_used, MetaItemKind};
|
||||
use crate::ast::{self, Attribute, MetaItem, NestedMetaItem};
|
||||
use crate::feature_gate::{Features, GatedCfg};
|
||||
use crate::feature_gate::feature_err;
|
||||
use crate::print::pprust;
|
||||
use crate::sess::ParseSess;
|
||||
|
||||
|
@ -9,12 +10,15 @@ use errors::{Applicability, Handler};
|
|||
use std::num::NonZeroU32;
|
||||
use syntax_pos::hygiene::Transparency;
|
||||
use syntax_pos::{symbol::Symbol, symbol::sym, Span};
|
||||
use rustc_feature::{Features, find_gated_cfg, GatedCfg, is_builtin_attr_name};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
use super::{mark_used, MetaItemKind};
|
||||
|
||||
use rustc_error_codes::*;
|
||||
|
||||
pub fn is_builtin_attr(attr: &Attribute) -> bool {
|
||||
attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
|
||||
}
|
||||
|
||||
enum AttrError {
|
||||
MultipleItem(String),
|
||||
UnknownMetaItem(String, &'static [&'static str]),
|
||||
|
@ -24,31 +28,6 @@ enum AttrError {
|
|||
UnsupportedLiteral(&'static str, /* is_bytestr */ bool),
|
||||
}
|
||||
|
||||
/// A template that the attribute input must match.
|
||||
/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct AttributeTemplate {
|
||||
pub word: bool,
|
||||
pub list: Option<&'static str>,
|
||||
pub name_value_str: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl AttributeTemplate {
|
||||
pub fn only_word() -> Self {
|
||||
Self { word: true, list: None, name_value_str: None }
|
||||
}
|
||||
|
||||
/// Checks that the given meta-item is compatible with this template.
|
||||
pub fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool {
|
||||
match meta_item_kind {
|
||||
ast::MetaItemKind::Word => self.word,
|
||||
ast::MetaItemKind::List(..) => self.list.is_some(),
|
||||
ast::MetaItemKind::NameValue(lit) if lit.kind.is_str() => self.name_value_str.is_some(),
|
||||
ast::MetaItemKind::NameValue(..) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
|
||||
let diag = &sess.span_diagnostic;
|
||||
match error {
|
||||
|
@ -555,8 +534,9 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
|
|||
/// Tests if a cfg-pattern matches the cfg set
|
||||
pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool {
|
||||
eval_condition(cfg, sess, &mut |cfg| {
|
||||
if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) {
|
||||
gated_cfg.check_and_emit(sess, feats);
|
||||
let gate = find_gated_cfg(|sym| cfg.check_name(sym));
|
||||
if let (Some(feats), Some(gated_cfg)) = (features, gate) {
|
||||
gate_cfg(&gated_cfg, cfg.span, sess, feats);
|
||||
}
|
||||
let error = |span, msg| { sess.span_diagnostic.span_err(span, msg); true };
|
||||
if cfg.path.segments.len() != 1 {
|
||||
|
@ -585,12 +565,21 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
|
|||
})
|
||||
}
|
||||
|
||||
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &Features) {
|
||||
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);
|
||||
feature_err(sess, *feature, cfg_span, &explain).emit()
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
|
||||
/// evaluate individual items.
|
||||
pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
|
||||
-> bool
|
||||
where F: FnMut(&ast::MetaItem) -> bool
|
||||
{
|
||||
pub fn eval_condition(
|
||||
cfg: &ast::MetaItem,
|
||||
sess: &ParseSess,
|
||||
eval: &mut impl FnMut(&ast::MetaItem) -> bool,
|
||||
) -> bool {
|
||||
match cfg.kind {
|
||||
ast::MetaItemKind::List(ref mis) => {
|
||||
for mi in mis.iter() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{active::{ACTIVE_FEATURES, Features}, Feature, State as FeatureState};
|
||||
use super::accepted::ACCEPTED_FEATURES;
|
||||
use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
|
||||
use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
|
||||
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};
|
||||
|
@ -19,18 +19,6 @@ use log::debug;
|
|||
|
||||
use rustc_error_codes::*;
|
||||
|
||||
|
||||
use std::env;
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Stability {
|
||||
Unstable,
|
||||
// First argument is tracking issue link; second argument is an optional
|
||||
// help message, which defaults to "remove this attribute"
|
||||
Deprecated(&'static str, Option<&'static str>),
|
||||
}
|
||||
|
||||
macro_rules! gate_feature_fn {
|
||||
($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
|
||||
let (cx, has_feature, span,
|
||||
|
@ -59,30 +47,6 @@ pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features:
|
|||
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.)
|
||||
|
@ -91,41 +55,35 @@ pub enum GateStrength {
|
|||
Soft,
|
||||
}
|
||||
|
||||
pub fn emit_feature_err(
|
||||
sess: &ParseSess,
|
||||
feature: Symbol,
|
||||
span: Span,
|
||||
issue: GateIssue,
|
||||
explain: &str,
|
||||
) {
|
||||
feature_err(sess, feature, span, issue, explain).emit();
|
||||
}
|
||||
|
||||
pub fn feature_err<'a, S: Into<MultiSpan>>(
|
||||
pub fn feature_err<'a>(
|
||||
sess: &'a ParseSess,
|
||||
feature: Symbol,
|
||||
span: S,
|
||||
span: impl Into<MultiSpan>,
|
||||
explain: &str,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
feature_err_issue(sess, feature, span, GateIssue::Language, explain)
|
||||
}
|
||||
|
||||
pub fn feature_err_issue<'a>(
|
||||
sess: &'a ParseSess,
|
||||
feature: Symbol,
|
||||
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))
|
||||
|
@ -133,7 +91,7 @@ fn leveled_feature_err<'a, S: Into<MultiSpan>>(
|
|||
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,
|
||||
|
@ -156,20 +114,6 @@ fn leveled_feature_err<'a, S: Into<MultiSpan>>(
|
|||
|
||||
}
|
||||
|
||||
const EXPLAIN_BOX_SYNTAX: &str =
|
||||
"box expression syntax is experimental; you can call `Box::new` instead";
|
||||
|
||||
pub const EXPLAIN_STMT_ATTR_SYNTAX: &str =
|
||||
"attributes on expressions are experimental";
|
||||
|
||||
pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &str =
|
||||
"allow_internal_unstable side-steps feature gating and stability checks";
|
||||
pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &str =
|
||||
"allow_internal_unsafe side-steps the unsafe_code lint";
|
||||
|
||||
pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str =
|
||||
"unsized tuple coercion is not stable enough for use and is subject to change";
|
||||
|
||||
struct PostExpansionVisitor<'a> {
|
||||
parse_sess: &'a ParseSess,
|
||||
features: &'a Features,
|
||||
|
@ -282,7 +226,6 @@ impl<'a> PostExpansionVisitor<'a> {
|
|||
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 {
|
||||
|
@ -529,7 +472,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
fn visit_expr(&mut self, e: &'a ast::Expr) {
|
||||
match e.kind {
|
||||
ast::ExprKind::Box(_) => {
|
||||
gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
|
||||
gate_feature_post!(
|
||||
&self, box_syntax, e.span,
|
||||
"box expression syntax is experimental; you can call `Box::new` instead"
|
||||
);
|
||||
}
|
||||
ast::ExprKind::Type(..) => {
|
||||
// To avoid noise about type ascription in common syntax errors, only emit if it
|
||||
|
@ -695,7 +641,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
|
|||
err.emit();
|
||||
}
|
||||
|
||||
let mut features = Features::new();
|
||||
let mut features = Features::default();
|
||||
let mut edition_enabled_features = FxHashMap::default();
|
||||
|
||||
for &edition in ALL_EDITIONS {
|
||||
|
@ -900,40 +846,6 @@ pub fn check_crate(krate: &ast::Crate,
|
|||
visit::walk_crate(&mut visitor, krate);
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Hash)]
|
||||
pub enum UnstableFeatures {
|
||||
/// Hard errors for unstable features are active, as on beta/stable channels.
|
||||
Disallow,
|
||||
/// Allow features to be activated, as on nightly.
|
||||
Allow,
|
||||
/// Errors are bypassed for bootstrapping. This is required any time
|
||||
/// during the build that feature-related lints are set to warn or above
|
||||
/// because the build turns on warnings-as-errors and uses lots of unstable
|
||||
/// features. As a result, this is always required for building Rust itself.
|
||||
Cheat
|
||||
}
|
||||
|
||||
impl UnstableFeatures {
|
||||
pub fn from_environment() -> UnstableFeatures {
|
||||
// `true` if this is a feature-staged build, i.e., on the beta or stable channel.
|
||||
let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
|
||||
// `true` if we should enable unstable features for bootstrapping.
|
||||
let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
|
||||
match (disable_unstable_features, bootstrap) {
|
||||
(_, true) => UnstableFeatures::Cheat,
|
||||
(true, _) => UnstableFeatures::Disallow,
|
||||
(false, _) => UnstableFeatures::Allow
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_nightly_build(&self) -> bool {
|
||||
match *self {
|
||||
UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
|
||||
UnstableFeatures::Disallow => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: UnstableFeatures) {
|
||||
if !unstable.is_nightly_build() {
|
||||
for attr in krate.attrs.iter().filter(|attr| attr.check_name(sym::feature)) {
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
//! # Feature gating
|
||||
//!
|
||||
//! This module implements the gating necessary for preventing certain compiler
|
||||
//! features from being used by default. This module will crawl a pre-expanded
|
||||
//! AST to ensure that there are no features which are used that are not
|
||||
//! enabled.
|
||||
//!
|
||||
//! Features are enabled in programs via the crate-level attributes of
|
||||
//! `#![feature(...)]` with a comma-separated list of features.
|
||||
//!
|
||||
//! For the purpose of future feature-tracking, once code for detection of feature
|
||||
//! gate usage is added, *do not remove it again* even once the feature
|
||||
//! becomes stable.
|
||||
|
||||
mod accepted;
|
||||
mod removed;
|
||||
mod active;
|
||||
mod builtin_attrs;
|
||||
mod check;
|
||||
|
||||
use crate::{edition::Edition, symbol::Symbol};
|
||||
use std::fmt;
|
||||
use std::num::NonZeroU32;
|
||||
use syntax_pos::Span;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum State {
|
||||
Accepted,
|
||||
Active { set: fn(&mut Features, Span) },
|
||||
Removed { reason: Option<&'static str> },
|
||||
Stabilized { reason: Option<&'static str> },
|
||||
}
|
||||
|
||||
impl fmt::Debug for State {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
State::Accepted { .. } => write!(f, "accepted"),
|
||||
State::Active { .. } => write!(f, "active"),
|
||||
State::Removed { .. } => write!(f, "removed"),
|
||||
State::Stabilized { .. } => write!(f, "stabilized"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Feature {
|
||||
state: State,
|
||||
name: Symbol,
|
||||
since: &'static str,
|
||||
issue: Option<u32>, // FIXME: once #58732 is done make this an Option<NonZeroU32>
|
||||
edition: Option<Edition>,
|
||||
description: &'static str,
|
||||
}
|
||||
|
||||
impl Feature {
|
||||
fn issue(&self) -> Option<NonZeroU32> {
|
||||
self.issue.and_then(|i| NonZeroU32::new(i))
|
||||
}
|
||||
}
|
||||
|
||||
pub use active::{Features, INCOMPLETE_FEATURES};
|
||||
pub use builtin_attrs::{
|
||||
AttributeGate, AttributeType, GatedCfg,
|
||||
BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
|
||||
deprecated_attributes, is_builtin_attr, is_builtin_attr_name,
|
||||
};
|
||||
pub use check::{
|
||||
check_crate, check_attribute, get_features, feature_err, emit_feature_err,
|
||||
Stability, GateIssue, UnstableFeatures,
|
||||
EXPLAIN_STMT_ATTR_SYNTAX, EXPLAIN_UNSIZED_TUPLE_COERCION,
|
||||
};
|
|
@ -92,7 +92,10 @@ pub mod attr;
|
|||
pub mod expand;
|
||||
pub use syntax_pos::source_map;
|
||||
pub mod entry;
|
||||
pub mod feature_gate;
|
||||
pub mod feature_gate {
|
||||
mod check;
|
||||
pub use check::{check_crate, check_attribute, get_features, feature_err, feature_err_issue};
|
||||
}
|
||||
pub mod mut_visit;
|
||||
pub mod ptr;
|
||||
pub mod show_span;
|
||||
|
|
|
@ -3,15 +3,15 @@
|
|||
|
||||
use crate::ast::{CrateConfig, NodeId};
|
||||
use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId};
|
||||
use crate::source_map::{SourceMap, FilePathMapping};
|
||||
use crate::feature_gate::UnstableFeatures;
|
||||
|
||||
use errors::{Applicability, emitter::SilentEmitter, Handler, ColorConfig, DiagnosticBuilder};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
|
||||
use rustc_data_structures::sync::{Lrc, Lock, Once};
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use syntax_pos::{Symbol, Span, MultiSpan};
|
||||
use syntax_pos::edition::Edition;
|
||||
use syntax_pos::hygiene::ExpnId;
|
||||
use syntax_pos::source_map::{SourceMap, FilePathMapping};
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::str;
|
||||
|
|
|
@ -16,6 +16,7 @@ log = "0.4"
|
|||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
errors = { path = "../librustc_errors", package = "rustc_errors" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_feature = { path = "../librustc_feature" }
|
||||
rustc_lexer = { path = "../librustc_lexer" }
|
||||
rustc_parse = { path = "../librustc_parse" }
|
||||
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
|
||||
|
|
|
@ -4,16 +4,17 @@ use crate::hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind};
|
|||
use crate::mbe::macro_rules::annotate_err_with_kind;
|
||||
use crate::placeholders::{placeholder, PlaceholderExpander};
|
||||
use crate::config::StripUnconfigured;
|
||||
use rustc_parse::configure;
|
||||
|
||||
use rustc_feature::Features;
|
||||
use rustc_parse::configure;
|
||||
use rustc_parse::DirectoryOwnership;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_parse::validate_attr;
|
||||
use syntax::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path};
|
||||
use syntax::ast::{MacStmtStyle, StmtKind, ItemKind};
|
||||
use syntax::attr::{self, HasAttrs};
|
||||
use syntax::attr::{self, HasAttrs, is_builtin_attr};
|
||||
use syntax::source_map::respan;
|
||||
use syntax::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
|
||||
use syntax::feature_gate::{self, feature_err};
|
||||
use syntax::mut_visit::*;
|
||||
use syntax::print::pprust;
|
||||
use syntax::ptr::P;
|
||||
|
@ -726,13 +727,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
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) {
|
||||
|
@ -744,13 +745,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
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();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -789,13 +790,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
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(
|
||||
|
@ -991,9 +992,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
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
|
||||
|
|
|
@ -8,12 +8,12 @@ use crate::mbe::macro_parser::{Error, Failure, Success};
|
|||
use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult};
|
||||
use crate::mbe::transcribe::transcribe;
|
||||
|
||||
use rustc_feature::Features;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_parse::Directory;
|
||||
use syntax::ast;
|
||||
use syntax::attr::{self, TransparencyError};
|
||||
use syntax::edition::Edition;
|
||||
use syntax::feature_gate::Features;
|
||||
use syntax::print::pprust;
|
||||
use syntax::sess::ParseSess;
|
||||
use syntax::symbol::{kw, sym, Symbol};
|
||||
|
|
|
@ -14,6 +14,7 @@ errors = { path = "../librustc_errors", package = "rustc_errors" }
|
|||
fmt_macros = { path = "../libfmt_macros" }
|
||||
log = "0.4"
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_feature = { path = "../librustc_feature" }
|
||||
rustc_parse = { path = "../librustc_parse" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
use log::debug;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use rustc_feature::Features;
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
use syntax::ast::{self, Ident};
|
||||
use syntax::attr;
|
||||
use syntax::entry::{self, EntryPointType};
|
||||
use syntax_expand::base::{ExtCtxt, Resolver};
|
||||
use syntax_expand::expand::{AstFragment, ExpansionConfig};
|
||||
use syntax::feature_gate::Features;
|
||||
use syntax::mut_visit::{*, ExpectOne};
|
||||
use syntax::ptr::P;
|
||||
use syntax::sess::ParseSess;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_parse::validate_attr;
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use syntax_pos::Symbol;
|
||||
use syntax::ast::MetaItem;
|
||||
use syntax::attr::AttributeTemplate;
|
||||
use syntax_expand::base::ExtCtxt;
|
||||
|
||||
pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
|
||||
|
|
|
@ -231,7 +231,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
|
|||
}
|
||||
|
||||
fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features {
|
||||
let path = base.join("libsyntax/feature_gate").join(file);
|
||||
let path = base.join("librustc_feature").join(file);
|
||||
let contents = t!(fs::read_to_string(&path));
|
||||
|
||||
// We allow rustc-internal features to omit a tracking issue.
|
||||
|
|
Loading…
Reference in New Issue