diff options
| author | bors <bors@rust-lang.org> | 2018-03-16 02:46:23 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-03-16 02:46:23 +0000 |
| commit | a7170b0412d1baa4e30cb31d1ea326617021f086 (patch) | |
| tree | c29e3be6c0201716b609c9e2f714f8703a580b3a /src/libsyntax/ext | |
| parent | 36b66873187e37a9d79adad89563088a9cb86028 (diff) | |
| parent | 69035f20b92870a7ad5dbc22c65aee971d8f8698 (diff) | |
| download | rust-a7170b0412d1baa4e30cb31d1ea326617021f086.tar.gz rust-a7170b0412d1baa4e30cb31d1ea326617021f086.zip | |
Auto merge of #48524 - abonander:check-macro-stability, r=petrochenkov
check stability of macro invocations I haven't implemented tests yet but this should be a pretty solid prototype. I think as-implemented it will also stability-check macro invocations in the same crate, dunno if we want that or not. I don't know if we want this to go through `rustc::middle::stability` or not, considering the information there wouldn't be available at the time of macro expansion (even for external crates, right?). r? @nrc closes #34079 cc @petrochenkov @durka @jseyfried #38356
Diffstat (limited to 'src/libsyntax/ext')
| -rw-r--r-- | src/libsyntax/ext/base.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 56 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/macro_rules.rs | 13 |
3 files changed, 56 insertions, 17 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 7b333270d04..23c42972912 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -555,6 +555,8 @@ pub enum SyntaxExtension { /// Whether the contents of the macro can use `unsafe` /// without triggering the `unsafe_code` lint. allow_internal_unsafe: bool, + /// The macro's feature name if it is unstable, and the stability feature + unstable_feature: Option<(Symbol, u32)>, }, /// A function-like syntax extension that has an extra ident before @@ -670,6 +672,7 @@ pub struct ExpansionData { pub depth: usize, pub module: Rc<ModuleData>, pub directory_ownership: DirectoryOwnership, + pub crate_span: Option<Span>, } /// One of these is made during expansion and incrementally updated as we go; @@ -701,6 +704,7 @@ impl<'a> ExtCtxt<'a> { depth: 0, module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }), directory_ownership: DirectoryOwnership::Owned { relative: None }, + crate_span: None, }, expansions: HashMap::new(), } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 3e75afcee1c..7ccace014d0 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -18,7 +18,7 @@ use ext::base::*; use ext::derive::{add_derived_markers, collect_derives}; use ext::hygiene::{Mark, SyntaxContext}; use ext::placeholders::{placeholder, PlaceholderExpander}; -use feature_gate::{self, Features, is_builtin_attr}; +use feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}; use fold; use fold::*; use parse::{DirectoryOwnership, PResult}; @@ -229,6 +229,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { module.directory.pop(); self.cx.root_path = module.directory.clone(); self.cx.current_expansion.module = Rc::new(module); + self.cx.current_expansion.crate_span = Some(krate.span); let orig_mod_span = krate.module.inner; @@ -533,11 +534,36 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let path = &mac.node.path; let ident = ident.unwrap_or_else(|| keywords::Invalid.ident()); - let validate_and_set_expn_info = |def_site_span, + let validate_and_set_expn_info = |this: &mut Self, // arg instead of capture + def_site_span: Option<Span>, allow_internal_unstable, - allow_internal_unsafe| { + allow_internal_unsafe, + // can't infer this type + unstable_feature: Option<(Symbol, u32)>| { + + // feature-gate the macro invocation + if let Some((feature, issue)) = unstable_feature { + let crate_span = this.cx.current_expansion.crate_span.unwrap(); + // don't stability-check macros in the same crate + // (the only time this is null is for syntax extensions registered as macros) + if def_site_span.map_or(false, |def_span| !crate_span.contains(def_span)) + && !span.allows_unstable() && this.cx.ecfg.features.map_or(true, |feats| { + // macro features will count as lib features + !feats.declared_lib_features.iter().any(|&(feat, _)| feat == feature) + }) { + let explain = format!("macro {}! is unstable", path); + emit_feature_err(this.cx.parse_sess, &*feature.as_str(), span, + GateIssue::Library(Some(issue)), &explain); + this.cx.trace_macros_diag(); + return Err(kind.dummy(span)); + } + } + if ident.name != keywords::Invalid.name() { - return Err(format!("macro {}! expects no ident argument, given '{}'", path, ident)); + let msg = format!("macro {}! expects no ident argument, given '{}'", path, ident); + this.cx.span_err(path.span, &msg); + this.cx.trace_macros_diag(); + return Err(kind.dummy(span)); } mark.set_expn_info(ExpnInfo { call_site: span, @@ -553,11 +579,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let opt_expanded = match *ext { DeclMacro(ref expand, def_span) => { - if let Err(msg) = validate_and_set_expn_info(def_span.map(|(_, s)| s), - false, false) { - self.cx.span_err(path.span, &msg); - self.cx.trace_macros_diag(); - kind.dummy(span) + if let Err(dummy_span) = validate_and_set_expn_info(self, def_span.map(|(_, s)| s), + false, false, None) { + dummy_span } else { kind.make_from(expand.expand(self.cx, span, mac.node.stream())) } @@ -567,14 +591,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ref expander, def_info, allow_internal_unstable, - allow_internal_unsafe + allow_internal_unsafe, + unstable_feature, } => { - if let Err(msg) = validate_and_set_expn_info(def_info.map(|(_, s)| s), - allow_internal_unstable, - allow_internal_unsafe) { - self.cx.span_err(path.span, &msg); - self.cx.trace_macros_diag(); - kind.dummy(span) + if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s), + allow_internal_unstable, + allow_internal_unsafe, + unstable_feature) { + dummy_span } else { kind.make_from(expander.expand(self.cx, span, mac.node.stream())) } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 9162a582599..a4b2c3990f5 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -283,11 +283,22 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> Syntax if body.legacy { let allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable"); let allow_internal_unsafe = attr::contains_name(&def.attrs, "allow_internal_unsafe"); + + let unstable_feature = attr::find_stability(&sess.span_diagnostic, + &def.attrs, def.span).and_then(|stability| { + if let attr::StabilityLevel::Unstable { issue, .. } = stability.level { + Some((stability.feature, issue)) + } else { + None + } + }); + NormalTT { expander, def_info: Some((def.id, def.span)), allow_internal_unstable, - allow_internal_unsafe + allow_internal_unsafe, + unstable_feature } } else { SyntaxExtension::DeclMacro(expander, Some((def.id, def.span))) |
