incubator-stdcxx-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Martin Sebor <se...@roguewave.com>
Subject Re: [RFC] stdcxx release process, second draft
Date Thu, 13 Dec 2007 23:44:58 GMT
Travis Vitek wrote:
>  
> 
>> Travis Vitek wrote
>>
>> Martin Sebor wrote:
>>> I've incorporated everyone's feedback and committed an updated
>>> version with a number of enhancements of my own. Among the most
>>> important are the new Goals section with suggested frequencies of
>>> releases, and the integration of the Version Policy (I plan to delete
>>> versions.html). Let me know what you think.
>>>
>>>     http://incubator.apache.org/stdcxx/releases.html
>>>
>> Martin,
>>
>> I found this page that documents a few do's and dont's of binary
>> compatibility. I realize that most of the tricky issues involve inline
>> functions or templates, but this gives a list of the common pitfalls.
>>
>>  http://tinyurl.com/2gf38p
>>
>> Travis
> 
> Here are some examples that I came up with. Each case is written in a
> pseudo diff format.

Excellent! See my comments below.

> 
> Travis
> 
>  // neither source nor binary compatible. not source compatible
>  // if user might take address of member function A::f.
>  struct A
>  {
> -    int f() const { return 1; }
> +    int f(int i = 1) const { return i; }
>  };
> 
>  // alternative is source and binary compatible. can be changed
>  // to a default argument in next source incompatible release.
>  struct A
>  {
>     int f() const { return 1; }
> +   int f(int i) const { return i; }
>  };
> 
>  // is binary compatible, but not be source compatible because
>  // the compiler has no way to handle A().f(1)
>  struct A
>  {
>     int f(long i) const { return 2; }
> +   int f(unsigned i) const { return 2; }
>  };
> 

I would tend to throw these in the bag of "obvious no-no's."

>  // not binary compatible, changing access specifier on windows is a
> no-no. if the
>  // new access modifier is more restricted, this may be source
> incompatible, but
>  // only if the user code calls or takes the address of the function.
>  class A
>  {
> -private:
> +public:
>      int f() const { return 1; }
>  };

This one is much less obvious and so it might be worth mentioning
in the document.

> 
>  // source and binary compatible, not functionally compatible. f() will
> square v
>  // in user code, and ctor will square v in library code. if an instance
> is
>  // created in library and passed to user code, it will be squared
> twice. if the
>  // other way, it will not be squared at all.
>  //
>  // if the definitions were outlined, this would be compatible.
>  class A
>  {
>  public:
> -    A(float f) : v(f) { }
> -    float f() const { return v*v; }
> +    A(float f) : v(f*f) { }
> +    float f() const { return v; }
>  private:
>      float v;
>  };

This is an interesting case. Why (when) does it matter that the result
of f() is different? What does it mean for STDCXX-226?

> 
> 
>  // binary and source compatible, but not functionally compatible
>  // because call to g() is inlined.
>  //
>  // this would be compatible if f() were outlined, or g() behaved
>  // the same for input values 2 and 3.
>  struct A
>  {
> -    void f() { g(2); }
> +    void f() { g(3); }
>      void g(int i);
>  };

Same as above.

> 
> 
>  // it appears that this could be fully compatible in some cases.
>  // it might not be source/functionally compatible if the user is
>  // exposed to this type. a switch on an E instance might cause a
>  // default block to be hit, which could trigger a failure in user
>  // code.
>  //
>  // if A::Z is used as a `last enum' marker, this might introduce
>  // a binary compatibility issue if a global or member array is
>  // declared to have A::Z elements.
>  //
>  // this might also be binary incompatible if the enum is persisted.
>  struct A
>  {
> -    enum E { W, X, Z };
> +    enum E { W, X, Y, Z };
>  };

I'd say this is both source and binary incompatible.

Consider:

   switch (e) {
   case A::Z: break;
   case 4:    break;   // okay in version 1 but error on version 2
   }

and:

   template <int> struct S { };

   void foo (S<A::Z>());   // ==> mangled as foo_S_A_2 in version 1
                           //     but foo_S_A_3 in version 2

Thanks again. These are exactly the kind of examples I was hoping for:
innocuous looking changes that are fully compatible in most situations
but can be actually be breaking in some edge cases.

Martin

Mime
View raw message