Skip to content

Commit 64471ab

Browse files
committed
ImportC: Add __module declarations
1 parent 8b215f8 commit 64471ab

File tree

10 files changed

+133
-9
lines changed

10 files changed

+133
-9
lines changed

changelog/dmd.import-c-modules.dd

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
C files can now include a module statement
2+
3+
Similar to the `__import` extension, the `__module` keyword brings D's module declaration to C.
4+
5+
It's particularly useful when you want to import multiple C files with the same name
6+
(e.g. hello/utils.c and world/utils.c), since both have to be imported with `import utils` when
7+
they are listed on the command line, resulting in conflicts.
8+
9+
Now you can do:
10+
11+
hello/utils.c:
12+
13+
```C
14+
15+
#if __IMPORTC__
16+
__module hello.utils;
17+
#endif
18+
19+
int sqr(int x) { return x * x; }
20+
```
21+
22+
world/utils.c:
23+
```C
24+
25+
#if __IMPORTC__
26+
__module world.utils;
27+
#endif
28+
29+
int max(int a, int b) { return a > b ? a : b; }
30+
```
31+
32+
app.d:
33+
```D
34+
import hello.utils;
35+
import world.utils;
36+
37+
static assert(sqr(3) == 9);
38+
static assert(max(3, 5) == 5);
39+
```
40+
41+
A __module declaration can appear anywhere in the top level scope.
42+
When there are multiple, the first one will be used.
43+
Therefore, every `#include` containing a __module declaration should come after the file's own module declaration,
44+
or it will be overwritten.
45+
When you always put the __module declaration at the very top like in D, there won't be such problems.

compiler/src/dmd/cparse.d

+14
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,20 @@ final class CParser(AST) : Parser!AST
143143
return wrap;
144144
}
145145

146+
if (token.value == TOK._module)
147+
{
148+
token.value = TOK.module_;
149+
auto oldMd = this.md;
150+
parseModuleDeclaration();
151+
if (oldMd)
152+
{
153+
// We only use the first module declaration,
154+
// subsequent __module statements should only come from #included files
155+
this.md = oldMd;
156+
}
157+
continue;
158+
}
159+
146160
/* GNU Extensions
147161
* external-declaration:
148162
* simple-asm-expr ;

compiler/src/dmd/dmodule.d

+7-1
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,13 @@ extern (C++) final class Module : Package
793793
p.nextToken();
794794
checkCompiledImport();
795795
members = p.parseModule();
796-
assert(!p.md); // C doesn't have module declarations
796+
md = p.md;
797+
if (md)
798+
{
799+
this.ident = md.id;
800+
dst = Package.resolve(md.packages, &this.parent, &ppack);
801+
}
802+
797803
numlines = p.scanloc.linnum;
798804
}
799805
else

compiler/src/dmd/frontend.h

+8-7
Original file line numberDiff line numberDiff line change
@@ -3007,13 +3007,14 @@ enum class TOK : uint8_t
30073007
_Thread_local_ = 217u,
30083008
_assert_ = 218u,
30093009
_import_ = 219u,
3010-
__cdecl_ = 220u,
3011-
__declspec_ = 221u,
3012-
__stdcall_ = 222u,
3013-
__thread_ = 223u,
3014-
__pragma_ = 224u,
3015-
__int128_ = 225u,
3016-
__attribute___ = 226u,
3010+
_module = 220u,
3011+
__cdecl_ = 221u,
3012+
__declspec_ = 222u,
3013+
__stdcall_ = 223u,
3014+
__thread_ = 224u,
3015+
__pragma_ = 225u,
3016+
__int128_ = 226u,
3017+
__attribute___ = 227u,
30173018
};
30183019

30193020
class FuncExp final : public Expression

compiler/src/dmd/tokens.d

+4-1
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ enum TOK : ubyte
277277
// C only extended keywords
278278
_assert,
279279
_import,
280+
_module,
280281
__cdecl,
281282
__declspec,
282283
__stdcall,
@@ -586,6 +587,7 @@ private immutable TOK[] keywords =
586587
// C only extended keywords
587588
TOK._assert,
588589
TOK._import,
590+
TOK._module,
589591
TOK.__cdecl,
590592
TOK.__declspec,
591593
TOK.__stdcall,
@@ -621,7 +623,7 @@ static immutable TOK[TOK.max + 1] Ckeywords =
621623
union_, unsigned, void_, volatile, while_, asm_, typeof_,
622624
_Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn,
623625
_Static_assert, _Thread_local,
624-
_import, __cdecl, __declspec, __stdcall, __thread, __pragma, __int128, __attribute__,
626+
_import, _module, __cdecl, __declspec, __stdcall, __thread, __pragma, __int128, __attribute__,
625627
_assert ];
626628

627629
foreach (kw; Ckwds)
@@ -901,6 +903,7 @@ extern (C++) struct Token
901903
// C only extended keywords
902904
TOK._assert : "__check",
903905
TOK._import : "__import",
906+
TOK._module : "__module",
904907
TOK.__cdecl : "__cdecl",
905908
TOK.__declspec : "__declspec",
906909
TOK.__stdcall : "__stdcall",

compiler/src/dmd/tokens.h

+1
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ enum class TOK : unsigned char
283283
// C only extended keywords
284284
_assert,
285285
_import,
286+
_module,
286287
cdecl_,
287288
declspec,
288289
stdcall,

compiler/test/compilable/cmodules.d

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
EXTRA_SOURCES: imports/cpkg/cmodule.c
3+
*/
4+
5+
import imports.cpkg.cmodule;
6+
7+
static assert(sqr(3) == 9);
8+
9+
void main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// D module declaration
2+
3+
#if __IMPORTC__
4+
5+
__module imports.cpkg.cmodule;
6+
7+
// Only the first module statement is used,
8+
// subsequent __module declarations are assumed to come from #included other files
9+
__module some.header;
10+
11+
#endif
12+
13+
int sqr(int i) { return i * i; }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
TEST_OUTPUT:
3+
---
4+
fail_compilation/cmodule_malformed.c(15): Error: identifier expected following `module`
5+
fail_compilation/cmodule_malformed.c(15): Error: no type for declarator before `"a"`
6+
fail_compilation/cmodule_malformed.c(21): Error: no type-specifier for struct member
7+
fail_compilation/cmodule_malformed.c(21): Error: identifier or `(` expected
8+
fail_compilation/cmodule_malformed.c(21): Error: expected identifier for declarator
9+
fail_compilation/cmodule_malformed.c(26): Error: found `__module` instead of statement
10+
---
11+
*/
12+
13+
#if __IMPORTC__
14+
15+
__module "a";
16+
17+
typedef struct S
18+
{
19+
int x;
20+
21+
__module b;
22+
} S;
23+
24+
void main(void)
25+
{
26+
__module c.d;
27+
}
28+
29+
__module e;
30+
31+
#endif

compiler/test/unit/lexer/location_offset.d

+1
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ enum ignoreTokens
542542

543543
_assert,
544544
_import,
545+
_module,
545546
__cdecl,
546547
__declspec,
547548
__stdcall,

0 commit comments

Comments
 (0)