From a578ab9ff9b5a3b475de603374c8213146be9946 Mon Sep 17 00:00:00 2001 From: usefahmed07 Date: Wed, 26 Aug 2026 14:49:33 +0300 Subject: [PATCH 1/4] Fix issue 19718 - check function safety attributes during template deduction When deducing a template parameter T from a function-literal argument against a declared parameter type like `T function(ref S) @safe` or `T delegate(ref S) @safe`, deduceType's TypeFunction visitor only checked varargs, linkage, and per-parameter covariance. It never checked that the argument's own function attributes (in particular @safe/@system) satisfy what the parameter type requires. As a result, an @system function literal could be wrongly deduced as an exact match against an @safe parameter type, and when this happened for two overloads simultaneously (function pointer vs delegate), the compiler reported a confusing 'matches multiple overloads' ambiguity error instead of the real 'no overload is callable' safety error. This adds a trust (safety) compatibility check right after the existing varargs/linkage check, mirroring the same trust-covariance rule already used elsewhere in the compiler (Type.covariant). https://github.com/dlang/dmd/issues/19718 --- compiler/src/dmd/templatesem.d | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/compiler/src/dmd/templatesem.d b/compiler/src/dmd/templatesem.d index 48f1be0519a0..237b597c478f 100644 --- a/compiler/src/dmd/templatesem.d +++ b/compiler/src/dmd/templatesem.d @@ -7183,6 +7183,19 @@ MATCH deduceType(scope RootObject o, scope Scope* sc, scope Type tparam, return; } + // https://github.com/dlang/dmd/issues/19718 + // The argument's safety must satisfy what the parameter type requires; + // an @system (or unmarked) function/delegate cannot match an @safe or + // @trusted parameter type. Without this check, template argument + // deduction only compares parameter lists and ignores the function's + // own attributes, so an unsafe argument can be wrongly deduced to + // match an @safe (or stronger) parameter type. + if (t.trust <= TRUST.system && tp.trust >= TRUST.trusted) + { + result = MATCH.nomatch; + return; + } + foreach (fparam; *tp.parameterList.parameters) { // https://issues.dlang.org/show_bug.cgi?id=2579 From 11d583ffb88a462f1fedadc19556a2636e46e4de Mon Sep 17 00:00:00 2001 From: usefahmed07 Date: Wed, 26 Aug 2026 14:58:43 +0300 Subject: [PATCH 2/4] Add regression test for issue 19718 --- compiler/test/fail_compilation/test19718.d | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 compiler/test/fail_compilation/test19718.d diff --git a/compiler/test/fail_compilation/test19718.d b/compiler/test/fail_compilation/test19718.d new file mode 100644 index 000000000000..e7f18854ea6e --- /dev/null +++ b/compiler/test/fail_compilation/test19718.d @@ -0,0 +1,30 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test19718.d(29): Error: none of the overloads of template `test19718.execute` are callable using argument types `!()(int function(ref Struct rng) @system)` +fail_compilation/test19718.d(15): Candidates are: `execute(T)(T function(ref Struct) @safe dg)` +fail_compilation/test19718.d(21): `execute(T)(T delegate(ref Struct) @safe dg)` +--- +*/ + +struct Struct +{ + int get() { return 1; } +} + +public T execute (T)(T function(ref Struct) @safe dg) +{ + Struct rng; + return dg(rng); +} + +public T execute (T)(T delegate(ref Struct) @safe dg) +{ + Struct rng; + return dg(rng); +} + +void main (string[] args) +{ + execute((ref Struct rng) { return rng.get(); }); +} From 8e44852fb5f20bca196d1bb01a5f2805ad069bf6 Mon Sep 17 00:00:00 2001 From: usefahmed07 Date: Wed, 26 Aug 2026 15:00:42 +0300 Subject: [PATCH 3/4] Simplify regression test for issue 19718 (remove main) --- compiler/test/fail_compilation/test19718.d | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/test/fail_compilation/test19718.d b/compiler/test/fail_compilation/test19718.d index e7f18854ea6e..413f53d86911 100644 --- a/compiler/test/fail_compilation/test19718.d +++ b/compiler/test/fail_compilation/test19718.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/test19718.d(29): Error: none of the overloads of template `test19718.execute` are callable using argument types `!()(int function(ref Struct rng) @system)` +fail_compilation/test19718.d(27): Error: none of the overloads of template `test19718.execute` are callable using argument types `!()(int function(ref Struct rng) @system)` fail_compilation/test19718.d(15): Candidates are: `execute(T)(T function(ref Struct) @safe dg)` fail_compilation/test19718.d(21): `execute(T)(T delegate(ref Struct) @safe dg)` --- @@ -24,7 +24,4 @@ public T execute (T)(T delegate(ref Struct) @safe dg) return dg(rng); } -void main (string[] args) -{ - execute((ref Struct rng) { return rng.get(); }); -} +auto x = execute((ref Struct rng) { return rng.get(); }); From 0c48143db52cb6a910106565747b8f423d719c7b Mon Sep 17 00:00:00 2001 From: usefahmed07 Date: Wed, 26 Aug 2026 16:55:36 +0300 Subject: [PATCH 4/4] ci: rerun CI