about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2020-11-14 14:47:14 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2020-11-19 19:25:20 +0300
commitb49fbc9432bdad5f1db59391600b56a6d5fbede9 (patch)
tree4a6eb40c550fa35e7ac91f752f6bf378da0d882d
parent7e2032390cf34f3ffa726b7bd890141e2684ba63 (diff)
downloadrust-b49fbc9432bdad5f1db59391600b56a6d5fbede9.tar.gz
rust-b49fbc9432bdad5f1db59391600b56a6d5fbede9.zip
expand: Tell built-in macros whether we are currently in forced expansion mode
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_accessible.rs11
-rw-r--r--compiler/rustc_expand/src/base.rs7
-rw-r--r--compiler/rustc_expand/src/expand.rs54
-rw-r--r--src/test/ui/conditional-compilation/cfg_accessible-stuck.rs2
-rw-r--r--src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr8
5 files changed, 42 insertions, 40 deletions
diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
index 75f4b077640..09ed1af3456 100644
--- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
@@ -1,7 +1,7 @@
 //! Implementation of the `#[cfg_accessible(path)]` attribute macro.
 
 use rustc_ast as ast;
-use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
+use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
 use rustc_feature::AttributeTemplate;
 use rustc_parse::validate_attr;
 use rustc_span::symbol::sym;
@@ -31,7 +31,7 @@ impl MultiItemModifier for Expander {
     fn expand(
         &self,
         ecx: &mut ExtCtxt<'_>,
-        _span: Span,
+        span: Span,
         meta_item: &ast::MetaItem,
         item: Annotatable,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
@@ -49,11 +49,14 @@ impl MultiItemModifier for Expander {
             None => return ExpandResult::Ready(Vec::new()),
         };
 
-        let failure_msg = "cannot determine whether the path is accessible or not";
         match ecx.resolver.cfg_accessible(ecx.current_expansion.id, path) {
             Ok(true) => ExpandResult::Ready(vec![item]),
             Ok(false) => ExpandResult::Ready(Vec::new()),
-            Err(_) => ExpandResult::Retry(item, failure_msg.into()),
+            Err(Indeterminate) if ecx.force_mode => {
+                ecx.span_err(span, "cannot determine whether the path is accessible or not");
+                ExpandResult::Ready(vec![item])
+            }
+            Err(Indeterminate) => ExpandResult::Retry(item),
         }
     }
 }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index b435def87ac..91617f2df9c 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -251,8 +251,7 @@ pub enum ExpandResult<T, U> {
     /// Expansion produced a result (possibly dummy).
     Ready(T),
     /// Expansion could not produce a result and needs to be retried.
-    /// The string is an explanation that will be printed if we are stuck in an infinite retry loop.
-    Retry(U, String),
+    Retry(U),
 }
 
 // `meta_item` is the attribute, and `item` is the item being modified.
@@ -919,6 +918,9 @@ pub struct ExtCtxt<'a> {
     pub root_path: PathBuf,
     pub resolver: &'a mut dyn ResolverExpand,
     pub current_expansion: ExpansionData,
+    /// Error recovery mode entered when expansion is stuck
+    /// (or during eager expansion, but that's a hack).
+    pub force_mode: bool,
     pub expansions: FxHashMap<Span, Vec<String>>,
     /// Called directly after having parsed an external `mod foo;` in expansion.
     pub(super) extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>,
@@ -945,6 +947,7 @@ impl<'a> ExtCtxt<'a> {
                 directory_ownership: DirectoryOwnership::Owned { relative: None },
                 prior_type_ascription: None,
             },
+            force_mode: false,
             expansions: FxHashMap::default(),
         }
     }
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 1b31bd6a305..a0ecc416617 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -404,6 +404,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     // Recursively expand all macro invocations in this AST fragment.
     pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment {
         let orig_expansion_data = self.cx.current_expansion.clone();
+        let orig_force_mode = self.cx.force_mode;
         self.cx.current_expansion.depth = 0;
 
         // Collect all macro invocations and replace them with placeholders.
@@ -432,6 +433,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
                 invocations = mem::take(&mut undetermined_invocations);
                 force = !mem::replace(&mut progress, false);
+                if force && self.monotonic {
+                    self.cx.sess.delay_span_bug(
+                        invocations.last().unwrap().0.span(),
+                        "expansion entered force mode without producing any errors",
+                    );
+                }
                 continue;
             };
 
