[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