Bug 5164 – Error without line number using "is (T...)"
Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
Windows
Creation time
2010-11-04T08:35:00Z
Last change time
2010-11-14T01:02:36Z
Keywords
diagnostic, patch
Assigned to
nobody
Creator
clugdbug
Comments
Comment #0 by clugdbug — 2010-11-04T08:35:52Z
static if (is(int Q == int, Z...)) { }
----
test0.d: Error: tuple test0.Z conflicts with tuple test0.Z at test0.d
An exceedingly poor error message.
Comment #1 by clugdbug — 2010-11-05T23:22:56Z
There are multiple problems here:
(1) The missing line number is because in declaration.c, line 157, 'loc' never gets stored:
TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects)
: Declaration(id)
{
+ this->loc = loc;
this->type = NULL;
this->objects = objects;
(2) The error message happens because in IsExp::semantic(), around line 5130, in the "declare trailing parameters" section, the symbol is added TWICE. First as:
sc->insert(s);
and later as
s->addMember(sc, sc->sd, 1);
For every other pooible symbol in an is(), it recognizes it's a duplicate and doesn't raise an error, but TupleDeclaration doesn't define overloadInsert, so it fails. But I don't think it should be adding twice in the first place.
The difference between insert() and addMember() is that the latter allows code such as this:
struct boo(T...) {}
template foo(T){
static if (is(T xxx == boo!(U), U...) ) {}
enum result = true;
}
foo!(boo!(int)).U[0] yyy;
That is, it makes the declared symbol accessible outside the template. But if it's a struct foo(T), the U symbol is accessible in both cases. So I think the call to sc->insert(s) should be moved to the end, and called only if addMember isn't called. Line 5145.
- if (!sc->insert(s))
- error("declaration %s is already defined", s->toChars());
#if 0
Object *o = (Object *)dedtypes.data[i];
Dsymbol *s = TemplateDeclaration::declareParameter(loc, sc, tp, o);
#endif
if (sc->sd)
s->addMember(sc, sc->sd, 1);
+ else if (!sc->insert(s))
+ error("declaration %s is already defined", s->toChars());
(3) Although the example in point 2 now compiles, it generates wrong code! The tuple will always be empty. This is because the earlier correctly deduced tuple is getting clobbered. This happens in template.c, line 3510
MATCH TemplateTupleParameter::matchArg(Scope *sc,
Objects *tiargs, int i, TemplateParameters *parameters,
Objects *dedtypes,
Declaration **psparam, int flags)
{
//printf("TemplateTupleParameter::matchArg()\n");
/* The rest of the actual arguments (tiargs[]) form the match
* for the variadic parameter.
*/
assert(i + 1 == dedtypes->dim); // must be the last one
Tuple *ovar;
+ // It might have already been deduced
+ if (dedtypes->data[i] && isTuple((Object *)dedtypes->data[i]))
+ ovar = isTuple((Object *)dedtypes->data[i]);
else
if (i + 1 == tiargs->dim && isTuple((Object *)tiargs->data[i]))
ovar = isTuple((Object *)tiargs->data[i]);