Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v2.112.0-beta.1
v2.112.0
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.
1 change: 0 additions & 1 deletion compiler/src/dmd/aggregate.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ class StructDeclaration : public AggregateDeclaration
static StructDeclaration *create(Loc loc, Identifier *id, bool inObject);
StructDeclaration *syntaxCopy(Dsymbol *s) override;
const char *kind() const override;
bool isPOD();
bool zeroInit() const; // !=0 if initialize with 0 fill
bool zeroInit(bool v);
bool hasIdentityAssign() const; // true if has identity opAssign
Expand Down
53 changes: 31 additions & 22 deletions compiler/src/dmd/backend/cgcs.d
Original file line number Diff line number Diff line change
Expand Up @@ -513,31 +513,40 @@ void ecom(ref CGCS cgcs, ref elem* pe)
printf("i: %2d Hhash: %6d Helem: %p\n",
cast(int) i,hcs.Hhash,hcs.Helem);

elem* ehash;
if (hash == hcs.Hhash && (ehash = hcs.Helem) != null)
if (hash == hcs.Hhash && hcs.Helem != null)
{
/* if elems are the same and we still have room for more */
if (el_match(e,ehash) && ehash.Ecount < 0xFF)
elem* ehash = hcs.Helem;

/* Make sure leaves are already merged as common subexpressions
* before trying to merge the current node with a candidate.
* Otherwise, hash collisions can result in invalid CSE
* (i.e. if a leaf has been clobbered by assignment).
*/
if (!OTleaf(op))
{
/* Make sure leaves are also common subexpressions
* to avoid false matches.
*/
if (!OTleaf(op))
{
if (!e.E1.Ecount)
continue;
if (OTbinary(op) && !e.E2.Ecount)
continue;
}
ehash.Ecount++;
pe = ehash;

debug if (debugx)
printf("**MATCH** %p with %p\n",e,pe);

el_free(e);
return;
if (e.E1 != ehash.E1 || !e.E1.Ecount)
continue;
if (OTbinary(op) && (e.E2 != ehash.E2 || !e.E2.Ecount))
continue;
}

/* Compare parents (the entire subtrees in fact) only when
* the children are eligible, which significantly speeds up
* common subexpression matching. Also, check for overflow.
*/
if (!el_match(e, ehash) || ehash.Ecount == 0xFF)
{
continue;
}

ehash.Ecount++;
pe = ehash;

debug if (debugx)
printf("**MATCH** %p with %p\n",e,pe);

el_free(e);
return;
}
}
}
Expand Down
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
6 changes: 6 additions & 0 deletions compiler/src/dmd/cxxfrontend.d
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,12 @@ PURE isPure(FuncDeclaration fd)
return dmd.funcsem.isPure(fd);
}

bool needsClosure(FuncDeclaration fd)
{
import dmd.funcsem;
return dmd.funcsem.needsClosure(fd);
}

/***********************************************************
* hdrgen.d
*/
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dmd/declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ namespace dmd
bool checkClosure(FuncDeclaration* fd);
MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, ArgumentLabels *names);
PURE isPure(FuncDeclaration *f);
bool needsClosure(FuncDeclaration *fd);
FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0);
FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0);
bool isAbstract(ClassDeclaration *cd);
bool overloadInsert(Dsymbol *ds, Dsymbol *s);
bool equals(const Dsymbol *ds, const Dsymbol *s);
bool equals(const Dsymbol * const ds, const Dsymbol * const s);
}

//enum STC : ulong from astenums.d:
Expand Down Expand Up @@ -717,7 +718,6 @@ class FuncDeclaration : public Declaration
virtual bool addPreInvariant();
virtual bool addPostInvariant();
const char *kind() const override;
bool needsClosure();
bool hasNestedFrameRefs();
ParameterList getParameterList();

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 @@ -765,7 +765,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.linnum;
}
else
Expand Down
20 changes: 1 addition & 19 deletions compiler/src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -3432,24 +3432,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sc.stc &= ~STC.static_; // not a static constructor

funcDeclarationSemantic(sc, ctd);
// Check short constructor: this() => expr;
if (ctd.fbody)
{
if (auto s = ctd.fbody.isExpStatement())
{
if (s.exp)
{
auto ce = s.exp.isCallExp();
// check this/super before semantic
if (!ce || (!ce.e1.isThisExp() && !ce.e1.isSuperExp()))
{
s.exp = s.exp.expressionSemantic(sc);
if (s.exp.type.ty != Tvoid)
error(s.loc, "can only return void expression, `this` call or `super` call from constructor");
}
}
}
}

sc.pop();