@@ -460,18 +467,18 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
             let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data;
             self.cx.current_expansion = invoc.expansion_data.clone();
+            self.cx.force_mode = force;
 
             // FIXME(jseyfried): Refactor out the following logic
             let (expanded_fragment, new_invocations) = match res {
                 InvocationRes::Single(ext) => match self.expand_invoc(invoc, &ext.kind) {
                     ExpandResult::Ready(fragment) => self.collect_invocations(fragment, &[]),
-                    ExpandResult::Retry(invoc, explanation) => {
+                    ExpandResult::Retry(invoc) => {
                         if force {
-                            // We are stuck, stop retrying and produce a dummy fragment.
-                            let span = invoc.span();
-                            self.cx.span_err(span, &explanation);
-                            let fragment = invoc.fragment_kind.dummy(span);
-                            self.collect_invocations(fragment, &[])
+                            self.cx.span_bug(
+                                invoc.span(),
+                                "expansion entered force mode but is still stuck",
+                            );
                         } else {
                             // Cannot expand, will retry this invocation later.
                             undetermined_invocations
@@ -526,6 +533,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
 
         self.cx.current_expansion = orig_expansion_data;
+        self.cx.force_mode = orig_force_mode;
 
         // Finally incorporate all the expanded macros into the input AST fragment.
         let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
@@ -735,20 +743,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         Ok(meta) => {
                             let items = match expander.expand(self.cx, span, &meta, item) {
                                 ExpandResult::Ready(items) => items,
-                                ExpandResult::Retry(item, explanation) => {
+                                ExpandResult::Retry(item) => {
                                     // Reassemble the original invocation for retrying.
-                                    return ExpandResult::Retry(
-                                        Invocation {
-                                            kind: InvocationKind::Attr {
-                                                attr,
-                                                item,
-                                                derives,
-                                                after_derive,
-                                            },
-                                            ..invoc
+                                    return ExpandResult::Retry(Invocation {
+                                        kind: InvocationKind::Attr {
+                                            attr,
+                                            item,
+                                            derives,
+                                            after_derive,
                                         },
-                                        explanation,
-                                    );
+                                        ..invoc
+                                    });
                                 }
                             };
                             fragment_kind.expect_from_annotatables(items)
@@ -781,15 +786,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path };
                     let items = match expander.expand(self.cx, span, &meta, item) {
                         ExpandResult::Ready(items) => items,
-                        ExpandResult::Retry(item, explanation) => {
+                        ExpandResult::Retry(item) => {
                             // Reassemble the original invocation for retrying.
-                            return ExpandResult::Retry(
-                                Invocation {
-                                    kind: InvocationKind::Derive { path: meta.path, item },
-                                    ..invoc
-                                },
-                                explanation,
-                            );
+                            return ExpandResult::Retry(Invocation {
+                                kind: InvocationKind::Derive { path: meta.path, item },
+                                ..invoc
+                            });
                         }
                     };
                     fragment_kind.expect_from_annotatables(items)
diff --git a/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs b/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs
index 8bc93fa3243..50504a44c95 100644
--- a/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs
+++ b/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs
@@ -1,6 +1,6 @@
 #![feature(cfg_accessible)]
 
-#[cfg_accessible(Z)] //~ ERROR cannot determine whether the path is accessible or not
+#[cfg_accessible(Z)] // OK, recovered after the other `cfg_accessible` produces an error.
 struct S;
 
 #[cfg_accessible(S)] //~ ERROR cannot determine whether the path is accessible or not
diff --git a/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr b/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr
index 9641441a819..33af7d62548 100644
--- a/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr
+++ b/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr
@@ -4,11 +4,5 @@ error: cannot determine whether the path is accessible or not
 LL | #[cfg_accessible(S)]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: cannot determine whether the path is accessible or not
-  --> $DIR/cfg_accessible-stuck.rs:3:1
-   |
-LL | #[cfg_accessible(Z)]
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error