Ah, yes, GCC and MSVC... Or, two compiler bugs in two hours.

jwatte's picture

Why is it that seemingly every week-end project ends up in tears and teeth gnashing over broken tools, instead of sweet progress? Why do computer companies keep cramming useless features into bloatware, instead of just making what they have, actually work?

I started out with an MSVC internal compiler error (in VS 2008 SP1 -- the latest available version). Trying to report it to http://connect.microsoft.com/, I got a time-out from their web service when uploading the file. Oh, great! But it seems that others have reported a similar crash, and it'll be fixed in VC 2010. Great, I only need to wait a year before that is out! (sarcasm)

Sometimes, VS crashes because it's trying to report an error, but the error message formatter is given bad data -- typically, someone put a ^1 where they meant a ^2 or something like that. Error handling is always pretty buggy, because it's usually tested much less than the "proper" code paths in a program. So, I figured I'd take the code over to Linux and run it through G++ (4.2.4 from Ubunty 8.04 Server LTS) to see where the error lies, if there is one, so I can make progress.

I removed all the Windows-specific stuff, and ended up with a small snippet of code. Unfortunately, that code actually compiles fine on Visual Studio. However, when compiling on GCC, GCC seems to be sorely confused, and tells me that my base class members aren't defined.

Imagine that! Two different compiler bugs, in two different compilers, in one week-end!

The code, for those of you who care:

class Subscriber
{
  public:
    virtual void OnDelivery() = 0;
    virtual void OnCancellation() = 0;
};
 
class Subscribable
{
  public:
    virtual void AddSubscriber(Subscriber *sub) = 0;
    virtual void RemoveSubscriber(Subscriber *sub) = 0;
};
 
template<typename Host>
class HostedSubscriberBase : Subscriber
{
  public:
    HostedSubscriberBase() : host_(0), subscribable_(0) {}
    void Start(Subscribable *sub, Host *host)
      {
        Stop();
        if (sub != 0)
        {
          host_ = host;
          subscribable_ = sub;
          sub->AddSubscriber(this);
        }
      }
    void Stop()
      {
        if (subscribable_)
          subscribable_->RemoveSubscriber(this);
        subscribable_ = 0;
        host_ = 0;
      }
    bool Active() const
      {
        return subscribable_ != 0;
      }
  protected:
    Host *host_;
    Subscribable * subscribable_;
};
 
template<typename Host, void (Host::*Delivery)(), void (Host::*Cancellation)()>
class HostedSubscriber : public HostedSubscriberBase<Host>
{
  public:
    void OnDelivery()
      {
        (host_->*Delivery)();
      }
    void OnCancellation()
      {
        subscribable_ = 0;
        Host *h = host_;
        host_ = 0;
        (h->*Cancellation)();
      }
};
 
template<typename Host, void (Host::*Delivery)()>
class HostedSubscriberDeliveryOnly : public HostedSubscriberBase<Host>
{
  public:
    void OnDelivery()
      {
        (host_->*Delivery)();
      }
    void OnCancellation()
      {
        subscribable_ = 0;
        host_ = 0;
      }
};
 
template<typename Host, void (Host::*Cancellation)()>
class HostedSubscriberCancellationOnly : public HostedSubscriberBase<Host>
{
  public:
    void OnDelivery()
      {
      }
    void OnCancellation()
      {
        subscribable_ = 0;
        Host *h = host_;
        host_ = 0;
        (h->*Cancellation)();
      }
};
 
class Foo
{
  public:
    void Func() {}
    HostedSubscriberCancellationOnly<Foo, &Foo::Func> foo_;
};

And the G++ error messages:

GuiKitWidget2.cpp: In member function âvoid HostedSubscriber<Host, Delivery, Cancellation>::OnDelivery()â:
GuiKitWidget2.cpp:52: error: âhost_â was not declared in this scope
GuiKitWidget2.cpp: In member function âvoid HostedSubscriber<Host, Delivery, Cancellation>::OnCancellation()â:
GuiKitWidget2.cpp:56: error: âsubscribable_â was not declared in this scope
GuiKitWidget2.cpp:57: error: âhost_â was not declared in this scope
GuiKitWidget2.cpp: In member function âvoid HostedSubscriberDeliveryOnly<Host, Delivery>::OnDelivery()â:
GuiKitWidget2.cpp:69: error: âhost_â was not declared in this scope
GuiKitWidget2.cpp: In member function âvoid HostedSubscriberDeliveryOnly<Host, Delivery>::OnCancellation()â:
GuiKitWidget2.cpp:73: error: âsubscribable_â was not declared in this scope
GuiKitWidget2.cpp:74: error: âhost_â was not declared in this scope
GuiKitWidget2.cpp: In member function âvoid HostedSubscriberCancellationOnly<Host, Cancellation>::OnCancellation()â:
GuiKitWidget2.cpp:87: error: âsubscribable_â was not declared in this scope
GuiKitWidget2.cpp:88: error: âhost_â was not declared in this scope

(Especially note the wonderful way in which back-quotes are turned into a-circumflex characters. Linux is truly the star of the desktop! (*not*))