What’s Bugging GDC?

Recently, I was asked the question:

Is gdc 4.3 really stable enough to be the default gdc?

As the gdc meta-package in Debian Squeeze and Ubuntu Lucid has been updated to now depend on gdc-4.3 instead of gdc-4.1. And by just playing around with D for a few days the kind fella who asked me that discovered two bugs. So it seems to him that gdc-4.3 is far from being as mature as gdc-4.1 …

I decided to look into this by running dstress against the most recent build. For those of you who don’t know, dstress is a testing suite for D to ensure that the compiler correctly compiles (or in some cases, must not compile) a collection of about 7000+ files with 32 different compiler flag combinations without dying unintentionally, ie: via assertion or a segmentation fault.

From that huge list, I got a total of 10 internal compiler errors produced.

Here is a beautified list of internal errors that I got from the report. This first list consists of GDC back-end errors only, as they will be specific to GDC. Unlike the front-end errors, which will most likely be present in DMD and possibly LDC too.

Update: Some good development has gone into GDC since writing this post, so I’m crossing off each issue as it gets resolved.

________________________________________________________________

Internal Compiler Error 1:

Code?

public struct Color
{
    double red   = 0;
    double green = 0;
    double blue  = 0;

    static Color opCall()
    {
        Color instance;
        return instance;
    }
    Color opAdd(real right){ return Color(); }
    void opAddAssign(real right){ *this = *this + right; }
}

Error?

opAddAssign_A.d: In member function ‘opAddAssign’:
opAddAssign_A.d:13: internal compiler error: in decl_ultimate_origin, at dwarf2out.c:5139

Reproducable?
Only via:

gdc -g -O3 -c opAddAssign_A.d
gdc -g -O2 -frelease -c opAddAssign_A.d
gdc -g -Os -frelease -c opAddAssign_A.d
gdmd -g -O -inline -c opAddAssign_A.d
gdmd -g -O -release -c opAddAssign_A.d

Variants?
Not known.

Workaround?
In all cases, include the compiler option “-fno-inline” to workaround the bug.

Bug seen in gdc-4.1?
No.

________________________________________________________________

Internal Compiler Error 2:

Code?

template thunk(alias fn)
{
    static void thunk(int* arg)
    {
        fn(arg);
    }
}

int main()
{
    int x = 1;
    void inner(int* arg)
    {
        if(!(arg !is &x))
            assert(0);
    }
    thunk!(inner)(&x);
    return 0;
}

Error?

bug_tree_inline_1902_B.d: In function ‘thunk’:
bug_tree_inline_1902_B.d:5: internal compiler error: in estimate_num_insns_1, at tree-inline.c:2494

Reproducable?
Always.

Variants?
Seen also in compiler error 3 and 4, but not known just how related they are.

Workaround?
Using “void thunk” instead of “static void thunk”.

Bug seen in gdc-4.1?
Yes.

________________________________________________________________

Internal Compiler Error 3:

Code?

int main()
{       
    void foo() {}       
    void function() bar = function void()
    {           
        foo();  
    };  
    return 0;
}

Error(s)?

bug_e2ir_299_A.d: In function ‘__funcliteral1’:
bug_e2ir_299_A.d:6: internal compiler error: in estimate_num_insns_1, at tree-inline.c:2494

Reproducable?
Always.

Variants?
Seen also in compiler error 2 and 4, but not known just how related they are.

Workaround?
Is apparently not supposed to be compilable. (comes under nocompile).

Bug seen in gdc-4.1?
Yes.

________________________________________________________________

Internal Compiler Error 4:

Code?

struct A (alias F)
{
    int f() { return F(); }
}

void main()
{
    int f() { return 0; }
    A!(f) a;
}

Error?

template_struct_01_A.d: In member function ‘f’:
template_struct_01_A.d:5: internal compiler error: in estimate_num_insns_1, at tree-inline.c:2494

Reproducable?
Always.

Variants?
Seen also in compiler error 2 and 3, but not known just how related they are.

Workaround?
None.

Bug seen in gdc-4.1?
Yes.

________________________________________________________________

Internal Compiler Error 5:

Code?

class Outer
{
    this()
    {
        Inner i = new Inner();
    }

