stdcxx-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Mark Brown" <mark.g.br...@gmail.com>
Subject Re: [RFC] stdcxx release process, second draft
Date Fri, 14 Dec 2007 05:02:15 GMT
The Linux Documentation Project lists a number of examples of library
incompatibilities:
http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html#AEN135

--Mark

On Dec 13, 2007 4:44 PM, Martin Sebor <sebor@roguewave.com> wrote:
> 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