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
6 changes: 0 additions & 6 deletions src/dmd/dmodule.d
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,6 @@ extern (C++) final class Module : Package
int isDocFile; // if it is a documentation input file, not D source
bool isPackageFile; // if it is a package.d
int needmoduleinfo;
/**
How many unit tests have been seen so far in this module. Makes it so the
unit test name is reproducible regardless of whether it's compiled
separately or all at once.
*/
uint unitTestCounter; // how many unittests have been seen so far
int selfimports; // 0: don't know, 1: does not, 2: does

/*************************************
Expand Down
6 changes: 0 additions & 6 deletions src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -3598,12 +3598,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor

override void visit(UnitTestDeclaration utd)
{
// The identifier has to be generated here in order for it to be possible
// to link regardless of whether the files were compiled separately
// or all at once. See:
// https://issues.dlang.org/show_bug.cgi?id=16995
utd.setIdentifier();

if (utd.semanticRun >= PASS.semanticdone)
return;
if (utd._scope)
Expand Down
48 changes: 3 additions & 45 deletions src/dmd/func.d
Original file line number Diff line number Diff line change
Expand Up @@ -3462,10 +3462,7 @@ extern (C++) final class UnitTestDeclaration : FuncDeclaration

extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc)
{
// Id.empty can cause certain things to fail, so we create a
// temporary one here that serves for most purposes with
// createIdentifier. There is no scope to pass so we pass null.
super(loc, endloc, createIdentifier(loc, null), stc, null);
super(loc, endloc, createIdentifier(loc), stc, null);
this.codedoc = codedoc;
}

Expand All @@ -3476,56 +3473,17 @@ extern (C++) final class UnitTestDeclaration : FuncDeclaration
return FuncDeclaration.syntaxCopy(utd);
}

/**
Sets the "real" identifier, replacing the one created in the contructor.
The reason for this is that the "real" identifier can only be generated
properly in the semantic pass. See:
https://issues.dlang.org/show_bug.cgi?id=16995
*/
final void setIdentifier()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this added to headers also?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I grepped and didn't find it anywhere.

{
ident = createIdentifier(loc, _scope);
}

/***********************************************************
* Generate unique unittest function Id so we can have multiple
* instances per module.
*/
private static Identifier createIdentifier(const ref Loc loc, Scope* sc)
private static Identifier createIdentifier(const ref Loc loc)
{
OutBuffer buf;
writeModuleNameOrFileName(buf, loc, sc);
buf.prependstring("__unittest_");
const index = sc ? sc._module.unitTestCounter++ : 0;
buf.printf("_%u_%d", loc.linnum, index);

// replace characters that demangle can't handle
auto str = buf.peekString;
for(int i = 0; str[i] != 0; ++i)
if(str[i] == '/' || str[i] == '\\' || str[i] == '.') str[i] = '_';

buf.printf("__unittest_L%u_C%u", loc.linnum, loc.charnum);
return Identifier.idPool(buf.peekSlice());
}

/*************************************************************************
* Writes a module name to name a unittest. Tries to use the fully
* qualified name if possible to avoid mismatches when compiling separately.
* Otherwise uses the file name.
* Params:
* buf = The buffer to write to.
* loc = The location of the unit test declaration.
* scope = The scope of the unit test declaration.
*/
private static void writeModuleNameOrFileName(ref OutBuffer buf, const ref Loc loc, Scope* scope_)
{
if (scope_ is null || scope_._module is null || scope_._module.ident is null)
{
buf.writestring(loc.filename);
return;
}
scope_._module.fullyQualifiedName(buf);
}

override AggregateDeclaration isThis()
{
return null;
Expand Down
6 changes: 0 additions & 6 deletions src/dmd/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,6 @@ class Module : public Package
int isDocFile; // if it is a documentation input file, not D source
bool isPackageFile; // if it is a package.d
int needmoduleinfo;
/**
How many unit tests have been seen so far in this module. Makes it so the
unit test name is reproducible regardless of whether it's compiled
separately or all at once.
*/
unsigned unitTestCounter;
int selfimports; // 0: don't know, 1: does not, 2: does
bool selfImports(); // returns true if module imports itself

Expand Down
5 changes: 0 additions & 5 deletions test/compilable/imports/module_with_tests.d

This file was deleted.

13 changes: 0 additions & 13 deletions test/compilable/issue16995.d

This file was deleted.

12 changes: 12 additions & 0 deletions test/compilable/issue18097.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// REQUIRED_ARGS: -unittest
module issue18097;

unittest // this first unittest is needed to trigger the bug
{
}

unittest // second unittest
{
auto a = &mixin(__traits(identifier, __traits(parent, { })));
auto b = &__traits(parent, { });
}
8 changes: 4 additions & 4 deletions test/fail_compilation/fail7848.d
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail7848.d(35): Error: `pure` function `fail7848.C.__unittest_fail7848_33_0` cannot call impure function `fail7848.func`
fail_compilation/fail7848.d(35): Error: `@safe` function `fail7848.C.__unittest_fail7848_33_0` cannot call `@system` function `fail7848.func`
fail_compilation/fail7848.d(35): Error: `@nogc` function `fail7848.C.__unittest_fail7848_33_0` cannot call non-@nogc function `fail7848.func`
fail_compilation/fail7848.d(35): Error: `pure` function `fail7848.C.__unittest_L33_C30` cannot call impure function `fail7848.func`
fail_compilation/fail7848.d(35): Error: `@safe` function `fail7848.C.__unittest_L33_C30` cannot call `@system` function `fail7848.func`
fail_compilation/fail7848.d(35): Error: `@nogc` function `fail7848.C.__unittest_L33_C30` cannot call non-@nogc function `fail7848.func`
fail_compilation/fail7848.d(35): Error: function `fail7848.func` is not `nothrow`
fail_compilation/fail7848.d(33): Error: `nothrow` function `fail7848.C.__unittest_fail7848_33_0` may throw
fail_compilation/fail7848.d(33): Error: `nothrow` function `fail7848.C.__unittest_L33_C30` may throw
fail_compilation/fail7848.d(40): Error: `pure` function `fail7848.C.__invariant1` cannot call impure function `fail7848.func`
fail_compilation/fail7848.d(40): Error: `@safe` function `fail7848.C.__invariant1` cannot call `@system` function `fail7848.func`
fail_compilation/fail7848.d(40): Error: `@nogc` function `fail7848.C.__invariant1` cannot call non-@nogc function `fail7848.func`
Expand Down
2 changes: 1 addition & 1 deletion test/fail_compilation/ice14424.d
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/ice14424.d(12): Error: `tuple(__unittest_imports_a14424_3_0)` has no effect
fail_compilation/ice14424.d(12): Error: `tuple(__unittest_L3_C1)` has no effect
---
*/

Expand Down
1 change: 1 addition & 0 deletions test/runnable/imports/module_with_tests.d
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
unittest {} unittest { assert(false); }
28 changes: 28 additions & 0 deletions test/runnable/issue16995.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// REQUIRED_ARGS: -unittest
// COMPILE_SEPARATELY
// EXTRA_SOURCES: imports/module_with_tests.d

import imports.module_with_tests;
import core.exception: AssertError;

shared static this()
{
import core.runtime: Runtime, UnitTestResult;
Runtime.extendedModuleUnitTester = () => UnitTestResult.pass;
}

void main()
{
import module_with_tests;
foreach(i, ut; __traits(getUnitTests, module_with_tests)) {
try
{
ut();
assert(i == 0, "2nd unittest should fail");
}
catch(AssertError e)
{
assert(i == 1, "Only 2nd unittest should fail");
}
}
}