Code:
------
void one(T)(T t, size_t ln = 0)
{
pragma(msg, "one: ", T.stringof);
two(t);
}
void two(T)(T t)
{
pragma(msg, "two: ", T.stringof);
}
enum Seq(T...) = 0;
alias Bug = Seq!(void delegate());
void main()
{
void func() @system { __gshared int x; ++x; throw new Exception(""); }
one(&func);
}
------
Compiler command:
------
dmd -o- -c test.d
------
Compiler output:
------
one: void delegate() @system
two: void delegate()
------
Note the lack of @system on the second line. Any of the following will cause @system to appear on the second line:
- Removing the default parameter `ln` from the template function `one`.
- Commenting out the `alias Bug` line.
- Adding a default parameter `size_t ln = 0` to the template function `two`.
Curiously, if the default parameter `ln` is *moved* from `one` to `two`, the output becomes:
-------
one: void delegate()
two: void delegate()
-------
which is even more strange, since the output now has *neither* @safe nor @system.
Expected behaviour:
The output should at least be consistent, and certainly should not change depending on whether the `alias Bug` line is there or not, since it has absolutely nothing to do with the templates `one` and `two`.
Reduced further:
-----------
void one(T)(T t, size_t ln = 0)
{
pragma(msg, "one: ", T.stringof);
two(t);
}
void two(T)(T t)
{
pragma(msg, "two: ", T.stringof);
}
alias T = void delegate();
void main()
{
void func() @system { __gshared int x; ++x; throw new Exception(""); }
one(&func);
}
-----------
Commenting out the `alias T` line makes the problem go away.
Current investigation seems to be pointing to an ambiguity in the string table. Still investigating further to narrow the problem down further.
Comment #3 by schveiguy — 2020-01-13T19:38:56Z
Is this literally just the string representation of a delegate type that is wrong? I mean, I tried this out on the latest compiler, and trying to *call* t in `two` and trying to apply a @safe tag to it makes it fail to compile.
Comment #4 by snarwin+bugzilla — 2020-06-19T14:07:17Z
(In reply to Steven Schveighoffer from comment #3)
> Is this literally just the string representation of a delegate type that is
> wrong? I mean, I tried this out on the latest compiler, and trying to *call*
> t in `two` and trying to apply a @safe tag to it makes it fail to compile.
Looks like just the string representation is wrong. Not the end of the world, but there *is* a unittest in std.format that checks for the string representation, and this bug is causing failures completely unrelated to the PR, and it's rather frustrating.
Comment #7 by boris2.9 — 2020-08-14T06:27:20Z
I checked the issue a few months ago, this is what I recall.
The problem here is that both 'void delegate()' and 'void delegate() @system' are mangled in the same way because @system isn't coded in the mangle system (it's the same as a function without attributes), so the types are identical to any compiler comparison and that includes template instantiation.
Whatever is seen first by the compiler then it's inserted to the type table and that is the type used by any function templates.
Second, there's a special code path in the presence of default arguments that just passes the original argument to the template, here is 'func' with the @system flag enabled, not the one in the type table (alias T = void delegate()), this peculiarity is orthogonal to the main issue.
Possible solutions are:
1. Integrate @system attribute in the mangle system.
2. That .stringof just print the naked functions (no attributes) with @system.
3. or better, save the type of these functions in the type table with the @system flag enabled (or @safe in the hypothetical case of safe by default).
2 and 3 mean the compiler should now interpret ("no attributes" == @system)
Comment #8 by hsteoh — 2020-08-14T14:45:51Z
Solution 3 sounds like the best solution.
Comment #9 by robert.schadek — 2024-12-13T18:56:14Z