about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorOliver Scherer <github35764891676564198441@oli-obk.de>2019-02-03 12:55:00 +0100
committerOliver Scherer <github35764891676564198441@oli-obk.de>2019-02-11 15:08:16 +0100
commitd3c212c5527f901fcb44d59d031695248762c340 (patch)
tree517e224748ab0be13ec54bc99b5f728263152328 /src/libsyntax
parent57d7cfc3cf50f0c427ad3043ff09eaef20671320 (diff)
Require a list of features to allow in `allow_internal_unstable`
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/base.rs20
-rw-r--r--src/libsyntax/ext/derive.rs5
-rw-r--r--src/libsyntax/ext/expand.rs27
-rw-r--r--src/libsyntax/ext/source_util.rs2
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs13
-rw-r--r--src/libsyntax/feature_gate.rs24
-rw-r--r--src/libsyntax/std_inject.rs4
-rw-r--r--src/libsyntax/test.rs6
8 files changed, 67 insertions, 34 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 465b53184dc..02d6d721873 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -621,7 +621,8 @@ pub enum SyntaxExtension {
     /// A function-like procedural macro. TokenStream -> TokenStream.
     ProcMacro {
         expander: Box<dyn ProcMacro + sync::Sync + sync::Send>,
-        allow_internal_unstable: bool,
+        /// Whitelist of unstable features that are treated as stable inside this macro
+        allow_internal_unstable: Vec<Symbol>,
         edition: Edition,
     },
 
@@ -638,8 +639,10 @@ pub enum SyntaxExtension {
         expander: Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
         def_info: Option<(ast::NodeId, Span)>,
         /// Whether the contents of the macro can
-        /// directly use `#[unstable]` things (true == yes).
-        allow_internal_unstable: bool,
+        /// directly use `#[unstable]` things.
+        ///
+        /// Only allows things that require a feature gate in the given whitelist
+        allow_internal_unstable: Vec<Symbol>,
         /// Whether the contents of the macro can use `unsafe`
         /// without triggering the `unsafe_code` lint.
         allow_internal_unsafe: bool,
@@ -654,8 +657,11 @@ pub enum SyntaxExtension {
 
     /// A function-like syntax extension that has an extra ident before
     /// the block.
-    ///
-    IdentTT(Box<dyn IdentMacroExpander + sync::Sync + sync::Send>, Option<Span>, bool),
+    IdentTT {
+        ext: Box<dyn IdentMacroExpander + sync::Sync + sync::Send>,
+        span: Option<Span>,
+        allow_internal_unstable: Vec<Symbol>,
+    },
 
     /// An attribute-like procedural macro. TokenStream -> TokenStream.
     /// The input is the annotated item.
@@ -682,7 +688,7 @@ impl SyntaxExtension {
         match *self {
             SyntaxExtension::DeclMacro { .. } |
             SyntaxExtension::NormalTT { .. } |
-            SyntaxExtension::IdentTT(..) |
+            SyntaxExtension::IdentTT { .. } |
             SyntaxExtension::ProcMacro { .. } =>
                 MacroKind::Bang,
             SyntaxExtension::NonMacroAttr { .. } |
@@ -716,7 +722,7 @@ impl SyntaxExtension {
             SyntaxExtension::ProcMacroDerive(.., edition) => edition,
             // Unstable legacy stuff
             SyntaxExtension::NonMacroAttr { .. } |
-            SyntaxExtension::IdentTT(..) |
+            SyntaxExtension::IdentTT { .. } |
             SyntaxExtension::MultiDecorator(..) |
             SyntaxExtension::MultiModifier(..) |
             SyntaxExtension::BuiltinDerive(..) => hygiene::default_edition(),
diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs
index 50cec9e7908..03d68f4257f 100644
--- a/src/libsyntax/ext/derive.rs
+++ b/src/libsyntax/ext/derive.rs
@@ -58,7 +58,10 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P
         call_site: span,
         def_site: None,
         format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
-        allow_internal_unstable: true,
+        allow_internal_unstable: vec![
+            Symbol::intern("rustc_attrs"),
+            Symbol::intern("structural_match"),
+        ],
         allow_internal_unsafe: false,
         local_inner_macros: false,
         edition: hygiene::default_edition(),
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 89d59478a5d..65500cd23bd 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -558,7 +558,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             call_site: attr.span,
             def_site: None,
             format: MacroAttribute(Symbol::intern(&attr.path.to_string())),
-            allow_internal_unstable: false,
+            allow_internal_unstable: Vec::new(),
             allow_internal_unsafe: false,
             local_inner_macros: false,
             edition: ext.edition(),
@@ -725,7 +725,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 // 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| {
+                    && !span.allows_unstable(&feature.as_str())
+                    && this.cx.ecfg.features.map_or(true, |feats| {
                     // macro features will count as lib features
                     !feats.declared_lib_features.iter().any(|&(feat, _)| feat == feature)
                 }) {
@@ -757,7 +758,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let opt_expanded = match *ext {
             DeclMacro { ref expander, def_info, edition, .. } => {
                 if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
-                                                                    false, false, false, None,
+                                                                    Vec::new(), false, false, None,
                                                                     edition) {
                     dummy_span
                 } else {
@@ -768,14 +769,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             NormalTT {
                 ref expander,
                 def_info,
-                allow_internal_unstable,
+                ref allow_internal_unstable,
                 allow_internal_unsafe,
                 local_inner_macros,
                 unstable_feature,
                 edition,
             } => {
                 if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
-                                                                    allow_internal_unstable,
+                                                                    allow_internal_unstable.clone(),
                                                                     allow_internal_unsafe,
                                                                     local_inner_macros,
                                                                     unstable_feature,
@@ -791,7 +792,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
             }
 
-            IdentTT(ref expander, tt_span, allow_internal_unstable) => {
+            IdentTT { ext: ref expander, span: tt_span, ref allow_internal_unstable } => {
                 if ident.name == keywords::Invalid.name() {
                     self.cx.span_err(path.span,
                                     &format!("macro {}! expects an ident argument", path));
@@ -802,7 +803,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         call_site: span,
                         def_site: tt_span,
                         format: macro_bang_format(path),
-                        allow_internal_unstable,
+                        allow_internal_unstable: allow_internal_unstable.clone(),
                         allow_internal_unsafe: false,
                         local_inner_macros: false,
                         edition: hygiene::default_edition(),
@@ -827,7 +828,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 kind.dummy(span)
             }
 
-            SyntaxExtension::ProcMacro { ref expander, allow_internal_unstable, edition } => {
+            SyntaxExtension::ProcMacro { ref expander, ref allow_internal_unstable, edition } => {
                 if ident.name != keywords::Invalid.name() {
                     let msg =
                         format!("macro {}! expects no ident argument, given '{}'", path, ident);
@@ -843,7 +844,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         def_site: None,
                         format: macro_bang_format(path),
                         // FIXME probably want to follow macro_rules macros here.
-                        allow_internal_unstable,
+                        allow_internal_unstable: allow_internal_unstable.clone(),
                         allow_internal_unsafe: false,
                         local_inner_macros: false,
                         edition,
@@ -918,7 +919,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             call_site: span,
             def_site: None,
             format: MacroAttribute(pretty_name),
-            allow_internal_unstable: false,
+            allow_internal_unstable: Vec::new(),
             allow_internal_unsafe: false,
             local_inner_macros: false,
             edition: ext.edition(),
@@ -937,7 +938,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 Some(invoc.fragment_kind.expect_from_annotatables(items))
             }
             BuiltinDerive(func) => {
-                expn_info.allow_internal_unstable = true;
+                expn_info.allow_internal_unstable = vec![
+                    Symbol::intern("rustc_attrs"),
+                    Symbol::intern("derive_clone_copy"),
+                    Symbol::intern("derive_eq"),
+                ];
                 invoc.expansion_data.mark.set_expn_info(expn_info);
                 let span = span.with_ctxt(self.cx.backtrace());
                 let mut items = Vec::new();
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 31a134b856d..549de1628eb 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -44,7 +44,7 @@ pub fn expand_column(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTr
 /* __rust_unstable_column!(): expands to the current column number */
 pub fn expand_column_gated(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
                   -> Box<dyn base::MacResult+'static> {
-    if sp.allows_unstable() {
+    if sp.allows_unstable("__rust_unstable_column") {
         expand_column(cx, sp, tts)
     } else {
         cx.span_fatal(sp, "the __rust_unstable_column macro is unstable");
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 33ea675f9d1..4409bf13b6c 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -376,7 +376,18 @@ pub fn compile(
     });
 
     if body.legacy {
-        let allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable");
+        let allow_internal_unstable = attr::find_by_name(&def.attrs, "allow_internal_unstable")
+            .map_or(Vec::new(), |attr| attr
+                .meta_item_list()
+                .unwrap_or_else(|| sess.span_diagnostic.span_bug(
+                    attr.span, "allow_internal_unstable expects list of feature names",
+                ))
+                .iter()
+                .map(|it| it.name().unwrap_or_else(|| sess.span_diagnostic.span_bug(
+                    it.span, "allow internal unstable expects feature names",
+                )))
+                .collect()
+            );
         let allow_internal_unsafe = attr::contains_name(&def.attrs, "allow_internal_unsafe");
         let mut local_inner_macros = false;
         if let Some(macro_export) = attr::find_by_name(&def.attrs, "macro_export") {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 0853b4399d2..1e1b315824f 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -1091,7 +1091,7 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
                                               stable",
                                              cfg_fn!(profiler_runtime))),
 
-    ("allow_internal_unstable", Normal, template!(Word), Gated(Stability::Unstable,
+    ("allow_internal_unstable", Normal, template!(List: "feat1, feat2"), Gated(Stability::Unstable,
                                               "allow_internal_unstable",
                                               EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
                                               cfg_fn!(allow_internal_unstable))),
@@ -1199,7 +1199,7 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
     ("proc_macro", Normal, template!(Word), Ungated),
 
     ("rustc_proc_macro_decls", Normal, template!(Word), Gated(Stability::Unstable,
-                                             "rustc_proc_macro_decls",
+                                             "rustc_attrs",
                                              "used internally by rustc",
                                              cfg_fn!(rustc_attrs))),
 
@@ -1284,7 +1284,7 @@ impl GatedCfg {
 
     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() {
+        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);
         }
@@ -1303,7 +1303,7 @@ macro_rules! gate_feature_fn {
              name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level);
         let has_feature: bool = has_feature(&$cx.features);
         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
-        if !has_feature && !span.allows_unstable() {
+        if !has_feature && !span.allows_unstable($name) {
             leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level)
                 .emit();
         }
@@ -1328,7 +1328,11 @@ impl<'a> Context<'a> {
         for &(n, ty, _template, ref gateage) in BUILTIN_ATTRIBUTES {
             if name == n {
                 if let Gated(_, name, desc, ref has_feature) = *gateage {
-                    gate_feature_fn!(self, has_feature, attr.span, name, desc, GateStrength::Hard);
+                    if !attr.span.allows_unstable(name) {
+                        gate_feature_fn!(
+                            self, has_feature, attr.span, name, desc, GateStrength::Hard
+                        );
+                    }
                 } else if name == "doc" {
                     if let Some(content) = attr.meta_item_list() {
                         if content.iter().any(|c| c.check_name("include")) {
@@ -1493,13 +1497,13 @@ struct PostExpansionVisitor<'a> {
 macro_rules! gate_feature_post {
     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
         let (cx, span) = ($cx, $span);
-        if !span.allows_unstable() {
+        if !span.allows_unstable(stringify!($feature)) {
             gate_feature!(cx.context, $feature, span, $explain)
         }
     }};
     ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
         let (cx, span) = ($cx, $span);
-        if !span.allows_unstable() {
+        if !span.allows_unstable(stringify!($feature)) {
             gate_feature!(cx.context, $feature, span, $explain, $level)
         }
     }}
@@ -1610,10 +1614,8 @@ impl<'a> PostExpansionVisitor<'a> {
 
 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_attribute(&mut self, attr: &ast::Attribute) {
-        if !attr.span.allows_unstable() {
-            // check for gated attributes
-            self.context.check_attribute(attr, false);
-        }
+        // check for gated attributes
+        self.context.check_attribute(attr, false);
 
         if attr.check_name("doc") {
             if let Some(content) = attr.meta_item_list() {
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index 5b904fa86ad..91ec42a33b5 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -20,7 +20,9 @@ fn ignored_span(sp: Span) -> Span {
         call_site: DUMMY_SP,
         def_site: None,
         format: MacroAttribute(Symbol::intern("std_inject")),
-        allow_internal_unstable: true,
+        allow_internal_unstable: vec![
+            Symbol::intern("prelude_import"),
+        ],
         allow_internal_unsafe: false,
         local_inner_macros: false,
         edition: hygiene::default_edition(),
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 703c4f2db34..aa107130eee 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -285,7 +285,11 @@ fn generate_test_harness(sess: &ParseSess,
         call_site: DUMMY_SP,
         def_site: None,
         format: MacroAttribute(Symbol::intern("test_case")),
-        allow_internal_unstable: true,
+        allow_internal_unstable: vec![
+            Symbol::intern("main"),
+            Symbol::intern("test"),
+            Symbol::intern("rustc_attrs"),
+        ],
         allow_internal_unsafe: false,
         local_inner_macros: false,
         edition: hygiene::default_edition(),