// if the definition still does not have a value, then it's an error
   if (!definition.has_value ())
     {
-      rust_error_at (invoc.get_locus (), ErrorCode::E0433,
-                    "could not resolve macro invocation");
+      collect_error ([&] () {
+       rust_error_at (invoc.get_locus (), ErrorCode::E0433,
+                      "could not resolve macro invocation");
+      });
       return;
     }
 
   // now do we need to keep mappings or something? or insert "uses" into our
   // ForeverStack? can we do that? are mappings simpler?
+  auto mappings = Analysis::Mappings::get ();
+  AST::MacroRulesDefinition *rules_def = nullptr;
+  if (!mappings->lookup_macro_def (definition.value (), &rules_def))
+    {
+      // Macro definition not found, maybe it is not expanded yet.
+      return;
+    }
+
+  AST::MacroRulesDefinition *tmp_def = nullptr;
+  if (mappings->lookup_macro_invocation (invoc, &tmp_def))
+    return;
+
+  mappings->insert_macro_invocation (invoc, rules_def);
 }
 
 void
 
 namespace Rust {
 namespace Resolver2_0 {
 
+using ResolveError = std::function<void ()>;
+
 class Early : public DefaultResolver
 {
   using DefaultResolver::visit;
 
   void go (AST::Crate &crate);
 
+  const std::vector<ResolveError> &get_macro_resolve_errors () const
+  {
+    return macro_resolve_errors;
+  }
+
   // we need to handle definitions for textual scoping
   void visit (AST::MacroRulesDefinition &) override;
 
   };
 
   TextualScope textual_scope;
+  std::vector<ResolveError> macro_resolve_errors;
+
+  void collect_error (ResolveError e) { macro_resolve_errors.push_back (e); }
 };
 
 } // namespace Resolver2_0
 
 
   if (macro.get_kind () == AST::MacroRulesDefinition::MacroKind::DeclMacro)
     insert_or_error_out (macro.get_rule_name (), macro, Namespace::Macros);
+
+  auto mappings = Analysis::Mappings::get ();
+  AST::MacroRulesDefinition *tmp = nullptr;
+  if (mappings->lookup_macro_def (macro.get_node_id (), &tmp))
+    return;
+
+  mappings->insert_macro_def (¯o);
 }
 
 void
 
   /* expand by calling cxtctxt object's monotonic_expander's expand_crate
    * method. */
   MacroExpander expander (crate, cfg, *this);
+  std::vector<Resolver2_0::ResolveError> macro_errors;
 
   while (!fixed_point_reached && iterations < cfg.recursion_limit)
     {
       auto ctx = Resolver2_0::NameResolutionContext ();
 
       if (flag_name_resolution_2_0)
-       Resolver2_0::Early (ctx).go (crate);
+       {
+         Resolver2_0::Early early (ctx);
+         early.go (crate);
+         macro_errors = early.get_macro_resolve_errors ();
+       }
       else
        Resolver::EarlyNameResolver ().go (crate);
 
        break;
     }
 
+  // Fixed point reached: Emit unresolved macros error
+  for (auto &error : macro_errors)
+    error ();
+
   if (iterations == cfg.recursion_limit)
     {
       auto &last_invoc = expander.get_last_invocation ();