    class Inner
    {
        Strct str;
    }
}

struct Strct
{
    int i;
}

int main()
{
    Outer o = new Outer();
    return 0;
}

Error?

forward_reference_17_A.d: In member function ‘_ctor’:
forward_reference_17_A.d:5: internal compiler error: Segmentation fault

Reproducable?

Always

Variants?
Not known.

Workaround?
Declare the struct before the class.

Bug seen in gdc-4.1?
Yes

________________________________________________________________

Internal Compiler Error 6:

Code?

bool nextis(void delegate() dgpositive = {})
{
    return true;
}

bool looping(lazy bool condition)
{
    return true;
}

int main()
{
    looping(nextis());
    return 0;
}

Error?

lazy_02_A.d: In member function ‘__dgliteral2’:
lazy_02_A.d:2: internal compiler error: in getFrameForSymbol, at d/d-codegen.cc:2541

Reproducable?
Always.

Variants?
Anything that uses the following as an argument.

void delegate() foo = {}

Workaround?
None.

Bug seen in gdc-4.1?
Yes.

________________________________________________________________

Internal Compiler Error 7:

Code?

int status;

template T(alias a)
{
    int dummy;
}

class C
{
    mixin T!(
            () {
                status++;
            }
        ) mixed;
}

int main()
{
    C c = new C();
    c.mixed.a();
    if(status != 1)
    {
        assert(0);
    }
    return 0;
}

Error?

mixin_23_A.d:11: Error: delegate mixin_23_A.C.__dgliteral1 literals cannot be class members
cc1d: internal compiler error: Segmentation fault

Reproducable?
Always.

Variants?
Also seen when using:

mixin T!( delegate() { status++; } ) mixed;

And:

mixin T!( { status++; } ) mixed;

Workaround?
Using function() works around the problem, but probably not correct due to semantic differences.

mixin T!( function(){ status++; } ) mixed;

Bug seen in gdc-4.1?
No.

________________________________________________________________

In this second list are DMD frontend compiler errors, they aren’t necessarily the fault of GDC’s, and they may well be present in LDC too.

Internal Compiler Error 8:

Code?

char[] testHelper(A ...)()
{
    char[] result;
    foreach(t; a)
    {
        result ~= "int " ~ t ~ ";\n";
    }
    return result;
}

int main()
{
    mixin( testHelper!( "hello", "world" )() );
    return 0;
}

Error?

cc1d: ../../src/gcc/d/dmd/template.c:811: MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc, Objects*, Expression*, Expressions*, Objects*): Assertion `i dim' failed.
cc1d: internal compiler error: Aborted

Reproducable?
Always.

Variants?
Not known.

Workaround?
Code is not supposed to be compilable. (comes under nocompile).

Bug seen in gdc-4.1?
No.

________________________________________________________________

Internal Compiler Error 9:

Code?

void[10] array;

Error?

Error: integral constant must be scalar type, not void
cc1d: ../../src/gcc/d/dmd/todt.c:85: dt_t* createTsarrayDt(dt_t*, Type*): Assertion `tsa->size(0) % eoa_size == 0' failed.
cc1d: internal compiler error: Aborted

Reproducable?
Always.

Variants?
Not known.

Workaround?
Code is not supposed to be compilable. (comes under nocompile).

Bug seen in gdc-4.1?
Yes.

________________________________________________________________

Internal Compiler Error 10:

Code?

int main()
{
    auto arr = [4:"vier", 0:"null", 2:"zwei"];

    if(3 != arr.length)
    {
        assert(0);
    }

    char[][] master_e = ["vier", "null", "zwei"];
    int[] master_i = [4, 0, 2];

    foreach(index, element; arr)
    {
        bool found = false;
        foreach(pos, i; master_i)
        {
            if(index == i && element == master_e[pos])
            {
                master_i = master_i[0 .. pos] ~ master_i[pos+1 .. $];
                master_e = master_e[0 .. pos] ~ master_e[pos+1 .. $];
                found = true;
                break;
            }
        }
        if(!found)
        {
            assert(0);
        }
    }
    if(master_i.length)
    {
        assert(0);
    }
    return 0;
}

Error?

