[gcc/devel/c++-modules] p1857 parser parts

Nathan Sidwell nathan@gcc.gnu.org
Fri Jan 31 13:35:00 GMT 2020


https://gcc.gnu.org/g:59068038ea2e13ff89e0ccdda0cf165cd1999f51

commit 59068038ea2e13ff89e0ccdda0cf165cd1999f51
Author: Nathan Sidwell <nathan@acm.org>
Date:   Thu Jan 30 08:45:53 2020 -0800

    p1857 parser parts
    
    	Implement p1857, part 2
    	libcpp/
    	* include/line-map.h (linemap_module_reparent): Declare.
    	* line-map.c (linemap_module_reparent): New.
    	gcc/cp/
    	* cp-lang.c (LANG_HOOKS_PREPROCESS_TOKEN): Adjust.
    	* cp-tree.h (module_preprocess_token): Rename to ...
    	(module_token_pre): ... here.
    	(module_token_{cdtor,lang}): Declare.
    	(module_map_header): Delete.
    	(module_preprocess): Adjust parameters.
    	(import_module): Delete, replace with ...
    	(import_modile_{pre,lang}): ... these.
    	(declare_module): Return void.
    	* lex.c (struct token_coro): New, broken out of ...
    	(module_preprocess_token): ... here.  Replace with ...
    	(module_token_{pre,lang,cdtor}): ... these.
    	* module.cc (module_state::read_location): Deal with early-read
    	partition locations.
    	(module_state::direct_import): Always preserve line map.  Take
    	for_cpp arg.
    	(import_module): Break into ...
    	(import_module_{pre,lang}): ... these.  Disable pending imports.
    	(declare_module): Adjust.
    	(module_map_header): Delete.
    	(module_preprocess): Do not change module array.  Return primary
    	module.
    	* parser.c (cp_lexer_tokenize): Delete.
    	(cp_lexer_new_main): New, resurrected from trunk.  Tokenize the
    	whole buffer.  Call the token coro.
    	(cp_parser_skip_to_closing_parenthesis_1): Deal with falling into
    	a module pseudo-pragma.
    	(cp_parser_skip_to_end_of_{,block_or_}statement): Likewise.
    	(cp_parser_translation_unit): Drop the incremental tokenization.
    	(cp_parser_module_name): Drop KIND parameter.
    	(cp_parser_module_directive_end): New.
    	(cp_parser_{import,module}_declaration): Adjust.
    	(cp_parser_declaration): Deal with (badly placed) import or module
    	declarations.
    	(cp_parser_toplevel_declaration): Restore PRAGMA parsing.
    	(c_parse_file): PCHness handled in cp_lexer_new_main, use it.
    	gcc/testsuite/
    	* g++.dg/modules/atom-decl-2.C: Adjust expected error
    	* g++.dg/modules/atom-pragma-3.C: Likewise.
    	* g++.dg/modules/exp-xlate-1_b.C: Likewise.
    	* g++.dg/modules/mod-decl-1.C: Likewise.
    	* g++.dg/modules/p0713-2.C: Likewise.
    	* g++.dg/modules/p0713-3.C: Likewise.
    	* g++.dg/modules/atom-preamble-2_d.C: Temporary XFAIL
    	* g++.dg/modules/unnamed-1_b.C: Adjust output scan

Diff:
---
 ChangeLog.modules                                |  51 +++
 gcc/cp/cp-lang.c                                 |   2 +-
 gcc/cp/cp-tree.h                                 |  21 +-
 gcc/cp/lex.c                                     | 302 +++++++-------
 gcc/cp/module.cc                                 | 190 +++++----
 gcc/cp/parser.c                                  | 480 ++++++++---------------
 gcc/testsuite/g++.dg/modules/atom-decl-2.C       |   2 +-
 gcc/testsuite/g++.dg/modules/atom-pragma-3.C     |   2 +-
 gcc/testsuite/g++.dg/modules/atom-preamble-2_d.C |   3 +-
 gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C     |   4 +-
 gcc/testsuite/g++.dg/modules/mod-decl-1.C        |  15 +-
 gcc/testsuite/g++.dg/modules/p0713-2.C           |   2 +-
 gcc/testsuite/g++.dg/modules/p0713-3.C           |   2 +-
 gcc/testsuite/g++.dg/modules/unnamed-1_b.C       |   2 +-
 libcpp/include/line-map.h                        |   5 +-
 libcpp/line-map.c                                |   7 +
 16 files changed, 521 insertions(+), 569 deletions(-)

diff --git a/ChangeLog.modules b/ChangeLog.modules
index cf2b16a0..ed5c73d 100644
--- a/ChangeLog.modules
+++ b/ChangeLog.modules
@@ -1,5 +1,56 @@
 2020-01-30  Nathan Sidwell  <nathan@acm.org>
 
+	Implement p1857, part 2
+	libcpp/
+	* include/line-map.h (linemap_module_reparent): Declare.
+	* line-map.c (linemap_module_reparent): New.
+	gcc/cp/
+	* cp-lang.c (LANG_HOOKS_PREPROCESS_TOKEN): Adjust.
+	* cp-tree.h (module_preprocess_token): Rename to ...
+	(module_token_pre): ... here.
+	(module_token_{cdtor,lang}): Declare.
+	(module_map_header): Delete.
+	(module_preprocess): Adjust parameters.
+	(import_module): Delete, replace with ...
+	(import_modile_{pre,lang}): ... these.
+	(declare_module): Return void.
+	* lex.c (struct token_coro): New, broken out of ...
+	(module_preprocess_token): ... here.  Replace with ...
+	(module_token_{pre,lang,cdtor}): ... these.
+	* module.cc (module_state::read_location): Deal with early-read
+	partition locations.
+	(module_state::direct_import): Always preserve line map.  Take
+	for_cpp arg.
+	(import_module): Break into ...
+	(import_module_{pre,lang}): ... these.  Disable pending imports.
+	(declare_module): Adjust.
+	(module_map_header): Delete.
+	(module_preprocess): Do not change module array.  Return primary
+	module.
+	* parser.c (cp_lexer_tokenize): Delete.
+	(cp_lexer_new_main): New, resurrected from trunk.  Tokenize the
+	whole buffer.  Call the token coro.
+	(cp_parser_skip_to_closing_parenthesis_1): Deal with falling into
+	a module pseudo-pragma.
+	(cp_parser_skip_to_end_of_{,block_or_}statement): Likewise.
+	(cp_parser_translation_unit): Drop the incremental tokenization.
+	(cp_parser_module_name): Drop KIND parameter.
+	(cp_parser_module_directive_end): New.
+	(cp_parser_{import,module}_declaration): Adjust.
+	(cp_parser_declaration): Deal with (badly placed) import or module
+	declarations.
+	(cp_parser_toplevel_declaration): Restore PRAGMA parsing.
+	(c_parse_file): PCHness handled in cp_lexer_new_main, use it.
+	gcc/testsuite/
+	* g++.dg/modules/atom-decl-2.C: Adjust expected error
+	* g++.dg/modules/atom-pragma-3.C: Likewise.
+	* g++.dg/modules/exp-xlate-1_b.C: Likewise.
+	* g++.dg/modules/mod-decl-1.C: Likewise.
+	* g++.dg/modules/p0713-2.C: Likewise.
+	* g++.dg/modules/p0713-3.C: Likewise.
+	* g++.dg/modules/atom-preamble-2_d.C: Temporary XFAIL
+	* g++.dg/modules/unnamed-1_b.C: Adjust output scan
+
 	gcc/cp/
 	* parser.c (cp_lexer_alloc): Remove pch finalizing.
 	(cp_parser_skip_to_closing_parenthesis_1): Deal with falling into
diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c
index 9fefa2e..d2e01556 100644
--- a/gcc/cp/cp-lang.c
+++ b/gcc/cp/cp-lang.c
@@ -86,7 +86,7 @@ static tree cxx_enum_underlying_base_type (const_tree);
 #undef LANG_HOOKS_PREPROCESS_DEFERRED_MACRO
 #define LANG_HOOKS_PREPROCESS_DEFERRED_MACRO module_cpp_deferred_macro
 #undef LANG_HOOKS_PREPROCESS_TOKEN
