Bug 3174 – ICE(mtype.c): Compiler crash or compiler error with auto returns and const / immutable / invarient / pure
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
Windows
Creation time
2009-07-14T10:16:00Z
Last change time
2015-06-09T01:28:06Z
Keywords
ice-on-valid-code, patch, rejects-valid
Assigned to
nobody
Creator
sandford
Comments
Comment #0 by sandford — 2009-07-14T10:16:54Z
DMD either crashes or fails to compile a auto return function marked const/immutable or invarient
class A {
const foo(int i) { return i; } // DMD crash
const auto foo(int i) { return i; } // DMD crash
pure auto foo(int i) { return i; } // Okay
auto foo(int i) pure { return i; } // Fails to compile
foo(int i) const { return i; } // Fails to compile
auto foo(int i) const { return i; } // Fails to compile
}
void main(char[][] args) {
const A a = new A();
a.foo(5);
return;
}
Errors for auto foo(int i) const { return i; } (line 146)
main.d(147): found 'int' when expecting ')'
main.d(147): no identifier for declarator foo
main.d(147): semicolon expected, not 'i'
main.d(147): no identifier for declarator i
main.d(147): semicolon expected, not ')'
main.d(147): Declaration expected, not ')'
main.d(148): unrecognized declaration
The issues using const also apply to immutable / invarient.
DMD Crash:
Unhandled exception at 0x00410ba3 in dmd.exe: 0xC0000005: Access violation reading location 0x00000000.
inside mytype.c, at line 3800:
void TypeFunction::toDecoBuffer(OutBuffer *buf, int flag)
{ unsigned char mc;
//printf("TypeFunction::toDecoBuffer() this = %p %s\n", this, toChars());
//static int nest; if (++nest == 50) *(char*)0=0;
if (inuse)
{ inuse = 2; // flag error to caller
return;
}
inuse++;
#if 1
if (mod & MODshared)
buf->writeByte('O');
if (mod & MODconst)
buf->writeByte('x');
else if (mod & MODinvariant)
buf->writeByte('y');
#endif
switch (linkage)
{
case LINKd: mc = 'F'; break;
case LINKc: mc = 'U'; break;
case LINKwindows: mc = 'W'; break;
case LINKpascal: mc = 'V'; break;
case LINKcpp: mc = 'R'; break;
default:
assert(0);
}
buf->writeByte(mc);
if (ispure || isnothrow || isref)
{
if (ispure)
buf->writestring("Na");
if (isnothrow)
buf->writestring("Nb");
if (isref)
buf->writestring("Nc");
}
// Write argument types
Argument::argsToDecoBuffer(buf, parameters);
//if (buf->data[buf->offset - 1] == '@') halt();
buf->writeByte('Z' - varargs); // mark end of arg list
next->toDecoBuffer(buf);
Watch reports
next is null
this 0x076471c4
TypeFunction::toDecoBuffer::buf 0x0012faa4
TypeFunction::toDecoBuffer::mc 70 'F'
TypeFunction::toDecoBuffer::flag 0
Call Stack:
> dmd.exe!TypeFunction::toDecoBuffer(OutBuffer*,int )() Line 3800 + 0x8 bytes C++
dmd.exe!Type::merge()() Line 1122 C++
dmd.exe!FuncDeclaration::semantic(Scope*)() Line 165 + 0x7 bytes C++
dmd.exe!ClassDeclaration::semantic(Scope*)() Line 596 C++
dmd.exe!Module::semantic()() Line 675 C++
dmd.exe!main() Line 1057 C++
dmd.exe!_mainCRTStartup() + 0xa9 bytes
kernel32.dll!7c816fe7()
Comment #1 by clugdbug — 2009-10-02T00:08:13Z
There are actually 2 independent bugs here. My patch only deals with the ICE.
I've created bug 3359 for the parsing failure.
CAUSE: It's trying to do type->deco->merge() on a function, when it doesn't yet
know the return type. merge() is never done on plain auto functions, which is
why the thrid case doesn't segfault.
COMMENT: mtype.c, TypeFunction::toDecoBuffer() desperately needs an
assert(next); to generate an ICE instead of a segfault. I have seen at least
five different
bugs that crash there.
PATCH: I've done this by copy-and-paste, you probably want to reorganize this
function a bit to avoid duplication. This makes 'const' functions behave the
same as 'auto'
-- but actually plain 'auto' functions suffer from the other bugs, I think
because the merge() never happens.
Index: func.c
===================================================================
--- func.c (revision 75)
+++ func.c (working copy)
@@ -144,6 +144,13 @@
* to the function type
*/
type = type->semantic(loc, sc);
+ if (type->ty != Tfunction)
+ {
+ error("%s must be a function", toChars());
+ return;
+ }
+ f = (TypeFunction *)(type);
+
unsigned stc = storage_class;
if (type->isInvariant())
stc |= STCimmutable;
@@ -159,22 +166,22 @@
case STCimmutable | STCshared:
// Don't use toInvariant(), as that will do a merge()
type = type->makeInvariant();
- type->deco = type->merge()->deco;
+ if (f->next) type->deco = type->merge()->deco;
break;
case STCconst:
type = type->makeConst();
- type->deco = type->merge()->deco;
+ if (f->next) type->deco = type->merge()->deco;
break;
case STCshared | STCconst:
type = type->makeSharedConst();
- type->deco = type->merge()->deco;
+ if (f->next) type->deco = type->merge()->deco;
break;
case STCshared:
type = type->makeShared();
- type->deco = type->merge()->deco;
+ if (f->next) type->deco = type->merge()->deco;
break;
case 0: