Skip to content

Commit 674c862

Browse files
committed
feat: allow authoring module units
1 parent 9221682 commit 674c862

File tree

4 files changed

+214
-105
lines changed

4 files changed

+214
-105
lines changed

regression-tests/test-results/pure2-bugfix-for-requires-clause-unbraced-function-initializer.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
//=== Cpp2 type definitions and function declarations ===========================
1212

1313
#line 1 "pure2-bugfix-for-requires-clause-unbraced-function-initializer.cpp2"
14-
template<typename T> auto f() -> void;
14+
template<typename T> auto f() -> void
15+
CPP2_REQUIRES (std::regular<T>)
16+
#line 1 "pure2-bugfix-for-requires-clause-unbraced-function-initializer.cpp2"
17+
;
1518
auto main() -> int;
1619

1720

source/common.h

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ struct source_line
4848
{
4949
std::string text;
5050

51-
enum class category { empty, preprocessor, comment, import, cpp1, cpp2, rawstring };
51+
enum class category { empty, preprocessor, comment, module_directive, module_declaration, import, cpp1, cpp2, rawstring };
5252
category cat;
5353

5454
bool all_tokens_are_densely_spaced = true; // to be overridden in lexing if they're not
@@ -73,13 +73,15 @@ struct source_line
7373
-> std::string
7474
{
7575
switch (cat) {
76-
break;case category::empty: return "/* */ ";
77-
break;case category::preprocessor: return "/* # */ ";
78-
break;case category::comment: return "/* / */ ";
79-
break;case category::import: return "/* i */ ";
80-
break;case category::cpp1: return "/* 1 */ ";
81-
break;case category::cpp2: return "/* 2 */ ";
82-
break;case category::rawstring: return "/* R */ ";
76+
break;case category::empty: return "/* */ ";
77+
break;case category::preprocessor: return "/* # */ ";
78+
break;case category::comment: return "/* / */ ";
79+
break;case category::module_directive: return "/* m#*/ ";
80+
break;case category::module_declaration: return "/* m */ ";
81+
break;case category::import: return "/* i */ ";
82+
break;case category::cpp1: return "/* 1 */ ";
83+
break;case category::cpp2: return "/* 2 */ ";
84+
break;case category::rawstring: return "/* R */ ";
8385
break;default: assert(!"illegal category"); abort();
8486
}
8587
}
@@ -127,7 +129,7 @@ struct string_parts {
127129

128130
string_parts(const std::string& beginseq,
129131
const std::string& endseq,
130-
adds_sequences strateg)
132+
adds_sequences strateg)
131133
: begin_seq{beginseq}
132134
, end_seq{endseq}
133135
, strategy{strateg}
@@ -144,16 +146,16 @@ struct string_parts {
144146
void clear() { parts.clear(); }
145147

146148
auto generate() const -> std::string {
147-
148-
if (parts.empty()) {
149-
return (strategy & on_the_beginning ? begin_seq : std::string{})
150-
+ (strategy & on_the_end ? end_seq : std::string{});
149+
150+
if (parts.empty()) {
151+
return (strategy & on_the_beginning ? begin_seq : std::string{})
152+
+ (strategy & on_the_end ? end_seq : std::string{});
151153
}
152154

153-
auto result = std::visit(begin_visit{begin_seq, strategy},
155+
auto result = std::visit(begin_visit{begin_seq, strategy},
154156
parts.front());
155157

156-
if (std::ssize(parts) > 1) {
158+
if (std::ssize(parts) > 1) {
157159
auto it1 = parts.cbegin();
158160
auto it2 = parts.cbegin()+1;
159161
for(;it2 != parts.cend(); ++it1, ++it2) {

source/cppfront.cpp

Lines changed: 121 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,70 @@ class cppfront
12231223
// Generate a reasonable macroized name
12241224
auto cpp1_FILENAME = to_upper_and_underbar(cpp1_filename);
12251225

1226+
lineno_t curr_lineno = 0;
1227+
auto hpp_includes = std::string{};
1228+
1229+
auto print_cpp2util = [&]() {
1230+
if (!tokens.get_map().empty()) {
1231+
printer.print_extra( "\n#include \"cpp2util.h\"\n\n" );
1232+
}
1233+
};
1234+
1235+
auto emit_cpp1_line = [&](auto const& line) {
1236+
if (
1237+
source.has_cpp2()
1238+
&& line.cat == source_line::category::empty
1239+
)
1240+
{
1241+
++ret.cpp2_lines;
1242+
}
1243+
else
1244+
{
1245+
++ret.cpp1_lines;
1246+
}
1247+
1248+
if (
1249+
flag_cpp2_only
1250+
&& !line.text.empty()
1251+
&& line.cat != source_line::category::comment
1252+
&& line.cat != source_line::category::module_directive
1253+
&& line.cat != source_line::category::module_declaration
1254+
&& line.cat != source_line::category::import
1255+
)
1256+
{
1257+
if (line.cat == source_line::category::preprocessor) {
1258+
if (!line.text.ends_with(".h2\"")) {
1259+
errors.emplace_back(
1260+
source_position(curr_lineno, 1),
1261+
"pure-cpp2 switch disables the preprocessor, including #include (except of .h2 files) - use import instead (note: 'import std;' is implicit in -pure-cpp2)"
1262+
);
1263+
return false;
1264+
}
1265+
}
1266+
else {
1267+
errors.emplace_back(
1268+
source_position(curr_lineno, 1),
1269+
"pure-cpp2 switch disables Cpp1 syntax"
1270+
);
1271+
return false;
1272+
}
1273+
}
1274+
1275+
if (
1276+
line.cat == source_line::category::preprocessor
1277+
&& line.text.ends_with(".h2\"")
1278+
)
1279+
{
1280+
// Strip off the 2"
1281+
auto h_include = line.text.substr(0, line.text.size()-2);
1282+
printer.print_cpp1( h_include + "\"", curr_lineno );
1283+
hpp_includes += h_include + "pp\"\n";
1284+
}
1285+
else {
1286+
printer.print_cpp1( line.text, curr_lineno );
1287+
}
1288+
return true;
1289+
};
12261290

12271291
//---------------------------------------------------------------------
12281292
// Do lowered file prolog
@@ -1237,23 +1301,62 @@ class cppfront
12371301
printer.print_extra( "#define " + cpp1_FILENAME+"__CPP2" + "\n\n" );
12381302
}
12391303

1240-
if (flag_use_source_location) {
1241-
printer.print_extra( "#define CPP2_USE_SOURCE_LOCATION Yes\n" );
1242-
}
1243-
if (flag_cpp2_only) {
1244-
printer.print_extra( "#define CPP2_USE_MODULES Yes\n" );
1245-
}
1246-
if (flag_no_exceptions) {
1247-
printer.print_extra( "#define CPP2_NO_EXCEPTIONS Yes\n" );
1304+
auto print_cpp2util_prolog = [&]() {
1305+
if (flag_use_source_location) {
1306+
printer.print_extra( "#define CPP2_USE_SOURCE_LOCATION Yes\n" );
1307+
}
1308+
if (flag_cpp2_only) {
1309+
printer.print_extra( "#define CPP2_USE_MODULES Yes\n" );
1310+
}
1311+
if (flag_no_exceptions) {
1312+
printer.print_extra( "#define CPP2_NO_EXCEPTIONS Yes\n" );
1313+
}
1314+
if (flag_no_rtti) {
1315+
printer.print_extra( "#define CPP2_NO_RTTI Yes\n" );
1316+
}
1317+
};
1318+
1319+
auto printed_module_directive = false;
1320+
1321+
if (source.is_module()) {
1322+
if (!source.has_module_directive())
1323+
{
1324+
printer.print_extra( "module;\n" );
1325+
printed_module_directive = true;
1326+
print_cpp2util_prolog();
1327+
print_cpp2util();
1328+
}
1329+
} else {
1330+
print_cpp2util_prolog();
12481331
}
1249-
if (flag_no_rtti) {
1250-
printer.print_extra( "#define CPP2_NO_RTTI Yes\n" );
1332+
1333+
// Module lines.
1334+
for (auto const& line : source.get_module_lines())
1335+
{
1336+
// Skip dummy line we added to make 0-vs-1-based offsets readable
1337+
if (curr_lineno != 0)
1338+
{
1339+
assert(line.cat != source_line::category::cpp2);
1340+
1341+
if (!emit_cpp1_line(line)) {
1342+
return {};
1343+
}
1344+
1345+
if (
1346+
!printed_module_directive
1347+
&& line.cat == source_line::category::module_directive
1348+
)
1349+
{
1350+
printed_module_directive = true;
1351+
print_cpp2util_prolog();
1352+
print_cpp2util();
1353+
}
1354+
}
1355+
++curr_lineno;
12511356
}
12521357
}
12531358

12541359
auto map_iter = tokens.get_map().cbegin();
1255-
auto hpp_includes = std::string{};
1256-
12571360

12581361
//---------------------------------------------------------------------
12591362
// Do phase0_type_decls
@@ -1267,9 +1370,8 @@ class cppfront
12671370
printer.print_extra( "\n//=== Cpp2 type declarations ====================================================\n\n" );
12681371
}
12691372

1270-
if (!tokens.get_map().empty())
1271-
{
1272-
printer.print_extra( "\n#include \"cpp2util.h\"\n\n" );
1373+
if (!source.is_module()) {
1374+
print_cpp2util();
12731375
}
12741376

12751377
for (auto& section : tokens.get_map())
@@ -1300,66 +1402,15 @@ class cppfront
13001402
}
13011403

13021404
assert (printer.get_phase() == positional_printer::phase1_type_defs_func_decls);
1303-
for (
1304-
lineno_t curr_lineno = 0;
1305-
auto const& line : source.get_lines()
1306-
)
1405+
for (auto const& line : source.get_non_module_lines())
13071406
{
13081407
// Skip dummy line we added to make 0-vs-1-based offsets readable
13091408
if (curr_lineno != 0)
13101409
{
13111410
// If it's a Cpp1 line, emit it
1312-
if (line.cat != source_line::category::cpp2)
1313-
{
1314-
if (
1315-
source.has_cpp2()
1316-
&& line.cat == source_line::category::empty
1317-
)
1318-
{
1319-
++ret.cpp2_lines;
1320-
}
1321-
else
1322-
{
1323-
++ret.cpp1_lines;
1324-
}
1325-
1326-
if (
1327-
flag_cpp2_only
1328-
&& !line.text.empty()
1329-
&& line.cat != source_line::category::comment
1330-
&& line.cat != source_line::category::import
1331-
)
1332-
{
1333-
if (line.cat == source_line::category::preprocessor) {
1334-
if (!line.text.ends_with(".h2\"")) {
1335-
errors.emplace_back(
1336-
source_position(curr_lineno, 1),
1337-
"pure-cpp2 switch disables the preprocessor, including #include (except of .h2 files) - use import instead (note: 'import std;' is implicit in -pure-cpp2)"
1338-
);
1339-
return {};
1340-
}
1341-
}
1342-
else {
1343-
errors.emplace_back(
1344-
source_position(curr_lineno, 1),
1345-
"pure-cpp2 switch disables Cpp1 syntax"
1346-
);
1347-
return {};
1348-
}
1349-
}
1350-
1351-
if (
1352-
line.cat == source_line::category::preprocessor
1353-
&& line.text.ends_with(".h2\"")
1354-
)
1355-
{
1356-
// Strip off the 2"
1357-
auto h_include = line.text.substr(0, line.text.size()-2);
1358-
printer.print_cpp1( h_include + "\"", curr_lineno );
1359-
hpp_includes += h_include + "pp\"\n";
1360-
}
1361-
else {
1362-
printer.print_cpp1( line.text, curr_lineno );
1411+
if (line.cat != source_line::category::cpp2) {
1412+
if (!emit_cpp1_line(line)) {
1413+
return {};
13631414
}
13641415
}
13651416

0 commit comments

Comments
 (0)