-#define LANG_HOOKS_PREPROCESS_TOKEN module_preprocess_token
+#define LANG_HOOKS_PREPROCESS_TOKEN module_token_pre
 
 #if CHECKING_P
 #undef LANG_HOOKS_RUN_LANG_SELFTESTS
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a1ee482..5a8e9e3 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6941,9 +6941,10 @@ extern void set_identifier_kind			(tree, cp_identifier_kind);
 extern bool cxx_init				(void);
 extern void cxx_finish				(void);
 extern bool in_main_input_context		(void);
-extern void *module_preprocess_token (cpp_reader *, const cpp_token *, void *);
-extern tree module_map_header (cpp_reader *, location_t, bool,
-			       const char *, size_t);
+extern void *module_token_pre (cpp_reader *, const cpp_token *, void *);
+extern void *module_token_cdtor (cpp_reader *, void *);
+extern void *module_token_lang (int type, int keyword, tree value, location_t,
+				void *);
 
 /* in method.c */
 extern void init_method				(void);
@@ -7001,7 +7002,9 @@ inline bool global_purview_p ()
 inline bool not_module_p ()
 { return (module_kind & (MK_MODULE | MK_GLOBAL)) == 0; }
 inline bool named_module_p ()
-{ /* The divides are constant shifts!  */
+{ /* This is a named module if exactly one of MODULE and GLOBAL is
+     set.  */
+  /* The divides are constant shifts!  */
   return ((module_kind / MK_MODULE) ^ (module_kind / MK_GLOBAL)) & 1;
 }
 inline bool header_module_p ()
@@ -7020,7 +7023,8 @@ inline bool module_exporting_p ()
 
 extern module_state *get_module (tree name, module_state *parent = NULL,
 				 bool partition = false);
-extern void module_preprocess (mkdeps *, module_state *, int is_module);
+extern module_state *module_preprocess (mkdeps *, module_state *,
+					bool is_import, bool is_export);
 extern bool module_may_redeclare (tree decl);
 
 /* Where the namespace-scope decl was originally declared.  */
@@ -7040,9 +7044,10 @@ extern void lazy_load_binding (unsigned mod, tree ns, tree id, mc_slot *mslot);
 extern void lazy_load_specializations (tree tmpl);
 extern void lazy_load_members (tree decl);
 extern bool lazy_specializations_p (unsigned, bool, bool);
-extern bool import_module (module_state *, location_t, bool, tree,
-			   cpp_reader *, bool in_extern_c);
-extern bool declare_module (module_state *, location_t, bool, tree,
+extern void import_module_pre (module_state *, location_t, tree, cpp_reader *);
+extern void import_module_lang (module_state *, location_t, bool, tree,
+				cpp_reader *, bool in_extern_c);
+extern void declare_module (module_state *, location_t, bool, tree attr,
 			    cpp_reader *);
 extern void process_deferred_imports (cpp_reader *);
 extern void module_cpp_undef (cpp_reader *, location_t, cpp_hashnode *);
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index c916be5..6df762a 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -383,169 +383,207 @@ interface_strcmp (const char* s)
 /* We've just read a cpp-token, figure out our next state.  Hey, this
    is a hand-coded co-routine!  */
 
-void *
-module_preprocess_token (cpp_reader *pfile, const cpp_token *tok, void *data_)
+struct token_coro
 {
-  enum mode_sm
+  enum state
   {
-   msm_idle,
-   msm_module_name,
-   msm_module_end,
+   idle,
+   module_first,
+   module_cont,
+   module_end,
   };
-  struct state
+
+  enum state state : 8;
+  bool is_import : 1;
+  bool is_header : 1;
+  bool got_export : 1;
+  bool got_colon : 1;
+  bool want_dot : 1;
+  location_t header_loc;
+  cpp_reader *reader;
+  mkdeps *deps;
+  module_state *module;
+  module_state *import;
+
+  token_coro (cpp_reader *reader)
+    : state (idle),
+    is_import (false), is_header (false),
+    got_export (false), got_colon (false), want_dot (false),
+    header_loc (UNKNOWN_LOCATION),
+    reader (reader), deps (cpp_get_deps (reader)),
+    module (NULL), import (NULL)
   {
-    mode_sm mode : 8;
-    bool is_import : 1;
-    bool is_header : 1;
-    bool got_export : 1;
-    bool got_colon : 1;
-    location_t header_loc;
-    unsigned tok_ix;
-    mkdeps *deps;
-    module_state *module;
-
-    state (mkdeps *deps)
-      : mode (msm_idle),
-      is_import (false), is_header (false),
-      got_export (false), got_colon (false),
-      header_loc (UNKNOWN_LOCATION),
-      tok_ix (0), deps (deps), module (NULL)
-    {
-    }
   };
-  state *data = (state *)data_;
 
-  if (!tok)
-    {
-      /* Initialize or teardown.  */
-      if (data)
-	{
-	  delete data;
-	  data = NULL;
-	}
-      else if (modules_p ())
-	data = new state (cpp_get_deps (pfile));
-      return data;
-    }
-
-  tree ident = NULL_TREE;
-  switch (data->mode)
-    {
-    case msm_idle:
-      if (tok->type == CPP_NAME)
-	{
-	  tree ident = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node.node));
-	  int keyword = C_RID_CODE (ident);
+  void resume (int type, int keyword, tree value, location_t loc)
+  {
+    switch (state)
+      {
+      case idle:
+	if (type == CPP_KEYWORD)
 	  switch (keyword)
 	    {
 	    default:
 	      break;
 
 	    case RID__EXPORT:
-	      data->got_export = true;
+	      got_export = true;
 	      break;
 
 	    case RID__IMPORT:
-	      data->is_import = true;
+	      is_import = true;
 	      /* FALLTHRU */
 	    case RID__MODULE:
-	      data->mode = msm_module_name;
-	      data->tok_ix = 0;
-	      data->got_colon = false;
-	      data->is_header = false;
+	      state = module_first;
+	      want_dot = false;
+	      got_colon = false;
+	      is_header = false;
 	      break;
 	    }
-	}
-      break;
-
-    case msm_module_name:
-      if (data->is_import && !data->tok_ix
-	  && tok->type == CPP_HEADER_NAME)
-	{
-	  /* A header name.  The preprocessor will have already
-	     done include searching and canonicalization.  */
-	  ident = build_string (tok->val.str.len,
-				(const char *)tok->val.str.text);
-	  data->is_header = true;
-	  data->header_loc = tok->src_loc;
-	  data->mode = msm_module_end;
-	  goto header_unit;
-	}
-
-      switch (tok->type)
-	{
-	case CPP_PADDING:
-	case CPP_COMMENT:
-	  gcc_unreachable ();
+	break;
 
-	default:
-	  data->mode = msm_module_end;
+      case module_first:
+	if (is_import && type == CPP_HEADER_NAME)
+	  {
+	    /* A header name.  The preprocessor will have already
+	       done include searching and canonicalization.  */
+	    is_header = true;
+	    header_loc = loc;
+	    state = module_end;
+	    goto header_unit;
+	  }
+	
+	if (type == CPP_PADDING || type == CPP_COMMENT)
 	  break;
 
-	case CPP_COLON:
-	  if (data->got_colon)
-	    data->mode = msm_module_end;
-	  data->got_colon = true;
-	  if (!data->tok_ix)
-	    /* We have a leading ':'  */
-	    data->tok_ix--;
-	  /* FALLTHROUGH  */
-	case CPP_DOT:
-	  if (!(data->tok_ix & 1))
-	    data->mode = msm_module_end;
-	  break;
+	state = module_cont;
+	if (type == CPP_COLON && module)
+	  {
+	    got_colon = true;
+	    import = module;
+	    break;
+	  }
+	/* FALLTHROUGH  */
+
+      case module_cont:
+	switch (type)
+	  {
+	  case CPP_PADDING:
+	  case CPP_COMMENT:
+	    break;
+
+	  default:
+	    state = module_end;
+	    break;
+
+	  case CPP_COLON:
+	    if (got_colon)
+	      state = module_end;
+	    got_colon = true;
+	    /* FALLTHROUGH  */
+	  case CPP_DOT:
+	    if (!want_dot)
+	      state = module_end;
+	    want_dot = false;
+	    break;
+
+	  case CPP_PRAGMA_EOL:
+	  case CPP_EOF:
+	    goto module_end;
+
+	  case CPP_NAME:
+	    if (want_dot)
+	      {
+		/* Got name instead of [.:].  */
+		state = module_end;
+		break;
+	      }
+	  header_unit:
+	    import = get_module (value, import, got_colon);
+	    want_dot = true;
+	    break;
+	  }
+	break;
+
+      case module_end:
+	if (type == CPP_PRAGMA_EOL || type == CPP_EOF)
+	  {
+	  module_end:;
+	    /* End of the directive, register the dep and maybe import
+	       the header.  */
+	    if (import)
+	      {
+		// FIXME: merge these two routines to a single entry
+		// point.
+		// FIXME: No preprocessor loading for preprocessed input
+		if (is_header)
+		  /* Load the header-unit import.  */
+		  import_module_pre (import, header_loc, NULL, reader);
+		
+		if (module_state *m = module_preprocess (deps, import,
+							 is_import, got_export))
+		  module = m;
+	      }
+
+	    import = NULL;
+	    is_import = got_export = false;
+	    state = idle;
+	  }
+	break;
+      }
+  }
+};
 
-	case CPP_PRAGMA_EOL:
-	case CPP_EOF:
-	  goto module_end;
+/* Initialize or teardown.  */
 
-	case CPP_NAME:
-	  if (data->tok_ix & 1)
-	    {
-	      /* Got name instead of [.:].  */
-	      data->mode = msm_module_end;
-	      break;
-	    }
+void *
+module_token_cdtor (cpp_reader *pfile, void *data_)
+{
+  token_coro *coro = (token_coro *)data_;
+  if (coro)
+    {
+      delete coro;
+      coro = NULL;
+    }
+  else if (modules_p ())
+    coro = new token_coro (pfile);
 
-	  ident = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node.node));
-	header_unit:
-	  data->module = get_module (ident, data->module, data->got_colon);
-	  break;
-	}
-      data->tok_ix++;
-      break;
+  return coro;
+}
 
