aboutsummaryrefslogtreecommitdiff
path: root/build2
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-06-24 11:43:45 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-06-24 11:43:45 +0200
commit1958b829f22e3b69d4c4c23662e0d1c7c4d2e62b (patch)
treefb94b1cba0d34e9b4cc6e1834495a9bd1e62a289 /build2
parentff8ed209cd80799199e0b2e3d37213d549bc342f (diff)
Make VC compatible with 'export module M;' by fixing up preprocessed output
Diffstat (limited to 'build2')
-rw-r--r--build2/cc/compile.cxx32
-rw-r--r--build2/cc/lexer.cxx7
-rw-r--r--build2/cc/lexer.hxx21
-rw-r--r--build2/cc/parser.cxx5
-rw-r--r--build2/cc/parser.hxx3
5 files changed, 55 insertions, 13 deletions
diff --git a/build2/cc/compile.cxx b/build2/cc/compile.cxx
index eddd465..9b8f31b 100644
--- a/build2/cc/compile.cxx
+++ b/build2/cc/compile.cxx
@@ -2398,7 +2398,37 @@ namespace build2
// implementation units.
//
if (cid == compiler_id::msvc && src.is_a (*x_mod))
- tu.mod.iface = true;
+ {
+ // It's quite painful to guard the export with an #if/#endif so
+ // if it is present, "fixup" the (temporary) preprocessed output
+ // by getting rid of the keyword.
+ //
+ // Note: when removing this also remember to remove the test.
+ //
+ if (tu.mod.iface)
+ {
+ // We can only fixup a temporary file.
+ //
+ if (!ps)
+ fail (relative (src)) << "fixup requires preprocessor";
+
+ // Stomp out the export keyword with spaces. We are using
+ // std::fstream since our fdstream does not yet support
+ // seeking.
+ //
+ fstream os (psrc.path ().string (),
+ fstream::out | fstream::in);
+
+ auto pos (static_cast<fstream::pos_type> (p.export_pos));
+
+ if (!os.is_open () ||
+ !os.seekp (pos) ||
+ !os.write (" ", 6))
+ fail << "unable to overwrite preprocessor output";
+ }
+ else
+ tu.mod.iface = true;
+ }
return tu;
}
diff --git a/build2/cc/lexer.cxx b/build2/cc/lexer.cxx
index faf73c8..ba6ea18 100644
--- a/build2/cc/lexer.cxx
+++ b/build2/cc/lexer.cxx
@@ -330,6 +330,13 @@ namespace build2
if (alpha (c) || c == '_')
{
+ // This smells a little: we know skip_spaces() did not peek at
+ // the next character because this is not '/'. Which means the
+ // position in the stream must be of this character + 1.
+ //
+ if (buf_ != nullptr)
+ t.position = buf_->tellg () - 1;
+
string& id (t.value);
id.clear ();
diff --git a/build2/cc/lexer.hxx b/build2/cc/lexer.hxx
index c74a0a9..65e9012 100644
--- a/build2/cc/lexer.hxx
+++ b/build2/cc/lexer.hxx
@@ -50,22 +50,19 @@ namespace build2
struct token
{
- token_type type;
+ token_type type = token_type::eos;
string value;
+ // Logical position.
+ //
path file;
- uint64_t line;
- uint64_t column;
-
- public:
- token ()
- : token (token_type::eos, 0, 0) {}
+ uint64_t line = 0;
+ uint64_t column = 0;
- token (token_type t, uint64_t l, uint64_t c)
- : token (t, string (), l, c) {}
-
- token (token_type t, string v, uint64_t l, uint64_t c)
- : type (t), value (move (v)), line (l), column (c) {}
+ // Physical position in the stream, currently only for identifiers and
+ // only if the stream is ifdstream.
+ //
+ uint64_t position = 0;
};
// Output the token value in a format suitable for diagnostics.
diff --git a/build2/cc/parser.cxx b/build2/cc/parser.cxx
index aae49dc..df2e257 100644
--- a/build2/cc/parser.cxx
+++ b/build2/cc/parser.cxx
@@ -82,13 +82,18 @@ namespace build2
}
else if (id == "export")
{
+ uint64_t pos (t.position);
+
switch (l_->next (t))
{
case type::lcbrace: ++bb; ex = true; break;
case type::identifier:
{
if (id == "module")
+ {
+ export_pos = pos;
parse_module (t, true);
+ }
else if (id == "import")
parse_import (t, true);
else
diff --git a/build2/cc/parser.hxx b/build2/cc/parser.hxx
index 8f327cd..d542d57 100644
--- a/build2/cc/parser.hxx
+++ b/build2/cc/parser.hxx
@@ -37,6 +37,9 @@ namespace build2
string
parse_module_name (token&);
+ public:
+ uint64_t export_pos; // Temporary hack, see parse_unit().
+
private:
lexer* l_;
translation_unit* u_;