4652 – Compiler hangs on template with zero-length tuple and another argument

D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 4652 - Compiler hangs on template with zero-length tuple and another argument
Summary: Compiler hangs on template with zero-length tuple and another argument
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: Other Windows
: P2 normal
Assignee: No Owner
URL:
Keywords: ice-on-valid-code, patch
Depends on:
Blocks:
Reported: 2010年08月15日 20:29 UTC by David Simcha
Modified: 2015年06月09日 05:10 UTC (History)
2 users (show)

See Also:


Attachments
Add an attachment (proposed patch, testcase, etc.)

Note You need to log in before you can comment on or make changes to this issue.
Description David Simcha 2010年08月15日 20:29:17 UTC
The following code simply hangs DMD 2.048. I haven't the slightest clue why.
struct Foo(Args...) if(Args.length > 1)
{
 Args args;
}
template Foo(Arg)
{
 alias Arg Foo;
}
Foo!(Args) getFoo(Args...)(Args args)
{
 static if(Args.length > 1)
 {
 return Foo!(Args)(args);
 }
 else
 {
 return args[0];
 }
}
Foo!(Args) getFoo(Args...)(Args args, uint num)
{
 static if(Args.length > 1)
 {
 return Foo!(Args)(args);
 }
 else
 {
 return args[0];
 }
}
void main()
{
 getFoo(1);
}
Comment 1 Don 2010年08月16日 00:00:43 UTC
Bug exists in 2.020. Not a regression.
Comment 2 Don 2010年08月16日 02:49:01 UTC
Reduced test case.
-------
void bug4652(T...)(T x, int n){}
void instantiate4652()
{
 bug4652(1);
}
Comment 3 Don 2010年08月16日 02:53:24 UTC
And it fails on D1, as well (as far back as D1.028).
Comment 4 Don 2010年08月18日 06:37:38 UTC
This is caused by a confusion in the code for deduceFunctionTemplateMatch.
The comment and loop condition implies that we're looping over the function
_parameters_. But the rest of the loop assumes it's a loop over the function _arguments_.
In the case where the tuple is of length zero, an infinite loop results.
Apart from the ICE, this also causes valid code to be rejected. 
------
void bug4652(U, T...)(long y, T x, U num){}
void instantiate4652()
{
 bug4652(2, 'c', 27, 'e', 'f',1); // rejects-valid
 bug4652(2, 1); // infinite loop on valid code
}
----
PATCH: template.c line 1090. Replace the first section of code, with the second.
---------------
 // Loop through the function parameters
 for (i = 0; i < nfparams; i++)
 {
 /* Skip over function parameters which wound up
 * as part of a template tuple parameter.
 */
 if (i == fptupindex)
 { if (fptupindex == nfparams - 1)
 break;
 i += tuple_dim - 1;
 continue;
 }
 Parameter *fparam = Parameter::getNth(fparameters, i);
---------------
 // Loop through the function arguments
 for (i = 0; i < nfargs; i++)
 {
 /* Skip over function parameters which wound up
 * as part of a template tuple parameter.
 */
 if (i >= fptupindex && i< fptupindex+tuple_dim)
 continue;
 /* Function parameters correspond to function arguments as follows.
 * Note that tuple_dim may be zero.
 * arg [0..fptupindex] == param[0..fptupindex]
 * arg [fptupindex..fptupindex+tuple_dim] == param[fptupindex]
 * arg[fputupindex+dim..nfargs] == param[fptupindex+1..nfparams]
 */
 size_t parami = i;
 if (fptupindex >= 0 && i >= fptupindex) {
 parami -= tuple_dim-1;
 }
 Parameter *fparam = Parameter::getNth(fparameters, parami);
--------
Comment 5 Don 2010年08月19日 04:30:12 UTC
That patch was incorrect, it failed to deal with default and variadic parameters. This new test case incorporates the test case from bug 4676 as well,
which is also fixed by this patch.
---
void bug4652(U, T...)(long y, T x, U num){}
void bug4652default(T) (T value, int x=2) {}
void bug4652default(T) (T value, int y){ }
void bug4676(T...)(T args, string str) {}
void bug4676(T...)(T args) {}
void instantiate4652()
{
 bug4652(2, 'c', 27, 'e', 'f',1); // rejects-valid
 bug4652(2, 1); // infinite loop on valid code
 bug4652default(true);
 bug4676(1, 2, 3);
}
---
Revised patch. Template.c, line 1090, deduceFunctionTemplateMatch().
==========================
 #endif
 
 // Loop through the function parameters
- for (i = 0; i < nfparams; i++)
+ for (size_t parami = 0; parami < nfparams; parami++)
 {
 /* Skip over function parameters which wound up
 * as part of a template tuple parameter.
 */
- if (i == fptupindex)
- { if (fptupindex == nfparams - 1)
- break;
+ if (parami == fptupindex)
+ continue;
+ /* Set i = index into function arguments 
+ * Function parameters correspond to function arguments as follows.
+ * Note that tuple_dim may be zero, and there may be default or 
+ * variadic arguments at the end.
+ * arg [0..fptupindex] == param[0..fptupindex]
+ * arg [fptupindex..fptupindex+tuple_dim] == param[fptupindex]
+ * arg[fputupindex+dim.. ] == param[fptupindex+1.. ]
+ */
+ i = parami;
+ if (fptupindex >= 0 && parami > fptupindex)
 i += tuple_dim - 1;
- continue;
- }
 
- Parameter *fparam = Parameter::getNth(fparameters, i);
+ Parameter *fparam = Parameter::getNth(fparameters, parami);
 
 if (i >= nfargs) // if not enough arguments
 {
Comment 6 Walter Bright 2010年08月27日 20:54:58 UTC
http://www.dsource.org/projects/dmd/changeset/635 


AltStyle によって変換されたページ (->オリジナル) /