-    case msm_module_end:
-      if (tok->type == CPP_PRAGMA_EOL
-	  || tok->type == CPP_EOF)
-	{
-	module_end:;
-	  /* End of the directive, register the dep and maybe import
-	     the header.  */
-	  if (data->module)
-	    {
-	      if (data->is_header)
-		/* Load the legacy import.  */
-		import_module (data->module, data->header_loc,
-			       data->got_export, NULL, pfile, false);
-
-	      if (data->deps)
-		module_preprocess (data->deps, data->module,
-				   data->is_import ? 0
-				   : data->got_export ? +1 : -1);
-	    }
+void *
+module_token_pre (cpp_reader *pfile, const cpp_token *tok, void *data_)
+{
+  if (!tok)
+    return module_token_cdtor (pfile, data_);
 
-	  data->module = NULL;
-	  data->header_loc = UNKNOWN_LOCATION;
-	  data->is_import = data->is_header = false;
-	  data->got_export = false;
+  int type = tok->type;
+  int keyword = RID_MAX;
+  tree value = NULL_TREE;
 
-	  data->mode = msm_idle;
+  if (tok->type == CPP_NAME)
+    {
+      value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node.node));
+      if (IDENTIFIER_KEYWORD_P (value))
+	{
+	  keyword = C_RID_CODE (value);
+	  type = CPP_KEYWORD;
 	}
-      break;
     }
+  else if (tok->type == CPP_HEADER_NAME)
+    value = build_string (tok->val.str.len, (const char *)tok->val.str.text);
+
+  return module_token_lang (type, keyword, value, tok->src_loc, data_);
+}
+
+void *
+module_token_lang (int type, int keyword, tree value, location_t loc,
+		   void *data_)
+{
+  token_coro *coro = (token_coro *)data_;
+  coro->resume (type, keyword, value, loc);
 
-  return data;
+  return data_;
 }
 
 /* Parse a #pragma whose sole argument is a string constant.
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index e4f07bc..f3dd342 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -3566,7 +3566,7 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state {
 
  public:
   bool do_import (const char *filename, cpp_reader *);
-  void direct_import (cpp_reader *, bool lazy);
+  void direct_import (cpp_reader *, bool for_cpp);
 };
 
 /* Hash module state by name.  This cannot be a member of
@@ -3681,6 +3681,7 @@ module_state_hash::equal (const value_type existing,
 /* Mapper name.  */
 static const char *module_mapper_name;
 
+// FIXME: pending_imports disabled during 1857 transition
 /* Deferred imports.  */
 static vec<module_state *, va_heap, vl_embed> *pending_imports;
 
