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:
Mazdak Farrokhzad 2019-11-30 16:56:58 +01:00 committed by GitHub
commit b772b5b19d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 448 additions and 464 deletions

View File

@ -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",

View File

@ -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" }

View File

@ -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<

View File

@ -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.

View File

@ -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 {

View File

@ -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();
}
}
}

View File

@ -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" }
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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)
}

View File

@ -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]

View File

@ -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;

View File

@ -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;

View File

@ -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" }

View File

@ -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 {

View File

@ -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" }

View File

@ -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 {
($(

View File

@ -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);)+
}
}

View File

@ -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();

137
src/librustc_feature/lib.rs Normal file
View File

@ -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,
};

View File

@ -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 {
($(

View File

@ -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" }

View File

@ -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,

View File

@ -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! {

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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"] }

View File

@ -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 `//`.");

View File

@ -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![];

View File

@ -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" }

View File

@ -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(

View File

@ -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),
}

View File

@ -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"] }

View File

@ -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)
);

View File

@ -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};

View File

@ -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();
}
}

View File

@ -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,

View File

@ -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)

View File

@ -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();
}
}

View File

@ -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`.

View File

@ -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))
}));

View File

@ -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;

View File

@ -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;

View File

@ -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};

View File

@ -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;

View File

@ -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;

View File

@ -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};

View File

@ -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;

View File

@ -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;

View File

@ -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" }

View File

@ -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() {

View File

@ -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)) {

View File

@ -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,
};

View File

@ -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;

View File

@ -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;

View File

@ -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"] }

View File

@ -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

View File

@ -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};

View File

@ -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"] }

View File

@ -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;

View File

@ -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) {

View File

@ -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.