[omniORB] IDL compiler output broken for VC++ in recent snapshots

Duncan Grisby dgrisby@uk.research.att.com
Thu, 01 Nov 2001 13:00:04 +0000


On Wednesday 31 October, Carl Thompson wrote:

>       I am getting the following output when trying compile IDL compiler 
> output from omniORB4 2001-10-31 on Windows 2000 with VC++6sp5.  I have 
> attached the offending header and idl files.  The same IDL works fine on 
> the snapshot dated 2001-10-08 and with the current snapshot using GCC on 
> Linux.  This idl and code also works with other ORBs so I'm pretty sure 
> it's a problem with the IDL compiler generating VC++ incompatible output.

The problem is due to a bug in VC++. Unfortunately, I don't think it's
possible to fix in the general case, although it could be worked
around in your particular case. The reason it worked with the earlier
snapshot is that the snapshot had a bug. If you try your IDL with
omniORB 3, you'll find you get the same VC++ error.

The cause of the problem is that your IDL is of the form:

  interface A {
    enum B { one, two };

    union C switch (long) {
      case 1:
        A::B b;
    };
  };

Note how the union member name is the same as its type, except for
case, necessitating the full qualification as A::B according to the
IDL scope rules.

The C++ generated for this by omniidl is (missing lots out):

  class A {
    enum B { one, two };

    class C {
      A::B b();
      void b(A::B _value);
    };
  };

The thing that VC++ is objecting to is the use of class A to qualify
A::B before class A has finished being defined. That is valid C++, so
VC++ is incorrect. In this particular case, the work-around is to use
the unscoped name of the type:

    class C {
      B b();
      void b(B _value);
    };

omniidl could be convinced to do that, but it's a bit of a pain. I'm
not sure it's worth it, since there's still a problem. Imagine the
original IDL was

  interface A {
    enum B { one, two };

    union C switch (long) {
      case 1:
        A::B B;
    };
  };

i.e. the union member is called B rather than b.

Now we're in trouble if we don't qualify A::B

    class C {
      B B();
      void B(B _value);
    };

VC++ is happy about the first B B(), but I wouldn't be sure about
other compilers. The second one has no hope, though, since the look-up
of B finds two functions, and not the type. I can't think of any clean
way of working around that. There is at least one ugly way involving
typedefs, but it's too horrid to contemplate.

So, I think the best solution is to use a member name that isn't the
same as the type. That way, you can have

  interface A {
    enum B { one, two };

    union C switch (long) {
      case 1:
        A::B the_B;
    };
  };

and omniidl will output

    class C {
      B the_B();
      void the_B(B _value);
    };

and everyone will be joyful.


Cheers,

Duncan.

-- 
 -- Duncan Grisby  \  Research Engineer  --
  -- AT&T Laboratories Cambridge          --
   -- http://www.uk.research.att.com/~dpg1 --