@@ -15085,14 +15086,25 @@ module_state::read_location (bytes_in &sec) const
      case LK_IMPORT_MACRO:
      case LK_IMPORT_ORDINARY:
        {
-	 unsigned mod = slurp->remap_module (sec.u ());
+	 unsigned mod = sec.u ();
 	 unsigned off = sec.u ();
+	 const module_state *import = NULL;
 
-	 if (!mod)
-	   sec.set_overrun ();
+	 if (!mod && !slurp->remap)
+	   /* This is an early read of a partition location during the
+	      read of our ordinary location map.  */
+	   import = this;
 	 else
 	   {
-	     const module_state *import = (*modules)[mod];
+	     mod = slurp->remap_module (mod);
+	     if (!mod)
+	       sec.set_overrun ();
+	     else
+	       import = (*modules)[mod];
+	   }
+
+	 if (import)
+	   {
 	     if (kind == LK_IMPORT_MACRO)
 	       {
 		 if (off < import->macro_locs.second - macro_locs.first)
@@ -15354,10 +15366,10 @@ module_state::write_ordinary_maps (elf_out *to, location_map_info &info,
 	    {
 	      /* A partition's span will have a from pointing at a
 		 MODULE_INC.  Find that map's from.  */
-		line_map_ordinary const *fmap
-		  = linemap_check_ordinary (linemap_lookup (line_table, from));
-		if (MAP_MODULE_P (fmap))
-		  from = linemap_included_from (fmap);
+	      line_map_ordinary const *fmap
+		= linemap_check_ordinary (linemap_lookup (line_table, from));
+	      if (MAP_MODULE_P (fmap))
+		from = linemap_included_from (fmap);
 	    }
 	  write_location (sec, from);
 	}
@@ -17782,7 +17794,7 @@ module_state::do_import (char const *fname, cpp_reader *reader)
    map already).  */
 
 void
-module_state::direct_import (cpp_reader *reader, bool lazy)
+module_state::direct_import (cpp_reader *reader, bool for_cpp)
 {
   timevar_start (TV_MODULE_IMPORT);
   unsigned n = dump.push (this);
@@ -17793,44 +17805,42 @@ module_state::direct_import (cpp_reader *reader, bool lazy)
       char *fname = NULL;
       unsigned pre_hwm = 0;
 
-      if (!lazy)
-	{
-	  /* Preserve the state of the line-map.  */
-	  pre_hwm = LINEMAPS_ORDINARY_USED (line_table);
-	  if (module_has_cmi_p ())
-	    spans.close ();
+      /* Preserve the state of the line-map.  */
+      // FIXME: Only need to do this for in-tokenizing importing --
+      // i.e. [indirectly from] a header unit during preprocessing
+      pre_hwm = LINEMAPS_ORDINARY_USED (line_table);
+      if (true // FIXME: our tokenizer coroutine can tell us this
+	       // early enough.  Oly need to do this
+	  || module_has_cmi_p ())
+	spans.close ();
 
-	  maybe_create_loc ();
-	  fname = module_mapper::import_export (this, false);
-	}
+      maybe_create_loc ();
+      fname = module_mapper::import_export (this, false);
 
       if (!do_import (fname, reader)
 	  && !flag_preprocess_only)
 	fatal_error (loc, "returning to gate for a mechanical issue");
 
       /* Restore the line-map state.  */
-      if (!lazy)
-	{
-	  linemap_module_restore (line_table, pre_hwm);
-	  if (module_has_cmi_p ())
-	    spans.open ();
-	}
+      linemap_module_restore (line_table, pre_hwm);
+      if (true || module_has_cmi_p ())
+	spans.open ();
     }
 
   if (is_imported ())
     {
       direct_p = true;
-      if (exported_p)
-	exported_p = true;
 
-      if (is_header ())
+      if (for_cpp)
 	{
 	  read_preprocessor ();
 	  import_macros ();
 	}
-
-      read_language ();
-      (*modules)[0]->set_import (this, exported_p);
+      else
+	{
+	  read_language ();
+	  (*modules)[0]->set_import (this, exported_p);
+	}
     }
 
   dump.pop (n);
@@ -18033,42 +18043,57 @@ lazy_load_members (tree decl)
   timevar_stop (TV_MODULE_IMPORT);
 }
 
-/* Import the module NAME into the current TU and maybe re-export it.
-   Return true if the import affects macro state.  */
+/* Import IMP for preprocessor goodies.  */
+// FIXME: These two routines can probably be merged as a post-p1857 cleanup
 
-bool
-import_module (module_state *imp, location_t from_loc, bool exporting,
-	       tree, cpp_reader *reader, bool /*in_extern_c*/)
+void
+import_module_pre (module_state *imp, location_t from_loc, tree,
+		   cpp_reader *reader)
 {
-  if (module_exporting_p ())
-    exporting = true;
-
-  gcc_assert (global_namespace == current_scope ());
+  gcc_checking_assert (imp->is_header ());
   from_loc = ordinary_loc_of (line_table, from_loc);
 
-  if (!imp->check_not_purview (from_loc))
-    return false;
+  if (!imp->is_direct ())
+    {
+      if (!imp->is_detached ())
+	/* This was indirectly imported, reparent it so the include
+	   chain shows it directly.  */
+	linemap_module_reparent (line_table, imp->loc, from_loc);
+      imp->attach (from_loc);
+    }
+  imp->direct_import (reader, true);
+}
 
-  if (imp->is_detached ())
-    imp->attach (from_loc);
+/* Import IMP for language goodies.  It might already have been
+   imported for its preprocesseriness.  */
 
-  if (exporting)
-    imp->exported_p = true;
+void
+import_module_lang (module_state *imp, location_t from_loc, bool exporting,
+		    tree, cpp_reader *reader, bool /*in_extern_c*/)
+{
+  from_loc = ordinary_loc_of (line_table, from_loc);
 
-  if (imp->is_header ())
-    imp->direct_import (reader, false);
-  else
-    vec_safe_push (pending_imports, imp);
+  if (!imp->check_not_purview (from_loc))
+    return;
 
-  return imp->is_header ();
+  if (exporting || module_exporting_p ())
+    imp->exported_p = true;
+  
+  if (!imp->is_direct ())
+    {
+      if (!imp->is_detached ())
+	linemap_module_reparent (line_table, imp->loc, from_loc);
+      imp->attach (from_loc);
+    }
+  imp->direct_import (reader, false);
 }
 
 /* Declare the name of the current module to be NAME.  EXPORTING_p is
    true if this TU is the exporting module unit.  */
 
-bool
+void
 declare_module (module_state *state, location_t from_loc, bool exporting_p,
-		tree, cpp_reader *)
+		tree, cpp_reader *reader)
 {
   gcc_assert (global_namespace == current_scope ());
   from_loc = ordinary_loc_of (line_table, from_loc);
@@ -18076,18 +18101,17 @@ declare_module (module_state *state, location_t from_loc, bool exporting_p,
   module_state *current = (*modules)[0];
   if (module_purview_p () || !state->is_detached ())
     {
-      if (module_purview_p ())
-	state = current;
-
       error_at (from_loc, module_purview_p ()
 		? G_("module already declared")
 		: G_("module already imported"));
+      if (module_purview_p ())
+	state = current;
       inform (state->from_loc,
 	      module_purview_p ()
 	      ? G_("module %qs declared here")
 	      : G_("module %qs imported here"),
 	      state->get_flatname ());
-      return false;
+      return;
     }
 
   state->attach (from_loc);
@@ -18115,16 +18139,15 @@ declare_module (module_state *state, location_t from_loc, bool exporting_p,
 
       state->mod = 0;
       (*modules)[0] = state;
+      if (char *fname = module_mapper::import_export (state, true))
+	state->filename = xstrdup (fname);
     }
   else
     {
       state->primary_p = state->interface_p = true;
       current->parent = state; /* So mangler knows module identity. */
+      state->direct_import (reader, false);
     }
-
-  vec_safe_push (pending_imports, state);
-
-  return true;
 }
 
 /* Track if NODE undefs an imported macro.  */
@@ -18222,14 +18245,6 @@ canonicalize_header_name (cpp_reader *reader, location_t loc, bool unquoted,
   return str;
 }
 
-tree
-module_map_header (cpp_reader *reader, location_t loc, bool search,
-		   const char *str, size_t len)
-{
-  str = canonicalize_header_name (search ? reader : NULL, loc, false, str, len);
-  return build_string (len, str);
-}
-
 /* Figure out whether to treat HEADER as an include or an import.  */
 
 bool
@@ -18323,30 +18338,31 @@ module_translate_include (cpp_reader *reader, line_maps *lmaps, location_t loc,
   return res;
 }
 
-void
-module_preprocess (mkdeps *deps, module_state *state, int is_module)
+module_state *
+module_preprocess (mkdeps *deps, module_state *state,
+		   bool is_import, bool is_export)
 {
-  if (is_module)
-    /* Record the module, so that partition imports resolve
-       correctly.  */
-    (*modules)[0] = state;
-
   if (!state->flatname)
     state->set_flatname ();
 
-  const char *path = NULL;
-  if (is_module > 0
-      /* Partitions always produce a CMI.  */
-      || (is_module < 0 && state->is_partition ()))
+  if (deps)
     {
-      path = state->filename;
-      if (!path)
-	path = module_mapper::import_export (state, true);
-      path = path ? maybe_add_cmi_prefix (path) : "";
+      // FIXME: We should possibly do this after tokenization, when
+      // we've resolved the cmi names via the mapper
+      const char *path = NULL;
+      if (!is_import && (is_export || state->is_partition ()))
+	{
+	  path = state->filename;
+	  if (!path)
+	    path = module_mapper::import_export (state, true);
+	  path = path ? maybe_add_cmi_prefix (path) : "";
+	}
+
+      deps_add_module (deps, state->get_flatname (),
+		       path, state->is_header ());
     }
 
-  deps_add_module (deps, state->get_flatname (),
-		   path, state->is_header ());
+  return is_import ? NULL : get_primary (state);
 }
 
 /* We've just properly entered the main source file.  I.e. after the
@@ -18379,7 +18395,7 @@ module_begin_main_file (cpp_reader *reader, line_maps *lmaps,
 	      process_deferred_imports (reader);
 	    }
 	  else if (mkdeps *deps = cpp_get_deps (reader))
-	    module_preprocess (deps, state, 1);
+	    module_preprocess (deps, state, false, true);
 	}
     }
 }
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index bcaeafb..aef6234 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -623,6 +623,55 @@ cp_lexer_alloc (void)
   return lexer;
 }
 
+/* Create a new main C++ lexer, the lexer that gets tokens from the
+   preprocessor.  */
+
+static cp_lexer *
+cp_lexer_new_main (void)
+{
+  cp_token token;
+
+  /* It's possible that parsing the first pragma will load a PCH file,
+     which is a GC collection point.  So we have to do that before
+     allocating any memory.  */
+  cp_lexer_get_preprocessor_token (0, &token);
+  cp_parser_initial_pragma (&token);
+  c_common_no_more_pch ();
+
+  cp_lexer *lexer = cp_lexer_alloc ();
+  /* Put the first token in the buffer.  */
+  cp_token *tok = lexer->buffer->quick_push (token);
+
+  void *coro = NULL;
+  if (modules_p ())
+    coro = module_token_cdtor (parse_in, coro);
+
+  /* Get the remaining tokens from the preprocessor.  */
+  while (tok->type != CPP_EOF)
+    {
+      if (coro)
+	/* Process the previous token.  */
+	module_token_lang (tok->type, tok->keyword, tok->u.value,
+			   tok->location, coro);
+      tok = vec_safe_push (lexer->buffer, cp_token ());
+      cp_lexer_get_preprocessor_token (C_LEX_STRING_NO_JOIN, tok);
+    }
+
+  lexer->next_token = lexer->buffer->address ();
+  lexer->last_token = lexer->next_token
+                      + lexer->buffer->length ()
+		      - 1;
+
+  if (coro)
+    module_token_cdtor (parse_in, coro);
+
+  /* Subsequent preprocessor diagnostics should use compiler
+     diagnostic functions to get the compiler source location.  */
+  done_lexing = true;
+
+  gcc_assert (!lexer->next_token->purged_p);
+  return lexer;
+}
 
 /* Create a new lexer whose token stream is primed with the tokens in
    CACHE.  When these tokens are exhausted, no new tokens will be read.  */
@@ -848,160 +897,6 @@ cp_lexer_get_preprocessor_token (unsigned flags, cp_token *token)
     }
 }
 
