aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/cc/lexer.hxx2
-rw-r--r--build2/cc/parser.cxx28
-rw-r--r--build2/cc/parser.hxx2
-rw-r--r--tests/cc/modules/testscript17
4 files changed, 45 insertions, 4 deletions
diff --git a/build2/cc/lexer.hxx b/build2/cc/lexer.hxx
index d41038d..0f52aff 100644
--- a/build2/cc/lexer.hxx
+++ b/build2/cc/lexer.hxx
@@ -177,7 +177,7 @@ namespace build2
// Diagnostics plumbing.
//
inline location
- get_location (const token& t, const void*)
+ get_location (const token& t, const void* = nullptr)
{
return location (&t.file, t.line, t.column);
}
diff --git a/build2/cc/parser.cxx b/build2/cc/parser.cxx
index b182ae4..e541d78 100644
--- a/build2/cc/parser.cxx
+++ b/build2/cc/parser.cxx
@@ -28,7 +28,8 @@ namespace build2
// diagnostics. However, the errors could as likely be because we are
// mis-parsing things. Initially, as a middle ground, we were going to
// issue warnings. But the problem with this approach is that they are
- // easy to miss. So for now we fail.
+ // easy to miss. So for now we fail. And it turns out we don't mis-
+ // parse much.
//
size_t bb (0); // {}-balance.
bool ex (false); // True if inside top-level export{} block.
@@ -63,6 +64,7 @@ namespace build2
// Constructs we need to recognize (the last one is only not to
// confuse it with others).
//
+ // module ;
// [export] import <module-name> [<attributes>] ;
// [export] module <module-name> [<attributes>] ;
// export { import <module-name> [<attributes>] ; }
@@ -120,6 +122,10 @@ namespace build2
if (bb != 0)
/*warn*/ fail (t) << "{}-imbalance detected";
+ if (module_marker_ && u.mod.name.empty ())
+ fail (*module_marker_) << "module declaration expected after "
+ << "leading module marker";
+
checksum = l.checksum ();
return u;
}
@@ -163,7 +169,23 @@ namespace build2
// enter: module keyword
// leave: semi
- l_->next (t); // Start of name.
+ location l (get_location (t));
+
+ l_->next (t);
+
+ // Handle the leading 'module;' marker (p0713).
+ //
+ // Note that we don't bother diagnosing invalid/duplicate markers
+ // leaving that to the compiler.
+ //
+ if (!ex && t.type == type::semi)
+ {
+ module_marker_ = move (l);
+ return;
+ }
+
+ // Otherwise it should be the start of the module name.
+ //
string n (parse_module_name (t));
// Should be {}-balanced.
@@ -174,7 +196,7 @@ namespace build2
fail (t) << "';' expected instead of " << t;
if (!u_->mod.name.empty ())
- fail (t) << "multiple module declarations";
+ fail (l) << "multiple module declarations";
u_->mod.name = move (n);
u_->mod.iface = ex;
diff --git a/build2/cc/parser.hxx b/build2/cc/parser.hxx
index fe40dcd..5a529fd 100644
--- a/build2/cc/parser.hxx
+++ b/build2/cc/parser.hxx
@@ -43,6 +43,8 @@ namespace build2
private:
lexer* l_;
translation_unit* u_;
+
+ optional<location> module_marker_;
};
}
}
diff --git a/tests/cc/modules/testscript b/tests/cc/modules/testscript
index 61cebc1..4401bfd 100644
--- a/tests/cc/modules/testscript
+++ b/tests/cc/modules/testscript
@@ -189,6 +189,23 @@ $* test clean <<EOI
lib{foo}: {mxx cxx}{core}
EOI
+: module-marker
+:
+: Test leading module marker (module;).
+:
+cat <<EOI >=core.mxx;
+#if __cpp_modules >= 201804
+module;
+#endif
+
+void g ();
+EOI
+cat <<<../core.mxx >+core.mxx;
+ln -s ../core.cxx ../driver.cxx ./;
+$* test clean <<EOI
+ exe{test}: cxx{driver} {mxx cxx}{core}
+ EOI
+
: re-export
:
: Test module re-exporting (export import M;)