Skip to content

Commit

Permalink
Fix Issue 8687 - Variadic templates do not work properly with default…
Browse files Browse the repository at this point in the history
… arguments
  • Loading branch information
timotheecour committed Feb 3, 2018
1 parent 15c8da1 commit 36af6b1
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 2 deletions.
17 changes: 17 additions & 0 deletions changelog/default_after_variadic.dd
@@ -0,0 +1,17 @@
Function parameters with default values are now allowed after variadic template parameters, and always take their default values. This allows using special tokens (eg __FILE__) after variadic parameters, which was previously impossible

Eg:
---
string log(T...)(T a, string file = __FILE__, int line = __LINE__)
{
return text(file, ":", line, " ", a);
}

assert(log(10, "abc") == text(__FILE__, ":", __LINE__, " 10abc"));
---

This should be preferred to the previous workaround, which caused template bloat:
---
string log(string file = __FILE__, int line = __LINE__, T...)(T a);
---

8 changes: 6 additions & 2 deletions src/dmd/dtemplate.d
Expand Up @@ -1342,13 +1342,17 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
declaredTuple = new Tuple();
(*dedargs)[parameters.dim - 1] = declaredTuple;

/* Count function parameters following a tuple parameter.
* void foo(U, T...)(int y, T, U, int) {} // rem == 2 (U, int)
/* Count function parameters with no defaults following a tuple parameter.
* void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double)
*/
size_t rem = 0;
for (size_t j = parami + 1; j < nfparams; j++)
{
Parameter p = Parameter.getNth(fparameters, j);
if(p.defaultArg)
{
break;
}
if (!reliesOnTident(p.type, parameters, inferStart))
{
Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope);
Expand Down
62 changes: 62 additions & 0 deletions test/runnable/testdefault_after_variadic.d
@@ -0,0 +1,62 @@
/*
PERMUTE_ARGS:
*/

import std.typecons : tuple;
import std.conv : text;

void fun0(U, T...)(U gold, int b_gold, T a, int b)
{
assert(tuple(a) == gold);
assert(b == b_gold);
}

void fun(U, T...)(U gold, T a, int b = 1)
{
assert(tuple(a) == gold);
assert(b == 1);
}

void fun2(U, V, T...)(U gold, V gold2, T a, string file = __FILE__, int line = __LINE__)
{
assert(tuple(a) == gold);
assert(tuple(file, line) == gold2);
}

//
void fun3(int[] gold, int[] a...)
{
assert(gold == a);
}

/+
NOTE: this is disallowed by the parser:
void fun4(int[] gold, int[] a ..., int b = 1)
{
assert(gold==a);
assert(b==1);
}
+/

// Example in changelog
string log(T...)(T a, string file = __FILE__, int line = __LINE__)
{
return text(file, ":", line, " ", a);
}

void main()
{
fun0(tuple(10), 7, 10, 7);

fun(tuple());
fun(tuple(10), 10);
fun(tuple(10, 11), 10, 11);

fun2(tuple(10), tuple(__FILE__, __LINE__), 10);

fun3([1, 2, 3], 1, 2, 3);
// fun4([1,2,3], 1,2,3);

assert(log(10, "abc") == text(__FILE__, ":", __LINE__, " 10abc"));
}

0 comments on commit 36af6b1

Please sign in to comment.