-/* Tokenize until we've got to EOF (return false), or we've just gone
-   past import declaration that affects the tokenizer (return true).
-   Entry is a little tricky, because we want to scan the current last
-   token in the buffer, if it's not already been parsed.  (a) The
-   first token comes from peeking for PCH, and (b) error recovery
-   following a bad header import decl.  Bah!  */
-
-static bool
-cp_lexer_tokenize (cp_lexer *lexer, int extern_c_depth)
-{
-  enum 
-  {
-    decl_start,
-    decl_other,
-    decl_header,
-    decl_extern_c,
-    decl_pragma,
-  } mode = decl_start;
-  unsigned depth = 0;
-
-  unsigned next_in = lexer->next_token - lexer->buffer->address ();
-  cp_token *tok = lexer->next_token;
-
-  if (!next_in)
-    goto first;
-
-  /* Drop the fake CPP_EOF token.  */
-  lexer->buffer->pop ();
-  if (lexer->next_token->type != CPP_EOF)
-    {
-      /* We need to examine the token.  */
-      tok = &lexer->buffer->last ();
-      goto first;
-    }
-
-  for (;;)
-    {
-      tok = vec_safe_push (lexer->buffer, cp_token ());
-      /* Get the next token.  */
-      cp_lexer_get_preprocessor_token (C_LEX_STRING_NO_JOIN, tok);
-
-    first:
-      switch (tok->type)
-	{
-	case CPP_PRAGMA:
-	  mode = decl_pragma;
-	  break;
-
-	case CPP_EOF:
-	  done_lexing = true;
-	  goto done;
-
-	case CPP_OPEN_BRACE:
-	  if (mode == decl_extern_c)
-	    {
-	      extern_c_depth++;
-	      mode = decl_start;
-	      break;
-	    }
-
-	  /* FALLTHROUGH.  */
-	case CPP_OPEN_PAREN:
-	case CPP_OPEN_SQUARE:
-	  depth++;
-	  if (mode != decl_header)
-	    mode = decl_start;
-	  break;
-
-	case CPP_CLOSE_BRACE:
-	  if (!depth)
-	    {
-	      if (mode == decl_header)
-		goto done;
-	      if (extern_c_depth)
-		extern_c_depth--;
-	    }
-	  /* FALLTHROUGH.  */
-	case CPP_CLOSE_PAREN:
-	case CPP_CLOSE_SQUARE:
-	  if (depth)
-	    depth--;
-	  else if (mode != decl_header)
-	    mode = decl_start;
-	  break;
-
-	case CPP_PRAGMA_EOL:
-	  if (!depth && mode == decl_header)
-	    goto done;
-	  mode = decl_start;
-	  break;
-
-	case CPP_STRING:
-	  /* Any string keeps us in decl_extern_c mode.  */
-	  if (mode != decl_extern_c
-	      && mode != decl_header)
-	    mode = decl_other;
-	  break;
-
-	default:
-	  switch (mode)
-	    {
-	    case decl_header:
-	      break;
-
-	    case decl_start:
-	      if (tok->keyword == RID__EXPORT)
-		;
-	      else if (tok->keyword == RID_EXTERN)
-		mode = decl_extern_c;
-	      else if (tok->keyword == RID__IMPORT && !depth)
-		{
-		  tok = vec_safe_push (lexer->buffer, cp_token ());
-		  cp_lexer_get_preprocessor_token (C_LEX_STRING_NO_JOIN, tok);
-		  if (tok->type == CPP_HEADER_NAME)
-		    {
-		      /* A stoppable decl.  */
-		      mode = decl_header;
-		    }
-		  else
-		    /* Process the token as usual.  */
-		    goto first;
-		}
-	      else
-		mode = decl_other;
-	      break;
-
-	    default:
-	      mode = decl_other;
-	      break;
-	    }
-	  break;
-	}
-    }
-
- done:
-  vec_safe_reserve (lexer->buffer, 1);
-  lexer->next_token = &(*lexer->buffer)[next_in];
-  lexer->last_token = &lexer->buffer->last ();
-
-  if (done_lexing)
-    /* End of Buffer.  */
-    return false;
-
-  /* Push an EOF.  */
-  static cp_token eof = {CPP_EOF, RID_MAX, 0,
-			 false, false, false, false, false,
-			 UNKNOWN_LOCATION, NULL};
-  tok = lexer->buffer->quick_push (eof);
-  tok[0].location = tok[-1].location;
-
-  lexer->last_token++;
-  return true;
-}
-
 /* Update the globals input_location and the input file stack from TOKEN.  */
 static inline void
 cp_lexer_set_source_position_from_token (cp_token *token)
@@ -2156,7 +2051,7 @@ static cp_expr cp_parser_userdef_numeric_literal
 
 /* Basic concepts [gram.basic]  */
 
-static void cp_parser_translation_unit (cp_parser *, cp_token *);
+static void cp_parser_translation_unit (cp_parser *);
 
 /* Expressions [gram.expr]  */
 
@@ -2272,6 +2167,7 @@ static tree cp_parser_implicitly_scoped_statement
 static void cp_parser_already_scoped_statement
   (cp_parser *, bool *, const token_indent_info &);
 
+// FIXME: Needs a cleanup, both names and semantics
 enum module_preamble
 {
   /* Order is important.  */
@@ -2280,12 +2176,12 @@ enum module_preamble
   MP_NOTHING,	/* Not special in any way.  */
   MP_POST,	/* After preamble.  */
   MP_GMF,	/* Global Module Fragment.  */
+  MP_BAD,
 };
 
-static void cp_parser_module_directive_end (cp_parser *parser);
 static module_preamble cp_parser_module_declaration
   (cp_parser *parser, module_preamble, bool exporting);
-static bool cp_parser_import_declaration
+static void cp_parser_import_declaration
   (cp_parser *parser, module_preamble, bool exporting);
 
 /* Declarations [gram.dcl.dcl] */
