Skip to content

Commit

Permalink
ImportC: Add __module declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
dkorpel committed Jan 8, 2025
1 parent 89546c1 commit f0058a1
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 9 deletions.
45 changes: 45 additions & 0 deletions changelog/dmd.import-c-modules.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
C files can now include a module statement

Similar to the `__import` extension, the `__module` keyword brings D's module declaration to C.

It's particularly useful when you want to import multiple C files with the same name
(e.g. hello/utils.c and world/utils.c), since both have to be imported with `import utils` when
they are listed on the command line, resulting in conflicts.

Now you can do:

hello/utils.c:

```C

#if __IMPORTC__
__module hello.utils;
#endif

int sqr(int x) { return x * x; }
```

world/utils.c:
```C

#if __IMPORTC__
__module world.utils;
#endif

int max(int a, int b) { return a > b ? a : b; }
```

app.d:
```D
import hello.utils;
import world.utils;

static assert(sqr(3) == 9);
static assert(max(3, 5) == 5);
```

A __module declaration can appear anywhere in the top level scope.
When there are multiple, the first one will be used.
Therefore, every `#include` containing a __module declaration should come after the file's own module declaration,
or it will be overwritten.
When you always put the __module declaration at the very top like in D, there won't be such problems.
14 changes: 14 additions & 0 deletions compiler/src/dmd/cparse.d
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,20 @@ final class CParser(AST) : Parser!AST
return wrap;
}

if (token.value == TOK._module)
{
token.value = TOK.module_;
auto oldMd = this.md;
parseModuleDeclaration();
if (oldMd)
{
// We only use the first module declaration,
// subsequent __module statements should only come from #included files
this.md = oldMd;
}
continue;
}

/* GNU Extensions
* external-declaration:
* simple-asm-expr ;
Expand Down
8 changes: 7 additions & 1 deletion compiler/src/dmd/dmodule.d
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,13 @@ extern (C++) final class Module : Package
p.nextToken();
checkCompiledImport();
members = p.parseModule();
assert(!p.md); // C doesn't have module declarations
md = p.md;
if (md)
{
this.ident = md.id;
dst = Package.resolve(md.packages, &this.parent, &ppack);
}

numlines = p.scanloc.linnum;
}
else
Expand Down
15 changes: 8 additions & 7 deletions compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -2911,13 +2911,14 @@ enum class TOK : uint8_t
_Thread_local_ = 217u,
_assert_ = 218u,
_import_ = 219u,
__cdecl_ = 220u,
__declspec_ = 221u,
__stdcall_ = 222u,
__thread_ = 223u,
__pragma_ = 224u,
__int128_ = 225u,
__attribute___ = 226u,
_module = 220u,
__cdecl_ = 221u,
__declspec_ = 222u,
__stdcall_ = 223u,
__thread_ = 224u,
__pragma_ = 225u,
__int128_ = 226u,
__attribute___ = 227u,
};

class FuncExp final : public Expression
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dmd/tokens.d
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ enum TOK : ubyte
// C only extended keywords
_assert,
_import,
_module,
__cdecl,
__declspec,
__stdcall,
Expand Down Expand Up @@ -586,6 +587,7 @@ private immutable TOK[] keywords =
// C only extended keywords
TOK._assert,
TOK._import,
TOK._module,
TOK.__cdecl,
TOK.__declspec,
TOK.__stdcall,
Expand Down Expand Up @@ -621,7 +623,7 @@ static immutable TOK[TOK.max + 1] Ckeywords =
union_, unsigned, void_, volatile, while_, asm_, typeof_,
_Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn,
_Static_assert, _Thread_local,
_import, __cdecl, __declspec, __stdcall, __thread, __pragma, __int128, __attribute__,
_import, _module, __cdecl, __declspec, __stdcall, __thread, __pragma, __int128, __attribute__,
_assert ];

foreach (kw; Ckwds)
Expand Down Expand Up @@ -901,6 +903,7 @@ extern (C++) struct Token
// C only extended keywords
TOK._assert : "__check",
TOK._import : "__import",
TOK._module : "__module",
TOK.__cdecl : "__cdecl",
TOK.__declspec : "__declspec",
TOK.__stdcall : "__stdcall",
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/tokens.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ enum class TOK : unsigned char
// C only extended keywords
_assert,
_import,
_module,
cdecl_,
declspec,
stdcall,
Expand Down
9 changes: 9 additions & 0 deletions compiler/test/compilable/cmodules.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
EXTRA_SOURCES: imports/cpkg/cmodule.c
*/

import imports.cpkg.cmodule;

static assert(sqr(3) == 9);

void main() {}
13 changes: 13 additions & 0 deletions compiler/test/compilable/imports/cpkg/cmodule.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// D module declaration

#if __IMPORTC__

__module imports.cpkg.cmodule;

// Only the first module statement is used,
// subsequent __module declarations are assumed to come from #included other files
__module some.header;

#endif

int sqr(int i) { return i * i; }
31 changes: 31 additions & 0 deletions compiler/test/fail_compilation/cmodule_malformed.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
TEST_OUTPUT:
---
fail_compilation/cmodule_malformed.c(15): Error: identifier expected following `module`
fail_compilation/cmodule_malformed.c(15): Error: no type for declarator before `"a"`
fail_compilation/cmodule_malformed.c(21): Error: no type-specifier for struct member
fail_compilation/cmodule_malformed.c(21): Error: identifier or `(` expected
fail_compilation/cmodule_malformed.c(21): Error: expected identifier for declarator
fail_compilation/cmodule_malformed.c(26): Error: found `__module` instead of statement
---
*/

#if __IMPORTC__

__module "a";

typedef struct S
{
int x;

__module b;
} S;

void main(void)
{
__module c.d;
}

__module e;

#endif

0 comments on commit f0058a1

Please sign in to comment.