associative_array_23_B.d:3: Error: cannot infer type from this array initializer
cc1d: ../../src/gcc/d/dmd/init.c:437: virtual Expression* ArrayInitializer::toExpression(): Assertion `j < edim' failed.
cc1d: internal compiler error: Aborted

Reproducable?
Always.

Variants?
Not known.

Workaround?
None.

Bug seen in gdc-4.1?
No.

________________________________________________________________

So, as far as the dstress testing goes, there are currently 4 regressions – 2 of which are not the fault of gdc – and 6 inherited bugs in gdc-4.3 when compared to gdc-4.1.

So, back to your original question, is gdc 4.3 really stable enough to be the default gdc? Thanks to your help in identifying two underlying problems in the Debianised version, yes, I believe it is!

Despite some outstanding quirks, and the odd ICE or two in this post that would be cool to plumb down and fix. I think we are heading in for a strong release – if and when the GDC upstream developers ever get round to it. In the meantime, I will continue maintaining the Debian and Ubuntu packages, and will love to hear more of your dedicated support and patience in testing.

Got any other show-stopping bugs? Please report! :-)

Proof of Concept: Writing a Linux Kernel Module in D

I thought it best today to post this in a QA format just to ease you into it.

Alright, what narcotics are you on? Seriously…
I’d like to start this post with answering a few prejudiced questions before anyone asks. No, I’m not on narcotics. Yes, this can be done. No I don’t recommend it, and no, I’m not that crazy, but I do have quite a bit of time on my hands.

Why?
Try asking yourself, why not?

D is a horrible language. It’s made more horrible by the fact that a lot of substandard programmers use it, to the point where it’s much much easier to generate total and utter crap with it. Quite frankly, even if the choice of C were to do *nothing* but keep the D programmers out, that in itself would be a huge reason to use C.
I think you are confusing D with C++. ;-)

Everyone happy? OK, I’ll continue then.

You actually wrote a kernel module using only D?
OK. First I’d like to clarify, I am not using pure D here, but instead a utilising D’s capability of Interfacing to C. The glue itself is in C, and the interfacing code is wrapped in “extern (C)”, so the kernel can call the functions. But given the capability, you can mixin D with C.

OK, so you’re faking it. Somehow I’ve lost interest in this.
Suit yourself, bet you don’t want to see the code either.

Fine, so what does it look like?
Here is a hello world module.

hello.c:

#include  /* Needed by all modules */

dinterface.d:

extern (C):
int printk(char *s, ...);

int __gdc_personality_v0()
{
    // STUB: int __gdc_personality_v0() not implemented
    return 0;
}

int init_module()
{
    printk("Hello world!\n");
    return 0;
}

void cleanup_module()
{
    printk("Goodbye world!\n");
}

Makefile:

# D compiler
DC := gdc
# D objects
DOBJS := dinterface.o

ifneq ($(MAKE_KBUILD),)
# kbuild part of makefile

obj-$(CONFIG_HELLO) := hello.o
hello-y += $(DOBJS)

else
# normal part of makefile

KERNELDIR := /lib/modules/$(shell uname -r)/build

all: $(DOBJS)
	$(MAKE) -C $(KERNELDIR) M=$(shell pwd) CONFIG_HELLO=m MAKE_KBUILD=1 modules

clean:
	$(MAKE) -C $(KERNELDIR) M=$(shell pwd) MAKE_KBUILD=1 clean

%.o: %.d
	$(DC) -c $< -o $@

endif

Simply type

make

to build it, then to insert the module into the kernel

sudo insmod hello.ko

And you can see the hello world in ‘dmesg’

That simple eh? OK, what is the catch Iain…
The catch? In order to use D’s most favoured features, such as arrays, you will have to port D’s runtime, typeinfo and exception handling routines (notice that __gdc_personality_v0 is just a dummy function), as they won’t be carried over in the linking of the module.

Hmm… so have you implemented this?
As of writing, no, and I don’t intend to either. You can however look into Xomb for a minimal d runtime. But the feasibility of porting it is not really worth the hassle. Infact, more than likely you will never get it working full stop, and just end up segfaulting the kernel every time.

OK, so what is the moral of this post then?
I’m wide awake, it’s Saturday. :)

Follow

Get every new post delivered to your Inbox.