@@ -3789,6 +3685,13 @@ cp_parser_skip_to_closing_parenthesis_1 (cp_parser *parser,
 	    condop_depth--;
 	  break;
 
+	case CPP_KEYWORD:
+	  if (token->keyword != RID__EXPORT
+	      && token->keyword != RID__MODULE
+	      && token->keyword != RID__IMPORT)
+	    break;
+	  /* FALLTHROUGH  */
+
 	case CPP_PRAGMA:
 	  /* We fell into a pragma.  Skip it, and continue. */
 	  cp_parser_skip_to_pragma_eol (parser, token);
@@ -3885,6 +3788,13 @@ cp_parser_skip_to_end_of_statement (cp_parser* parser)
 	  ++nesting_depth;
 	  break;
 
+	case CPP_KEYWORD:
+	  if (token->keyword != RID__EXPORT
+	      && token->keyword != RID__MODULE
+	      && token->keyword != RID__IMPORT)
+	    break;
+	  /* FALLTHROUGH  */
+
 	case CPP_PRAGMA:
 	  /* We fell into a pragma.  Skip it, and be done */
 	  cp_parser_skip_to_pragma_eol (parser, token);
@@ -3965,6 +3875,13 @@ cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser)
 	  nesting_depth++;
 	  break;
 
+	case CPP_KEYWORD:
+	  if (token->keyword != RID__EXPORT
+	      && token->keyword != RID__MODULE
+	      && token->keyword != RID__IMPORT)
+	    break;
+	  /* FALLTHROUGH  */
+
 	case CPP_PRAGMA:
 	  /* We fell into a pragma.  Skip it, and be done */
 	  cp_parser_skip_to_pragma_eol (parser, token);
@@ -4822,7 +4739,7 @@ cp_parser_userdef_string_literal (tree literal)
      declaration-seq [opt]  */
 
 static void
-cp_parser_translation_unit (cp_parser* parser, cp_token *tok)
+cp_parser_translation_unit (cp_parser* parser)
 {
   gcc_checking_assert (!cp_error_declarator);
 
@@ -4839,18 +4756,10 @@ cp_parser_translation_unit (cp_parser* parser, cp_token *tok)
   push_deferring_access_checks (flag_access_control
 				? dk_no_deferred : dk_no_check);
 
-  bool implicit_extern_c = false;
   module_preamble preamble =
     modules_p () && !module_purview_p () ? MP_FIRST : MP_NOTHING;
   bool deferred_imports = false;
-  int extern_c_depth = 0;
-
-  /* Push the already tokenized first token.  */
-  parser->lexer->next_token = vec_safe_push (parser->lexer->buffer, *tok);
-
- more_tokens:
-  /* Tokenize until EOF or end-of-{module,import}-decl.  */
-  bool more_tokens = cp_lexer_tokenize (parser->lexer, extern_c_depth);
+  bool implicit_extern_c = false;
 
   /* Parse until EOF.  */
   for (;;)
@@ -4871,41 +4780,27 @@ cp_parser_translation_unit (cp_parser* parser, cp_token *tok)
 	}
 
       if (token->type == CPP_EOF)
-	{
-	  if (more_tokens)
-	    /* We must retokenize some more, as the import affected
-	       the macro table.  Usually we only get here after parsing an
-	       import declaration, but bogus source may have caused the
-	       parser to have scanned past where the tokenizer thought
-	       there was one.  */
-	    goto more_tokens;
-	  break;
-	}
-      else if (token->type == CPP_PRAGMA)
-	{
-	  // FIXME: I think 1103r3 changes this?
-	  /* A pragma does not count as a declaration from a module
-	     POV.  */
-	  cp_parser_pragma (parser, pragma_external, NULL);
-	  continue;
-	}
-
+	break;
       if (modules_p ())
 	{
+	  /* Top-level module declarations are ok, and change the
+	     portion of file we're in.  Top-level import declarations
+	     are significant for the preamble.  */
+
+	  cp_token *next = token;
 	  bool exporting = token->keyword == RID__EXPORT;
-	  cp_token *next
-	    = exporting ? cp_lexer_peek_nth_token (parser->lexer, 2) : token;
-	  if (next->keyword == RID__MODULE && !extern_c_depth)
+	  if (exporting)
+	    {
+	      cp_lexer_consume_token (parser->lexer);
+	      next = cp_lexer_peek_token (parser->lexer);
+	    }
+	  if (next->keyword == RID__MODULE)
 	    {
 	      if (deferred_imports)
-		// FIXME: I think p1103 makes this unnecessary
 		/* The GMF may have deferred imports.  Do them before
 		   we become a module.  */
 		process_deferred_imports (parse_in);
 
-	      if (exporting)
-		cp_lexer_consume_token (parser->lexer);
-
 	      preamble
 		= cp_parser_module_declaration (parser, preamble, exporting);
 	      deferred_imports = true;
@@ -4915,21 +4810,20 @@ cp_parser_translation_unit (cp_parser* parser, cp_token *tok)
 	    {
 	      if (preamble == MP_FIRST)
 		preamble = MP_NOTHING;
-	      if (exporting)
-		cp_lexer_consume_token (parser->lexer);
 	      if (false && named_module_p ()
 		  && IDENTIFIER_POINTER (next->u.value)[0] == '_')
 		{
+		  // FIXME: Can we and do we need to detect this?
 		  error_at (next->location, "include-translated header unit"
 			    " not permitted in module purview");
 		  exporting = false;
 		}
-	      if (cp_parser_import_declaration (parser, preamble, exporting)
-		  && more_tokens)
-		goto more_tokens;
+	      cp_parser_import_declaration (parser, preamble, exporting);
 	      deferred_imports = true;
 	      continue;
 	    }
+	  else
+	    gcc_checking_assert (!exporting);
 
 	  if (preamble == MP_GMF && token->main_source_p)
 	    {
@@ -4942,34 +4836,6 @@ cp_parser_translation_unit (cp_parser* parser, cp_token *tok)
 			    " from preprocessor inclusion");
 		}
 	    }
-
-	  /* We have to detect outer level extern "C" { ... } here to
-	     deal with translated headers residing in such regions,
-	     which sadly are a thing.  */
-	  if (token->keyword == RID_EXTERN)
-	    {
-	      cp_token *str = cp_lexer_peek_nth_token (parser->lexer, 2);
-	      if (str->type == CPP_STRING
-		  && TREE_STRING_LENGTH (str->u.value) == 3
-		  && TREE_STRING_POINTER (str->u.value)[1] == 'C'
-		  && (cp_lexer_peek_nth_token (parser->lexer, 3)->type
-		      == CPP_OPEN_BRACE))
-		{
-		  cp_lexer_consume_token (parser->lexer);
-		  cp_lexer_consume_token (parser->lexer);
-		  cp_lexer_consume_token (parser->lexer);
-		  push_lang_context (lang_name_c);
-		  extern_c_depth++;
-		  continue;
-		}
-	    }
-	  else if (next->type == CPP_CLOSE_BRACE && extern_c_depth)
-	    {
-	      cp_lexer_consume_token (parser->lexer);
-	      pop_lang_context ();
-	      extern_c_depth--;
-	      continue;
-	    }
 	}
 
       /* This relies on the ordering of module_preamble values.  */
