Skip to content

Commit 69fb77b

Browse files
committed
Only compile unittests in root modules
1 parent 44d849e commit 69fb77b

File tree

12 files changed

+133
-62
lines changed

12 files changed

+133
-62
lines changed

src/dmd/astbase.d

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,6 +1441,21 @@ struct ASTBase
14411441
srcfile = new File(srcfilename);
14421442
}
14431443

1444+
/**
1445+
A root module is one that will be compiled to object code.
1446+
*/
1447+
final bool isRoot() const
1448+
{
1449+
return true;
1450+
}
1451+
1452+
/**
1453+
Called by the parser after the module declaration has been determined.
1454+
*/
1455+
final void afterModuleDeclaration(ModuleDeclaration* md)
1456+
{
1457+
}
1458+
14441459
override void accept(Visitor v)
14451460
{
14461461
v.visit(this);

src/dmd/dmodule.d

Lines changed: 33 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,10 @@ extern (C++) final class Module : Package
292292
extern (C++) static __gshared Dsymbols deferred3; // deferred Dsymbol's needing semantic3() run on them
293293
extern (C++) static __gshared uint dprogress; // progress resolving the deferred list
294294
/**
295-
* A callback function that is called once an imported module is
296-
* parsed. If the callback returns true, then it tells the
297-
* frontend that the driver intends on compiling the import.
298-
*/
295+
A callback function that is called when a module is loaded as soon as its
296+
module declaration has been parsed. If the callback returns true, then it tells the
297+
frontend that the driver intends on compiling the import.
298+
*/
299299
extern (C++) static __gshared bool function(Module mod) onImport;
300300

301301
static void _init()
@@ -370,12 +370,10 @@ extern (C++) final class Module : Package
370370
int searchCacheFlags; // cached flags
371371

372372
/**
373-
* A root module is one that will be compiled all the way to
374-
* object code. This field holds the root module that caused
375-
* this module to be loaded. If this module is a root module,
376-
* then it will be set to `this`. This is used to determine
377-
* ownership of template instantiation.
378-
*/
373+
This field holds the root module that caused this module
374+
to be loaded. If this module is a root module, then it will
375+
be set to `this`.
376+
*/
379377
Module importedFrom;
380378

381379
Dsymbols* decldefs; // top level declarations for this Module
@@ -515,41 +513,6 @@ extern (C++) final class Module : Package
515513
message("import %s", buf.peekString());
516514
}
517515
m = m.parse();
518-
519-
// Call onImport here because if the module is going to be compiled then we
520-
// need to determine it early because it affects semantic analysis. This is
521-
// being done after parsing the module so the full module name can be taken
522-
// from whatever was declared in the file.
523-
524-
//!!!!!!!!!!!!!!!!!!!!!!!
525-
// Workaround for bug in dmd version 2.068.2 platform Darwin_64_32.
526-
// This is the compiler version that the autotester uses, and this code
527-
// has been carefully crafted using trial and error to prevent a seg fault
528-
// bug that occurs with that version of the compiler. Note, this segfault
529-
// does not occur on the next version of dmd, namely, version 2.069.0. If
530-
// the autotester upgrades to that version, then this workaround can be removed.
531-
//!!!!!!!!!!!!!!!!!!!!!!!
532-
version(OSX)
533-
{
534-
if (!m.isRoot() && onImport)
535-
{
536-
auto onImportResult = onImport(m);
537-
if(onImportResult)
538-
{
539-
m.importedFrom = m;
540-
assert(m.isRoot());
541-
}
542-
}
543-
}
544-
else
545-
{
546-
if (!m.isRoot() && onImport && onImport(m))
547-
{
548-
m.importedFrom = m;
549-
assert(m.isRoot());
550-
}
551-
}
552-
553516
Target.loadModule(m);
554517
return m;
555518
}
@@ -853,7 +816,6 @@ extern (C++) final class Module : Package
853816
scope p = new Parser!ASTCodegen(this, buf[0 .. buflen], docfile !is null);
854817
p.nextToken();
855818
members = p.parseModule();
856-
md = p.md;
857819
numlines = p.scanloc.linnum;
858820
if (p.errors)
859821
++global.errors;
@@ -1288,11 +1250,35 @@ extern (C++) final class Module : Package
12881250
return false;
12891251
}
12901252

1291-
bool isRoot()
1253+
/**
1254+
A root module is one that will be compiled to object code. This is used to
1255+
determine ownership of template instantiation and when to compile unittests.
1256+
Returns:
1257+
true if this is a root module
1258+
*/
1259+
final bool isRoot() const
12921260
{
12931261
return this.importedFrom == this;
12941262
}
12951263

