use codemap::Spanned;
use edition::{ALL_EDITIONS, Edition};
use syntax_pos::{Span, DUMMY_SP};
-use errors::{DiagnosticBuilder, Handler, FatalError};
+use errors::{DiagnosticBuilder, Handler};
use visit::{self, FnKind, Visitor};
use parse::ParseSess;
use symbol::{keywords, Symbol};
}
pub fn use_extern_macros(&self) -> bool {
- // The `decl_macro` and `tool_attributes` features imply `use_extern_macros`.
- self.use_extern_macros || self.decl_macro || self.tool_attributes
+ // A number of "advanced" macro features enable
+ // macro modularization (`use_extern_macros`) implicitly.
+ self.use_extern_macros || self.decl_macro ||
+ self.tool_attributes || self.custom_attribute ||
+ self.macros_in_extern || self.proc_macro_path_invoc ||
+ self.proc_macro_mod || self.proc_macro_expr ||
+ self.proc_macro_non_items || self.proc_macro_gen ||
+ self.stmt_expr_attributes || self.unrestricted_attribute_tokens
}
}
};
(active, mmx_target_feature, "1.27.0", Some(44839), None),
(active, sse4a_target_feature, "1.27.0", Some(44839), None),
(active, tbm_target_feature, "1.27.0", Some(44839), None),
+ (active, wasm_target_feature, "1.30.0", Some(44839), None),
// Allows macro invocations of the form `#[foo::bar]`
(active, proc_macro_path_invoc, "1.27.0", Some(38356), None),
// impl<I:Iterator> Iterator for &mut Iterator
// impl Debug for Foo<'_>
(active, impl_header_lifetime_elision, "1.30.0", Some(15872), Some(Edition::Edition2018)),
+
+ // Support for arbitrary delimited token streams in non-macro attributes.
+ (active, unrestricted_attribute_tokens, "1.30.0", Some(44690), None),
+
+ // Allows `use x::y;` to resolve through `self::x`, not just `::x`.
+ (active, uniform_paths, "1.30.0", Some(53130), None),
);
declare_features! (
}
pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
- BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name)) ||
- attr.name().as_str().starts_with("rustc_")
+ BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.path == builtin_name)
}
// Attributes that have a special meaning to rustc or rustdoc
pub const EXPLAIN_MACRO_AT_MOST_ONCE_REP: &'static str =
"using the `?` macro Kleene operator for \"at most one\" repetition is unstable";
-pub const EXPLAIN_MACROS_IN_EXTERN: &'static str =
- "macro invocations in `extern {}` blocks are experimental.";
-
-// mention proc-macros when enabled
-pub const EXPLAIN_PROC_MACROS_IN_EXTERN: &'static str =
- "macro and proc-macro invocations in `extern {}` blocks are experimental.";
-
struct PostExpansionVisitor<'a> {
context: &'a Context<'a>,
}
}
}
- // allow attr_literals in #[repr(align(x))] and #[repr(packed(n))]
- let mut allow_attr_literal = false;
- if attr.path == "repr" {
- if let Some(content) = attr.meta_item_list() {
- allow_attr_literal = content.iter().any(
- |c| c.check_name("align") || c.check_name("packed"));
- }
- }
-
- if self.context.features.use_extern_macros() && attr::is_known(attr) {
- return
- }
+ if !self.context.features.unrestricted_attribute_tokens {
+ // Unfortunately, `parse_meta` cannot be called speculatively because it can report
+ // errors by itself, so we have to call it only if the feature is disabled.
+ match attr.parse_meta(self.context.parse_sess) {
+ Ok(meta) => {
+ // allow attr_literals in #[repr(align(x))] and #[repr(packed(n))]
+ let mut allow_attr_literal = false;
+ if attr.path == "repr" {
+ if let Some(content) = meta.meta_item_list() {
+ allow_attr_literal = content.iter().any(
+ |c| c.check_name("align") || c.check_name("packed"));
+ }
+ }
- if !allow_attr_literal {
- let meta = panictry!(attr.parse_meta(self.context.parse_sess));
- if contains_novel_literal(&meta) {
- gate_feature_post!(&self, attr_literals, attr.span,
- "non-string literals in attributes, or string \
- literals in top-level positions, are experimental");
+ if !allow_attr_literal && contains_novel_literal(&meta) {
+ gate_feature_post!(&self, attr_literals, attr.span,
+ "non-string literals in attributes, or string \
+ literals in top-level positions, are experimental");
+ }
+ }
+ Err(mut err) => {
+ err.help("try enabling `#![feature(unrestricted_attribute_tokens)]`").emit()
+ }
}
}
}
err.emit();
}
- let mut features = Features::new();
-
- let mut feature_checker = FeatureChecker::default();
+ // Some features are known to be incomplete and using them is likely to have
+ // unanticipated results, such as compiler crashes. We warn the user about these
+ // to alert them.
+ let incomplete_features = ["generic_associated_types"];
+ let mut features = Features::new();
let mut edition_enabled_features = FxHashMap();
- for &(name, .., f_edition, set) in ACTIVE_FEATURES.iter() {
+ for &edition in ALL_EDITIONS {
+ if edition <= crate_edition {
+ // The `crate_edition` implies its respective umbrella feature-gate
+ // (i.e. `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX).
+ edition_enabled_features.insert(Symbol::intern(edition.feature_name()), edition);
+ }
+ }
+
+ for &(name, .., f_edition, set) in ACTIVE_FEATURES {
if let Some(f_edition) = f_edition {
if f_edition <= crate_edition {
set(&mut features, DUMMY_SP);
}
}
+ // Process the edition umbrella feature-gates first, to ensure
+ // `edition_enabled_features` is completed before it's queried.
for attr in krate_attrs {
if !attr.check_name("feature") {
continue
let list = match attr.meta_item_list() {
Some(list) => list,
- None => {
- span_err!(span_handler, attr.span, E0555,
- "malformed feature attribute, expected #![feature(...)]");
- continue
- }
+ None => continue,
};
for mi in list {
let name = if let Some(word) = mi.word() {
word.name()
} else {
- span_err!(span_handler, mi.span, E0556,
- "malformed feature, expected just one word");
continue
};
+ if incomplete_features.iter().any(|f| *f == name.as_str()) {
+ span_handler.struct_span_warn(
+ mi.span,
+ &format!(
+ "the feature `{}` is incomplete and may cause the compiler to crash",
+ name
+ )
+ ).emit();
+ }
+
if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
if *edition <= crate_edition {
- continue
+ continue;
}
- for &(name, .., f_edition, set) in ACTIVE_FEATURES.iter() {
+ for &(name, .., f_edition, set) in ACTIVE_FEATURES {
if let Some(f_edition) = f_edition {
if f_edition <= *edition {
// FIXME(Manishearth) there is currently no way to set
}
}
}
+ }
+ }
+ }
+
+ for attr in krate_attrs {
+ if !attr.check_name("feature") {
+ continue
+ }
+
+ let list = match attr.meta_item_list() {
+ Some(list) => list,
+ None => {
+ span_err!(span_handler, attr.span, E0555,
+ "malformed feature attribute, expected #![feature(...)]");
+ continue
+ }
+ };
+ for mi in list {
+ let name = if let Some(word) = mi.word() {
+ word.name()
+ } else {
+ span_err!(span_handler, mi.span, E0556,
+ "malformed feature, expected just one word");
continue
+ };
+
+ if let Some(edition) = edition_enabled_features.get(&name) {
+ struct_span_warn!(
+ span_handler,
+ mi.span,
+ E0705,
+ "the feature `{}` is included in the Rust {} edition",
+ name,
+ edition,
+ ).emit();
+ continue;
+ }
+
+ if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) {
+ // Handled in the separate loop above.
+ continue;
}
if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
- if let Some(edition) = edition_enabled_features.get(&name) {
- struct_span_warn!(
- span_handler,
- mi.span,
- E0705,
- "the feature `{}` is included in the Rust {} edition",
- name,
- edition,
- ).emit();
- } else {
- set(&mut features, mi.span);
- feature_checker.collect(&features, mi.span);
- features.declared_lang_features.push((name, mi.span, None));
- }
+ set(&mut features, mi.span);
+ features.declared_lang_features.push((name, mi.span, None));
continue
}
}
}
- feature_checker.check(span_handler);
-
features
}
-/// A collector for mutually exclusive and interdependent features and their flag spans.
-#[derive(Default)]
-struct FeatureChecker {
- use_extern_macros: Option<Span>,
- custom_attribute: Option<Span>,
-}
-
-impl FeatureChecker {
- // If this method turns out to be a hotspot due to branching,
- // the branching can be eliminated by modifying `set!()` to set these spans
- // only for the features that need to be checked for mutual exclusion.
- fn collect(&mut self, features: &Features, span: Span) {
- if features.use_extern_macros() {
- // If self.use_extern_macros is None, set to Some(span)
- self.use_extern_macros = self.use_extern_macros.or(Some(span));
- }
-
- if features.custom_attribute {
- self.custom_attribute = self.custom_attribute.or(Some(span));
- }
- }
-
- fn check(self, handler: &Handler) {
- if let (Some(pm_span), Some(ca_span)) = (self.use_extern_macros, self.custom_attribute) {
- handler.struct_span_err(pm_span, "Cannot use `#![feature(use_extern_macros)]` and \
- `#![feature(custom_attribute)] at the same time")
- .span_note(ca_span, "`#![feature(custom_attribute)]` declared here")
- .emit();
-
- FatalError.raise();
- }
- }
-}
-
pub fn check_crate(krate: &ast::Crate,
sess: &ParseSess,
features: &Features,