@@ -13495,34 +13361,24 @@ cp_parser_already_scoped_statement (cp_parser* parser, bool *if_p,
 /* Parse a module-name,
    identifier
    module-name . identifier
-   header-name (ATOM)
+   header-name
 
    Returns a pointer to module object, NULL.   */
 
 static module_state *
-cp_parser_module_name (cp_parser *parser, int kind)
+cp_parser_module_name (cp_parser *parser)
 {
   cp_token *token = cp_lexer_peek_token (parser->lexer);
   if (token->type == CPP_HEADER_NAME)
     {
       cp_lexer_consume_token (parser->lexer);
 
-      if (kind <= 0)
-	return get_module (token->u.value);
-
-      error_at (token->location,
-		"header unit cannot be explicitly declared");
-      return NULL;
-    }
-  else if (kind < 0)
-    {
-      error_at (token->location, "header unit name expected");
-      return NULL;
+      return get_module (token->u.value);
     }
 
   module_state *parent = NULL;
   bool partitioned = false;
-  if (!kind && token->type == CPP_COLON && named_module_p ())
+  if (token->type == CPP_COLON && named_module_p ())
     {
       partitioned = true;
       cp_lexer_consume_token (parser->lexer);
@@ -13538,37 +13394,18 @@ cp_parser_module_name (cp_parser *parser, int kind)
 
       tree name = cp_lexer_consume_token (parser->lexer)->u.value;
       parent = get_module (name, parent, partitioned);
-      if (kind > 0 && !partitioned
-	  && cp_lexer_peek_token (parser->lexer)->type == CPP_COLON)
+      token = cp_lexer_peek_token (parser->lexer);
+      if (!partitioned && token->type == CPP_COLON)
 	partitioned = true;
-      else if (cp_lexer_peek_token (parser->lexer)->type != CPP_DOT)
+      else if (token->type != CPP_DOT)
 	break;
+
       cp_lexer_consume_token (parser->lexer);
    }
 
   return parent;
 }
 
-static void
-cp_parser_module_directive_end (cp_parser *parser)
-{
-  parser->lexer->in_pragma = false;
-
-  for (bool first = true;; first = false)
-    {
-      cp_token *token = cp_lexer_peek_token (parser->lexer);
-      if (token->type != CPP_EOF)
-	cp_lexer_consume_token (parser->lexer);
-
-      if (token->type == CPP_PRAGMA_EOL)
-	break;
-      if (first)
-	cp_parser_error (parser, "expected end of control-line");
-      if (token->type == CPP_EOF)
-	break;
-    }
-}
-
 /* Named module-declaration
      __module ; PRAGMA_EOL
      [__export] __module module-name attr-spec-seq-opt ; PRAGMA_EOL
@@ -13590,34 +13427,26 @@ cp_parser_module_declaration (cp_parser *parser, module_preamble preamble,
       cp_lexer_consume_token (parser->lexer);
       module_kind |= MK_GLOBAL;
       preamble = MP_GMF;
-      goto out;
+      cp_parser_require_pragma_eol (parser, token);
     }
+  else if (preamble != MP_FIRST && preamble != MP_GMF)
+    {
+      error_at (token->location, "module-declaration not permitted here");
+    skip_eol:
+      cp_parser_skip_to_pragma_eol (parser, token);
+    }
+  else
+    {
+      module_state *mod = cp_parser_module_name (parser);
+      tree attrs = cp_parser_attributes_opt (parser);
 
-  {
-    module_state *mod = cp_parser_module_name (parser, true);
-    tree attrs = cp_parser_attributes_opt (parser);
-
-    if (!mod || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
-      {
-	/* Syntax error.  */
-	cp_parser_skip_to_end_of_statement (parser);
-	if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
-	  cp_lexer_consume_token (parser->lexer);
-
-	/* Remain in whatever state we were.  */
-	goto out;
-      }
-
-    /* Other cases will emit an error in declare_module.  */
-    if (preamble == MP_NOTHING)
-      error_at (token->location, "global module fragment not present");
-
-    if (declare_module (mod, token->location, exporting, attrs, parse_in))
       preamble = MP_PREAMBLE;
-  }
+      if (!mod || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
+	goto skip_eol;
 
- out:;
-  cp_parser_module_directive_end (parser);
+      declare_module (mod, token->location, exporting, attrs, parse_in);
+      cp_parser_require_pragma_eol (parser, token);
+    }
 
   return preamble;
 }