1264+
/**
1265+
Called by the parser after the module declaration has been determined.
1266+
*/
1267+
final void afterModuleDeclaration(ModuleDeclaration* md)
1268+
{
1269+
this.md = md;
1270+
1271+
// Call onImport here because if the module is going to be compiled then we
1272+
// need to determine it early because it affects whether unittests will be parsed
1273+
// and semantic analysis. This is being done right after parsing the module delclaration
1274+
// so the full module name can be taken from whatever was declared in the file.
1275+
if (!isRoot() && onImport && onImport(this))
1276+
{
1277+
importedFrom = this;
1278+
assert(isRoot());
1279+
}
1280+
}
1281+
12961282
// true if the module source file is directly
12971283
// listed in command line.
12981284
bool isCoreModule(Identifier ident)

src/dmd/dtemplate.d

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6360,8 +6360,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
63606360
* is behind a conditional debug declaration.
63616361
*/
63626362
// workaround for https://issues.dlang.org/show_bug.cgi?id=11239
6363-
if (global.params.useUnitTests ||
6364-
global.params.debuglevel)
6363+
if (global.params.debuglevel)
63656364
{
63666365
// Prefer instantiations from root modules, to maximize link-ability.
63676366
if (minst.isRoot())
@@ -7354,7 +7353,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
73547353
{
73557354
Module mi = minst; // instantiated . inserted module
73567355

7357-
if (global.params.useUnitTests || global.params.debuglevel)
7356+
if (global.params.debuglevel)
73587357
{
73597358
// Turn all non-root instances to speculative
73607359
if (mi && !mi.isRoot())

src/dmd/glue.d

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -752,8 +752,17 @@ void FuncDeclaration_toObjFile(FuncDeclaration fd, bool multiobj)
752752
if (!fd.fbody)
753753
return;
754754

755+
// Find module m for this function
756+
Module m = null;
757+
for (Dsymbol p = fd.parent; p; p = p.parent)
758+
{
759+
m = p.isModule();
760+
if (m)
761+
break;
762+
}
763+
755764
UnitTestDeclaration ud = fd.isUnitTestDeclaration();
756-
if (ud && !global.params.useUnitTests)
765+
if (ud && (!global.params.useUnitTests || !m.isRoot))
757766
return;
758767

759768
if (multiobj && !fd.isStaticDtorDeclaration() && !fd.isStaticCtorDeclaration())
@@ -886,15 +895,6 @@ void FuncDeclaration_toObjFile(FuncDeclaration fd, bool multiobj)
886895
symtab_t *symtabsave = cstate.CSpsymtab;
887896
cstate.CSpsymtab = &f.Flocsym;
888897

889-
// Find module m for this function
890-
Module m = null;
891-
for (Dsymbol p = fd.parent; p; p = p.parent)
892-
{
893-
m = p.isModule();
894-
if (m)
895-
break;
896-
}
897-
898898
Dsymbols deferToObj; // write these to OBJ file later
899899
Array!(elem*) varsInScope;
900900
Label*[void*] labels = null;

src/dmd/module.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ class Module : public Package
144144
static void clearCache();
145145
int imports(Module *m);
146146

147-
bool isRoot() { return this->importedFrom == this; }
147+
bool isRoot() const { return this->importedFrom == this; }
148148
// true if the module source file is directly
149149
// listed in command line.
150150
bool isCoreModule(Identifier *ident);

src/dmd/parse.d

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,8 @@ final class Parser(AST) : Lexer
377377
}
378378
}
379379

380+
mod.afterModuleDeclaration(md);
381+
380382
decldefs = parseDeclDefs(0, &lastDecl);
381383
if (token.value != TOK.endOfFile)
382384
{
@@ -547,7 +549,7 @@ final class Parser(AST) : Lexer
547549
break;
548550
}
549551
case TOK.unittest_:
550-
if (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration)
552+
if ( (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration) && mod.isRoot)
551553
{
552554
s = parseUnitTest(pAttrs);
553555
if (*pLastDecl)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env bash
2+
3+
if [ "$2" == "HAS" ]; then
4+
GREP_OPTION=
5+
elif [ "$2" == "DOES_NOT_HAVE" ]; then
6+
GREP_OPTION=-v
7+
else
8+
echo Unknown option "$2"
9+
exit 1
10+
fi
11+
12+
if [ ${OS} != "linux" ]; then
13+
echo Skipping checkbin $2 $3 because os $OS is not linux
14+
exit 0
15+
fi
16+
17+
objdump -t "$1" | grep -q $GREP_OPTION "$3"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module printVersionUnittest;
2+
3+
version(unittest)
4+
{
5+
pragma(msg, "version unittest");
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module printingUnittest;
2+
3+
unittest
4+
{
5+
import core.stdc.stdio;
6+
printf("unittesting printingUnittest\n");
7+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import printingUnittest;
2+
void main()
3+
{
4+
// have to print something so grep works
5+
import core.stdc.stdio; printf("done\n");
6+
}

0 commit comments

Comments
 (0)