Expand Down Expand Up @@ -8963,7 +8945,7 @@ bool isAbstract(ClassDeclaration cd)
static int virtualSemantic(Dsymbol s, void*)
{
auto fd = s.isFuncDeclaration();
if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration())
if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration() && !fd.isCtorDeclaration())
fd.dsymbolSemantic(null);
return 0;
}
Expand Down
8 changes: 6 additions & 2 deletions compiler/src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -4528,7 +4528,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
setError();
}
}
scope (exit) result.rvalue = exp.rvalue;
scope (exit)
{
if (result !is null)
result.rvalue = exp.rvalue;
}

Dsymbol scopesym;
Dsymbol s = sc.search(exp.loc, exp.ident, scopesym);
Expand Down Expand Up @@ -6620,7 +6624,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
setError();
}
else
else if (result !is null)
{
result.rvalue = true;
}
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 @@ -3169,13 +3169,14 @@ enum class TOK : uint8_t
_Thread_local_ = 216u,
_assert_ = 217u,
_import_ = 218u,
__cdecl_ = 219u,
__declspec_ = 220u,
__stdcall_ = 221u,
__thread_ = 222u,
__pragma_ = 223u,
__int128_ = 224u,
__attribute___ = 225u,
_module = 219u,
__cdecl_ = 220u,
__declspec_ = 221u,
__stdcall_ = 222u,
__thread_ = 223u,
__pragma_ = 224u,
__int128_ = 225u,
__attribute___ = 226u,
};

class FuncExp final : public Expression
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ struct CompileEnv
d_bool transitionIn;
d_bool ddocOutput;
d_bool masm;
DString switchPrefix;
IdentifierCharLookup cCharLookupTable;
IdentifierCharLookup dCharLookupTable;
};
Expand Down
5 changes: 1 addition & 4 deletions compiler/src/dmd/parse.d
Original file line number Diff line number Diff line change
Expand Up @@ -5322,10 +5322,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
error("missing `do { ... }` after `in` or `out`");
const returnloc = token.loc;
nextToken();
if (f.isCtorDeclaration)
f.fbody = new AST.ExpStatement(returnloc, parseExpression());
else
f.fbody = new AST.ReturnStatement(returnloc, parseExpression());
f.fbody = new AST.ReturnStatement(returnloc, parseExpression());
f.endloc = token.loc;
check(TOK.semicolon);
break;
Expand Down
7 changes: 5 additions & 2 deletions compiler/src/dmd/semantic3.d
Original file line number Diff line number Diff line change
Expand Up @@ -1450,6 +1450,10 @@ private extern(C++) final class Semantic3Visitor : Visitor
if (ctor.semanticRun >= PASS.semantic3)
return;

if (!ctor.fbody)
return visit(cast(FuncDeclaration)ctor);


/* If any of the fields of the aggregate have a destructor, add
* scope (failure) { this.fieldDtor(); }
* as the first statement of the constructor (unless the constructor
Expand All @@ -1460,7 +1464,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
* https://issues.dlang.org/show_bug.cgi?id=14246
*/
AggregateDeclaration ad = ctor.isMemberDecl();
if (!ctor.fbody || !ad || !ad.fieldDtor ||
if (!ad || !ad.fieldDtor ||
global.params.dtorFields == FeatureState.disabled || !global.params.useExceptions || ctor.type.toTypeFunction.isNothrow)
return visit(cast(FuncDeclaration)ctor);

Expand Down Expand Up @@ -1533,7 +1537,6 @@ private extern(C++) final class Semantic3Visitor : Visitor
visit(cast(FuncDeclaration)ctor);
}


override void visit(Nspace ns)
{
if (ns.semanticRun >= PASS.semantic3)
Expand Down
42 changes: 35 additions & 7 deletions compiler/src/dmd/statementsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -2536,16 +2536,44 @@ Statement statementSemanticVisit(Statement s, Scope* sc)

if (fd.isCtorDeclaration())
{
if (rs.exp)
// Constructors implicitly do:
// return this;
auto ctorReturn = new ThisExp(Loc.initial);
ctorReturn.type = tret;

bool isConstructorCall(Expression e)
{
error(rs.loc, "cannot return expression from constructor");
errors = true;
auto ce = e.isCallExp();
if (!ce)
return false;

auto dve = ce.e1.isDotVarExp();
if (!dve)
return false;

return dve.var.isThis !is null;
}

// Constructors implicitly do:
// return this;
rs.exp = new ThisExp(Loc.initial);
rs.exp.type = tret;
if (rs.exp)
{
rs.exp = rs.exp.expressionSemantic(sc);

if (rs.exp.type.ty != Tvoid && !isConstructorCall(rs.exp))
{

error(rs.loc, "can only return void expression, `this` call or `super` call from constructor");
errors = true;
rs.exp = ErrorExp.get();
}
else
{
rs.exp = new CommaExp(rs.loc, rs.exp, ctorReturn).expressionSemantic(sc);
}
}
else
{
rs.exp = ctorReturn;
}
}
else if (rs.exp)
{
Expand Down
Loading
Loading