@@ -13626,7 +13455,7 @@ cp_parser_module_declaration (cp_parser *parser, module_preamble preamble,
    [__export] __import module-name attr-spec-seq-opt ; PRAGMA_EOL */
 // FIXME: This is untidy due to the 1857 transition in progress
 
-static bool
+static void
 cp_parser_import_declaration (cp_parser *parser, module_preamble preamble,
 			      bool exporting)
 {
@@ -13634,33 +13463,32 @@ cp_parser_import_declaration (cp_parser *parser, module_preamble preamble,
   parser->lexer->in_pragma = true;
 
   cp_token *token = cp_lexer_consume_token (parser->lexer);
-  int need_hdr = 0;//IDENTIFIER_POINTER (token->u.value)[0] == '_' ? -1 : 0;
-  module_state *mod = cp_parser_module_name (parser, need_hdr);
-  tree attrs = cp_parser_attributes_opt (parser);
-  bool ok = true;
 
-  if (!mod || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
+  if (preamble == MP_BAD || current_scope () != global_namespace)
     {
-      cp_parser_skip_to_end_of_statement (parser);
-      if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
-	cp_lexer_consume_token (parser->lexer);
-      ok = false;
+      error_at (token->location, "import-declaration must be at global scope");
+    skip_eol:
+      cp_parser_skip_to_pragma_eol (parser, token);
+    }
+  else if (preamble != MP_PREAMBLE
+	   && module_purview_p () && !global_purview_p ())
+    {
+      error_at (token->location, "import-declarations must immediately"
+		" follow the module-declaration");
+      goto skip_eol;
     }
   else
     {
-      if (preamble == MP_POST)
-	{
-	  error_at (token->location,
-		    "module import declarations must be within preamble");
-	  ok = false;
-	}
-      else
-	ok = import_module (mod, token->location, exporting, attrs, parse_in,
-			    current_lang_name == lang_name_c);
+      module_state *mod = cp_parser_module_name (parser);
+      tree attrs = cp_parser_attributes_opt (parser);
+      
+      if (!mod || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
+	goto skip_eol;
+      cp_parser_require_pragma_eol (parser, token);
+      import_module_lang (mod, token->location, exporting, attrs, parse_in,
+			  current_lang_name == lang_name_c);
     }
 
-  cp_parser_module_directive_end (parser);
-  return ok;
 }
 
 /*  export-declaration.
@@ -13819,6 +13647,19 @@ cp_parser_declaration (cp_parser* parser)
       else
 	cp_parser_module_export (parser);
     }
+  else if (token1->keyword == RID__EXPORT
+	   || token1->keyword == RID__IMPORT
+	   || token1->keyword == RID__MODULE)
+    {
+      bool exporting = token1->keyword == RID__EXPORT;
+      cp_token *next = exporting ? token2 : token1;
+      if (exporting)
+	cp_lexer_consume_token (parser->lexer);
+      if (next->keyword == RID__MODULE)
+	cp_parser_module_declaration (parser, MP_BAD, exporting);
+      else
+	cp_parser_import_declaration (parser, MP_NOTHING, exporting);
+    }
   /* If the next token is `extern', 'static' or 'inline' and the one
      after that is `template', we have a GNU extended explicit
      instantiation directive.  */
@@ -13874,7 +13715,13 @@ cp_parser_toplevel_declaration (cp_parser* parser)
 {
   cp_token *token = cp_lexer_peek_token (parser->lexer);
 
-  if (token->type == CPP_SEMICOLON)
+  if (token->type == CPP_PRAGMA)
+    /* A top-level declaration can consist solely of a #pragma.  A
+       nested declaration cannot, so this is done here and not in
+       cp_parser_declaration.  (A #pragma at block scope is
+       handled in cp_parser_statement.)  */
+    cp_parser_pragma (parser, pragma_external, NULL);
+  else if (token->type == CPP_SEMICOLON)
     {
       /* A declaration consisting of a single semicolon is
 	 invalid.  Allow it unless we're being pedantic.  */
@@ -29357,7 +29204,7 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
   /* Finish the function.  */
   fn = finish_function (inline_p);
 
-  if (flag_modules
+  if (modules_p ()
       && !inline_p
       && TYPE_P (DECL_CONTEXT (fn))
       && (DECL_DECLARED_INLINE_P (fn)
@@ -44183,22 +44030,13 @@ c_parse_file (void)
 		 "multi-source compilation not implemented for C++");
   already_called = true;
 
-  cp_token first;
-
-  /* It's possible that parsing the first pragma will load a PCH file,
-     which is a GC collection point.  So we have to do that before
-     allocating any memory.  Modules is incompatible with PCH.  */
-  cp_lexer_get_preprocessor_token (0, &first);
-  cp_parser_initial_pragma (&first);
-  c_common_no_more_pch ();
-
   /* cp_lexer_new_main is called before doing any GC allocation
      because tokenization might load a PCH file.  */
-  cp_lexer *lexer = cp_lexer_alloc ();
+  cp_lexer *lexer = cp_lexer_new_main ();
 
   the_parser = cp_parser_new (lexer);
 
-  cp_parser_translation_unit (the_parser, &first);
+  cp_parser_translation_unit (the_parser);
   class_decl_loc_t::diag_mismatched_tags ();
 
   the_parser = NULL;
diff --git a/gcc/testsuite/g++.dg/modules/atom-decl-2.C b/gcc/testsuite/g++.dg/modules/atom-decl-2.C
index de38b88..8938c35 100644
--- a/gcc/testsuite/g++.dg/modules/atom-decl-2.C
+++ b/gcc/testsuite/g++.dg/modules/atom-decl-2.C
@@ -1,6 +1,6 @@
 // { dg-additional-options "-fmodules-ts" }
 export module thing;
 int i;
-import baz; // { dg-error "must be within preamble" }
+import baz; // { dg-error "must immediately follow" }
 
 // { dg-warning "not writing module" "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/modules/atom-pragma-3.C b/gcc/testsuite/g++.dg/modules/atom-pragma-3.C
index 816e96d..e1e4dec 100644
--- a/gcc/testsuite/g++.dg/modules/atom-pragma-3.C
+++ b/gcc/testsuite/g++.dg/modules/atom-pragma-3.C
@@ -5,7 +5,7 @@ export module foo;
 ;
 
 #pragma pack(2)
-import baz; // { dg-error "must be within preamble" }
+import baz; // { dg-error "must immediately follow" }
 
 int i;
 
diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-2_d.C b/gcc/testsuite/g++.dg/modules/atom-preamble-2_d.C
index a96d57f..e0a7d8e 100644
--- a/gcc/testsuite/g++.dg/modules/atom-preamble-2_d.C
+++ b/gcc/testsuite/g++.dg/modules/atom-preamble-2_d.C
@@ -12,4 +12,5 @@ int i;
 int j; // end here
 
 // No duplicate mapper request.
-// { dg-final { scan-lang-dump "Mapper request:\\+IMPORT kevin\n-\n" module } }
+// FIXME: need to rejig the mapper request queueing post-1857
+// { dg-final { scan-lang-dump "Mapper request:\\+IMPORT kevin\n-\n" module { xfail *-*-* } } }
diff --git a/gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C b/gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C
index dd72f39..ba8c150 100644
--- a/gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C
+++ b/gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C
@@ -5,7 +5,5 @@ export module evil;
 // FIXME: xfailing until __import and co are actual keywords.
 export
 #include "exp-xlate-1_a.H" // { dg-error "not permitted" "" { xfail *-*-* } }
-// { dg-bogus "-:before end of line" "" { xfail *-*-* } }
-// { dg-bogus "before .__import" "" { xfail *-*-* } .-2 }
-
+// { dg-bogus "must immediately follow" "" { xfail *-*-* } .-1 }
 // { dg-prune-output {not writing module} }
diff --git a/gcc/testsuite/g++.dg/modules/mod-decl-1.C b/gcc/testsuite/g++.dg/modules/mod-decl-1.C
index 61784b47..287e7d0 100644
--- a/gcc/testsuite/g++.dg/modules/mod-decl-1.C
+++ b/gcc/testsuite/g++.dg/modules/mod-decl-1.C
@@ -6,28 +6,23 @@ export module frist;
 
 import frist; // { dg-error {cannot import module.* in its own purview} }
 
-module foo.second; // { dg-error "already declared" }
+module foo.second; // { dg-error "not permitted here" }
 
 namespace Foo 
 {
-  module  // { dg-error "does not name a type" }
-  third;
+module third;  // { dg-error "not permitted here" }
 }
 
 struct Baz
 {
-  module   // { dg-error "does not name a type" }
-  forth;
+  module forth; // { dg-error "expected" }
 };
 
 void Bink ()
 {
-  module   // { dg-error "not declared" }
-    fifth;
+  module fifth; // { dg-error "expected" }
 }
 
-module a.; // { dg-error "expected" }
-// { dg-error "already declared" "" { target *-*-* } .-1 }
-
+module a.; // { dg-error "not permitted" }
 
 // { dg-warning "not writing module" "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/modules/p0713-2.C b/gcc/testsuite/g++.dg/modules/p0713-2.C
index 03560cc..c7846e4 100644
--- a/gcc/testsuite/g++.dg/modules/p0713-2.C
+++ b/gcc/testsuite/g++.dg/modules/p0713-2.C
@@ -1,3 +1,3 @@
 // { dg-additional-options "-fmodules-ts" }
 int j;
-module; // { dg-error "expected" }
+module; // { dg-error "not permitted" }
diff --git a/gcc/testsuite/g++.dg/modules/p0713-3.C b/gcc/testsuite/g++.dg/modules/p0713-3.C
index 88a13c9..3c539eb 100644
--- a/gcc/testsuite/g++.dg/modules/p0713-3.C
+++ b/gcc/testsuite/g++.dg/modules/p0713-3.C
@@ -1,6 +1,6 @@
 // { dg-additional-options "-fmodules-ts" }
 int k;
-module frob; // { dg-error "global module fragment not present" }
+module frob; // { dg-error "not permitted" }
 // { dg-prune-output "failed to read" }
 // { dg-prune-output "fatal error:" }
 // { dg-prune-output "compilation terminated" }
diff --git a/gcc/testsuite/g++.dg/modules/unnamed-1_b.C b/gcc/testsuite/g++.dg/modules/unnamed-1_b.C
index 30856ac..847ced6 100644
--- a/gcc/testsuite/g++.dg/modules/unnamed-1_b.C
+++ b/gcc/testsuite/g++.dg/modules/unnamed-1_b.C
@@ -15,5 +15,5 @@ int main ()
   return 0;
 }
 
-// { dg-final { scan-lang-dump {> Bindings '::counter'} module } }
+// { dg-final { scan-lang-dump {Bindings '::counter'} module } }
 // { dg-final { scan-lang-dump {>Loading entity PiL\[0\] section:1} module } }
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index ca6d279..75f9376 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -440,7 +440,8 @@ struct GTY((tag ("1"))) line_map_ordinary : public line_map {
 
   /* Location from whence this line map was included.  For regular
      #includes, this location will be the last location of a map.  For
-     outermost file, this is 0.  */
+     outermost file, this is 0.  For modules it could be anywhere
+     within a map.  */
   location_t included_from;
 
   /* Size is 20 or 24 bytes, no padding  */
@@ -1132,6 +1133,8 @@ const line_map_macro *linemap_enter_macro (line_maps *, cpp_hashnode *,
 
 extern location_t linemap_module_loc
   (line_maps *, location_t from, const char *name);
+extern void linemap_module_reparent
+  (line_maps *, location_t loc, location_t new_parent);
 
 /* Restore the linemap state such that the map at LWM-1 continues.  */
 extern void linemap_module_restore
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index 8e38dd5..a944d23 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -613,6 +613,13 @@ linemap_module_loc (line_maps *set, location_t from, const char *name)
   return loc;
 }
 
+void
+linemap_module_reparent (line_maps *set, location_t loc, location_t adoptor)
+{
+  const line_map_ordinary *map = linemap_ordinary_map_lookup (set, loc);
+  const_cast<line_map_ordinary *> (map)->included_from = adoptor;
+}
+
 /* A linemap at LWM-1 was interrupted to insert module locations & imports.
    Append a new map, continuing the interrupted one.  */



More information about the Gcc-cvs mailing list