Issue 14901 - [reg 2.067/2.068] template static shared this() run multiple times with separate compilation
Summary: [reg 2.067/2.068] template static shared this() run multiple times with separ...
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P1 regression
Assignee: No Owner
URL:
Keywords: pull, wrong-code
Depends on:
Blocks:
 
Reported: 2015-08-10 18:18 UTC by David Nadlinger
Modified: 2015-09-02 04:10 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description David Nadlinger 2015-08-10 18:18:15 UTC
Consider the following test case (zip attached for your convenience):

---
module a;

extern(C) int printf(const char*, ...);

int make(string s)() {
	__gshared static int value;
	struct WithCtor {
		shared static this() {
			printf("%s\n", s.ptr);
		}
	}
	return value;
}
---
module b;

import a;

alias bar = make!"bar";

struct User(int id) {
	int foo() {
		return bar;
	}
}
---
module c;

import b;

// This causes the id that is part of the generated name to be different.
shared static this() {}

void caller1() {
	User!1 u;
}
---
module d;

import b;

void caller2() {
	User!2 u;
}
---
module e;

import c;
import d;

void main() {
	caller1();
	caller2();
}
---

When compiled separately and with -unittest (e.g. using 'find *.d | xargs -n1 dmd -c -unittest' and then linking), it will print "bar" twice. This was likely introduced in 2.067 (could not reproduce in 2.066), and still affects 2.068.

As far as the cause for this goes, for reasons I'm not entirely clear about a unique identifier is used for function name of the static ctor (e.g. _sharedStaticCtor55). For (amongst others) -unittest builds, the ctor function is always emitted to fix issue 11239. Thus, different object files end up with differently named copies of the same function, which consequently also gets run multiple times.

Because the function name is also a part of the symbol name for the gate boolean, the latter does not help with resolving this issue.
Comment 1 Kenji Hara 2015-08-11 02:53:51 UTC
The bug behavior has introduced by the excessive instantiation and codegen for the non-root instances. From 2.067, the make!"bar" instance code which aliased in b.d will be instantiated and stored into [bcde].obj. With 2.066 and earlier, it had stored only into b.obj.

Those regressions have the same root:

Issue 14431 - [REG 2.067.0] huge slowdown of compilation speed
Issue 14508 - [REG2.067.0] compiling with -unittest instantiates templates in non-root modules
Issue 14564 - [REG2.067] dmd -property -unittest combination causes compiler error

and it will be fixed by:

https://github.com/D-Programming-Language/dmd/pull/4784

But unfortunately, my PR is not released into 2.068.0, because Walter couldn't understand the fix.
David, I wish to you to join its code review, if you have a time.

----

> As far as the cause for this goes, for reasons I'm not entirely clear about a unique identifier is used for function name of the static ctor (e.g. _sharedStaticCtor55). For (amongst others) -unittest builds, the ctor function is always emitted to fix issue 11239. Thus, different object files end up with differently named copies of the same function, which consequently also gets run multiple times.

That's an another, fragile naming mechanism issue in current dmd front-end. Some unnamed symbols (static this, unittest, anonymous class, etc) are numbered by the `Identifier::generateId()`. It's result not *stable* because it fully depends on the order of semantic analysis and it will be changed by the conditional compilation.

For lambdas and unnamed mixin declarations, I added "scope local unique number" (See FuncExp::genIdent and TemplateMixin::semantic).
For them, the frequency of the issue has been reduced by them, but it's not yet perfect answer...
Comment 2 Walter Bright 2015-08-11 09:43:08 UTC
The cause of this is not excessive instantiation, it is the fragile name generation system.
Comment 3 Kenji Hara 2015-08-11 11:14:13 UTC
(In reply to Walter Bright from comment #2)
> The cause of this is not excessive instantiation, it is the fragile name
> generation system.

Yes, the ultimate root issue is it. But if the code for the instance make!"bar" is generated and stored only in b.obj, the problem does not happen.

So, the regression from 2.067 is introduced by the excessive instantiation. The issue should be fixed ASAP.
Comment 4 Steven Schveighoffer 2015-08-11 12:56:34 UTC
Does this have any bearing/relation to https://issues.dlang.org/show_bug.cgi?id=14517 ?
Comment 5 Kenji Hara 2015-08-11 14:11:47 UTC
(In reply to Steven Schveighoffer from comment #4)
> Does this have any bearing/relation to
> https://issues.dlang.org/show_bug.cgi?id=14517 ?

Unfortunately, it is not related with.
Comment 6 github-bugzilla 2015-08-30 19:18:37 UTC
Commit pushed to stable at https://github.com/D-Programming-Language/dmd

https://github.com/D-Programming-Language/dmd/commit/5b464f3393980a0229c079ff6e646ef843681996
fix Issue 14901 - template static shared this() run multiple times with separate compilation
Comment 7 github-bugzilla 2015-09-02 04:10:14 UTC
Commit pushed to master at https://github.com/D-Programming-Language/dmd

https://github.com/D-Programming-Language/dmd/commit/5b464f3393980a0229c079ff6e646ef843681996
fix Issue 14901 - template static shared this() run multiple times with separate compilation