'''Reason''': the mangling of the functions related to this template type change because its template expansion changes too. This can happen both for member functions (for example, the constructor) as well as functions that take it as a parameter.

'''Reason''': the mangling of the functions related to this template type change because its template expansion changes too. This can happen both for member functions (for example, the constructor) as well as functions that take it as a parameter.

Line 96:

Line 96:

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Q_CORE_EXPORT const char *qVersion();

Q_CORE_EXPORT const char *qVersion();

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

const char *qVersion();

const char *qVersion();

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 105:

Line 105:

KDECORE_EXPORT QTcpSocket *connectToHost(...);

KDECORE_EXPORT QTcpSocket *connectToHost(...);

}

}

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

namespace KSocketFactory {

namespace KSocketFactory {

QTcpSocket *connectToHost(...);

QTcpSocket *connectToHost(...);

}

}

−

</code>

+

</syntaxhighlight>

|}

|}

Line 123:

Line 123:

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

int square(int n);

int square(int n);

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

inline int square(int n) { return n * n; }

inline int square(int n) { return n * n; }

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

int square(int n) { return n * n; }

int square(int n) { return n * n; }

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

inline int square(int n) { return n * n; }

inline int square(int n) { return n * n; }

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 144:

Line 144:

int Math::square(int n)

int Math::square(int n)

{ return n * n; }

{ return n * n; }

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

class Math

class Math

Line 154:

Line 154:

inline int Math::square(int n)

inline int Math::square(int n)

{ return n * n; }

{ return n * n; }

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 165:

Line 165:

int Math::square(int n)

int Math::square(int n)

{ return n * n; }

{ return n * n; }

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

class Math

class Math

Line 172:

Line 172:

{ return n * n; }

{ return n * n; }

};

};

−

</code>

+

</syntaxhighlight>

|}

|}

Line 187:

Line 187:

// MSVC mangling: ?doSomething@@YAXHH@Z

// MSVC mangling: ?doSomething@@YAXHH@Z

void doSomething(int i1, int i2);

void doSomething(int i1, int i2);

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

// GCC mangling: _Z11doSomethingis

// GCC mangling: _Z11doSomethingis

// MSVC mangling: ?doSomething@@YAXHF@Z

// MSVC mangling: ?doSomething@@YAXHF@Z

void doSomething(int i1, short i2);

void doSomething(int i1, short i2);

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 198:

Line 198:

// MSVC mangling: ?doSomething@@YAXHH@Z

// MSVC mangling: ?doSomething@@YAXHH@Z

void doSomething(int i1, int i2);

void doSomething(int i1, int i2);

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

// GCC mangling: _Z11doSomethingiii

// GCC mangling: _Z11doSomethingiii

// MSVC mangling: ?doSomething@@YAXHHH@Z

// MSVC mangling: ?doSomething@@YAXHHH@Z

void doSomething(int i1, int i2, int i3 = 0);

void doSomething(int i1, int i2, int i3 = 0);

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 209:

Line 209:

// MSVC mangling: ?doSomething@@YAXABH@Z

// MSVC mangling: ?doSomething@@YAXABH@Z

void doSomething(int &i1);

void doSomething(int &i1);

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

// GCC mangling: _Z11doSomethingRKi

// GCC mangling: _Z11doSomethingRKi

// MSVC mangling: ?doSomething@@YAXAAH@Z

// MSVC mangling: ?doSomething@@YAXAAH@Z

void doSomething(const int &i1);

void doSomething(const int &i1);

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

void doSomething(int i1);

void doSomething(int i1);

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

void doSomething(const int i1); // breaks with Sun CC

void doSomething(const int i1); // breaks with Sun CC

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 227:

Line 227:

// MSVC mangling: ?doSomething@@YAXPAD@Z (32-bit)

// MSVC mangling: ?doSomething@@YAXPAD@Z (32-bit)

void doSomething(char *ptr);

void doSomething(char *ptr);

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

// GCC mangling: _Z11doSomethingPKc

// GCC mangling: _Z11doSomethingPKc

// MSVC mangling: ?doSomething@@YAXPBD@Z (32-bit)

// MSVC mangling: ?doSomething@@YAXPBD@Z (32-bit)

void doSomething(const char *ptr);

void doSomething(const char *ptr);

−

</code>

+

</syntaxhighlight>

|}

|}

Line 249:

Line 249:

// MSVC mangling: ?position@@YA_JXZ

// MSVC mangling: ?position@@YA_JXZ

qint64 position();

qint64 position();

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

// GCC mangling: _Z8positionv

// GCC mangling: _Z8positionv

// MSVC mangling: ?position@@YAHXZ

// MSVC mangling: ?position@@YAHXZ

int position();

int position();

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 260:

Line 260:

// MSVC mangling: ?position@@YAVQByteArray@@DXZ

// MSVC mangling: ?position@@YAVQByteArray@@DXZ

QByteArray name();

QByteArray name();

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

// GCC mangling: _Z4namev

// GCC mangling: _Z4namev

// MSVC mangling: ?position@@YAVQString@@XZ

// MSVC mangling: ?position@@YAVQString@@XZ

QString name();

QString name();

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 271:

Line 271:

// MSVC mangling: ?position@@YAPBDXZ

// MSVC mangling: ?position@@YAPBDXZ

const char *name();

const char *name();

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

// GCC mangling: _Z4namev

// GCC mangling: _Z4namev

// MSVC mangling: ?position@@YAVQString@@XZ

// MSVC mangling: ?position@@YAVQString@@XZ

QString name();

QString name();

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 282:

Line 282:

// MSVC mangling: ?createDevice@@YAPAVQTcpSocket@@XZ

// MSVC mangling: ?createDevice@@YAPAVQTcpSocket@@XZ

QTcpSocket *createDevice();

QTcpSocket *createDevice();

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

// GCC mangling: _Z12createDevicev (unchanged)

// GCC mangling: _Z12createDevicev (unchanged)

// MSVC mangling: ?createDevice@@YAPAVQIODevice@@XZ

// MSVC mangling: ?createDevice@@YAPAVQIODevice@@XZ

QIODevice *createDevice();

QIODevice *createDevice();

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 293:

Line 293:

// MSVC mangling: ?at@QByteArray@@QBA?BDH@Z

// MSVC mangling: ?at@QByteArray@@QBA?BDH@Z

const char QByteArray::at(int) const;

const char QByteArray::at(int) const;

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

// GCC mangling: _ZNK10QByteArray2atEi (unchanged)

// GCC mangling: _ZNK10QByteArray2atEi (unchanged)

// MSVC mangling: ?at@QByteArray@@QBADH@Z

// MSVC mangling: ?at@QByteArray@@QBADH@Z

char QByteArray::at(int) const;

char QByteArray::at(int) const;

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 304:

Line 304:

// MSVC mangling: ?registerEventType@QEvent@@QAAXH@Z

// MSVC mangling: ?registerEventType@QEvent@@QAAXH@Z

int QEvent::registerEventType(int)

int QEvent::registerEventType(int)

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

// GCC mangling: _ZN6QEvent17registerEventTypeEi (unchanged)

// GCC mangling: _ZN6QEvent17registerEventTypeEi (unchanged)

// MSVC mangling: ?registerEventType@QEvent@@QAAXW4Type@V0@@@Z

// MSVC mangling: ?registerEventType@QEvent@@QAAXW4Type@V0@@@Z

QEvent::Type QEvent::registerEventType(int)

QEvent::Type QEvent::registerEventType(int)

−

</code>

+

</syntaxhighlight>

|}

|}

Line 334:

Line 334:

void doSomething();

void doSomething();

};

};

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

class MyClass

class MyClass

Line 343:

Line 343:

void doSomething();

void doSomething();

};

};

−

</code>

+

</syntaxhighlight>

|}

|}

Line 362:

Line 362:

int something() const;

int something() const;

};

};

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

class MyClass

class MyClass

Line 371:

Line 371:

int something();

int something();

};

};

−

</code>

+

</syntaxhighlight>

|}

|}

Line 386:

Line 386:

// MSVC mangling: ?data@@3HA

// MSVC mangling: ?data@@3HA

int data = 42;

int data = 42;

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

// GCC mangling: data (undecorated)

// GCC mangling: data (undecorated)

// MSVC mangling: ?data@@3FA

// MSVC mangling: ?data@@3FA

short data = 42;

short data = 42;

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 401:

Line 401:

static int data;

static int data;

};

};

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

class MyClass

class MyClass

Line 410:

Line 410:

static short data;

static short data;

};

};

−

</code>

+

</syntaxhighlight>

|}

|}

Line 426:

Line 426:

// MSVC mangling: ?data@@3HA

// MSVC mangling: ?data@@3HA

int data = 42;

int data = 42;

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

// MSVC mangling: ?data@@3HB

// MSVC mangling: ?data@@3HB

const int data = 42;

const int data = 42;

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 439:

Line 439:

static int data;

static int data;

};

};

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

class MyClass

class MyClass

Line 447:

Line 447:

static const int data;

static const int data;

};

};

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 455:

Line 455:

static int data;

static int data;

};

};

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

class MyClass

class MyClass

Line 463:

Line 463:

static const int data = 42;

static const int data = 42;

};

};

−

</code>

+

</syntaxhighlight>

|}

|}

Line 481:

Line 481:

int i;

int i;

};

};

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

struct Data

struct Data

Line 488:

Line 488:

virtual int j();

virtual int j();

};

};

−

</code>

+

</syntaxhighlight>

|}

|}

Line 506:

Line 506:

virtual void foo();

virtual void foo();

};

};

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

class MyClass

class MyClass

Line 515:

Line 515:

virtual void bar();

virtual void bar();

};

};

−

</code>

+

</syntaxhighlight>

|}

|}

Line 534:

Line 534:

virtual void bar();

virtual void bar();

};

};

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

class MyClass

class MyClass

Line 543:

Line 543:

virtual void foo();

virtual void foo();

};

};

−

</code>

+

</syntaxhighlight>

|}

|}

Line 565:

Line 565:

virtual void bar();

virtual void bar();

};

};

−

</code>

+

</syntaxhighlight>

{|

{|

|-

|-

Line 578:

Line 578:

void foo();

void foo();

};

};

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

class MyClass: public PrimaryBase, public SecondaryBase

class MyClass: public PrimaryBase, public SecondaryBase

Line 587:

Line 587:

void bar();

void bar();

};

};

−

</code>

+

</syntaxhighlight>

|}

|}

Line 606:

Line 606:

struct Complex1: Data0, Data1 { };

struct Complex1: Data0, Data1 { };

struct Complex2: virtual Data1 { };

struct Complex2: virtual Data1 { };

−

</code>

+

</syntaxhighlight>

{|

{|

|-

|-

Line 617:

Line 617:

public:

public:

};

};

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

class MyClass: public BaseClass

class MyClass: public BaseClass

Line 624:

Line 624:

Complex1 *get();

Complex1 *get();

};

};

−

</code>

+

</syntaxhighlight>

|-

|-

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

Line 631:

Line 631:

public:

public:

};

};

−

</code>

+

</syntaxhighlight>

| <syntaxhighlight lang="cpp-qt">

| <syntaxhighlight lang="cpp-qt">

class MyClass: public BaseClass

class MyClass: public BaseClass

Line 638:

Line 638:

Complex2 *get();

Complex2 *get();

};

};

−

</code>

+

</syntaxhighlight>

|}

|}

Latest revision as of 20:57, 29 June 2011

This page is meant as examples of things you cannot do in C++ when maintaining binary compatibility.

Reason: the mangling of the functions related to this template type change because its template expansion changes too. This can happen both for member functions (for example, the constructor) as well as functions that take it as a parameter.

class Math
{int square(int n);};// the following could be in a .cppint Math::square(int n){return n * n;}

class Math
{int square(int n);};// the following could be in a .cppinlineint Math::square(int n){return n * n;}

class Math
{int square(int n);};// the following could be in a .cppint Math::square(int n){return n * n;}

class Math
{int square(int n){return n * n;}};

Reason: when a function is declared inline and the compiler does inline it at its call point, the compiler does not have to emit an out-of-line copy. Code that exists and was calling this function will therefore not be able to resolve the function anymore. Also, when compiling with GCC and -fvisibility-inlines-hidden, if the compiler does emit an out-of-line copy, it will be hidden (not added to the exported symbols table) and therefore not accessible from other libraries.

Reason: changing the parameters of a function (adding new or changing existing) changes the mangled name of that function. The reason for that is that the C++ language allows overloading of functions with the same name but slightly different parameters.

I don't have the mangled name for the Sun CC example above, that compiler does enforce the constness of POD types in both declaration and implementation.

Reason: changing the return type changes the mangled name of the function names in some compilers (GCC notably does not encode the return type). However, even if the mangling doesn't change, the convention on how the return types are handled may change.

In the first example above, the return type changed from a 64- to a 32-bit integer, which means on some architectures, the upper half of the return register may contain garbage. In the second example, the return type changed from QByteArray to QString, which are two incompatible types.

In the third example, the return type changed from a simple integer (a POD) to a QString -- in this case, the compiler usually needs to pass a hidden implicit first parameter, which won't be there. In this case, existing code calling the function will more than likely crash, due to trying to dereference the implicit QString* parameter that isn't there.

In the fourth example, the return type changed from one POD type (an int) to another (an enum), which is also carried by an int. The calling sequence is most likely the same in all compilers, however the mangling of the symbol name changed, meaning that calls will fail due to an unresolved symbol.

Reason: some compilers encode the type of the global data in its mangled name. Especially note that some compilers mangle even for simple data types that would be allowed in C, meaning the extern "C" qualifier makes a difference too.

Even if the mangling doesn't change, changing the type often changes the size of the data as well. That means code that was accessing the global data may be access too many or too few bytes.

Reason: some compilers encode the CV-qualifiers of the global data in its mangled name. Especially note that a static const value declared in the class itself can be considered for "inlining" -- that is, the compiler doesn't need to generate an external symbol for the value since all implementations are guaranteed to know it.

Even for compilers that don't encode the CV-qualifiers of global data, adding const may make the compiler place the variable in a read-only section of memory. Code that tried to write it will probably crash.

Reason: a class without any virtual members or bases is guaranteed to be exactly like a C structure, for compatibility with that language (that is a POD structure). On some compilers, structures/classes with bases that are POD themselves are also POD. However, as soon as there's one virtual base or virtual member function, the compiler is free to arrange the structure in a C++ manner, which usually means inserting a hidden pointer at the beginning or the end of the structure, pointing to the virtual table of that class. This changes the size and offset of the elements in the structure.

Reason: the addition of a new virtual function to a class that is non-leaf (that is, there is at least one class deriving from this class) changes the layout of the virtual table (the virtual table is basically a list of function pointers, pointing to the functions that are active in this class level). To accommodate the new virtual, the compiler must add a new entry to this table, but existing derived classes won't know about it and will not have the entry in their virtual tables.

Reason: the compiler places the pointers to the functions implementing the virtual functions in the order that they are declared in the class. By changing the order of the declaration, the order of the entries in the virtual table changes too.

Note: the order is inherited from the parent classes, so overriding a virtual will allocate the entry in the parent's order.

Reason: this is a tricky case. When dealing with multiple-inheritance of classes with virtual tables, the compiler must create multiple virtual tables to guarantee polymorphism works (that is, when your MyClass object is stored in a PrimaryBase or SecondaryBase pointer). The virtual table for the primary base is shared with the class's own virtual table, because they have the same layout at the beginning. However, if you override a virtual coming from a non-primary base, it is the same as adding a new virtual, since that primary base did not have the virtual by that name.

Note: this applies to any case of multiple-inheritance, even if it's not a direct base. In the example above, if we had MyOtherClass deriving from MyClass, the same restriction would apply.

[edit] Override a virtual with a covariant return with different top address

Reason: this is another tricky case, like the above one and also for the same reason: the compiler must add a second entry to the virtual table, just as if a new virtual function had been added, which changes the layout of the virtual table and breaks derived classes.

Covariant calls happen when the function overriding a virtual from a parent class returns a class different from the parent (this is allowed by the C++ standard, so the code above is perfectly valid and calling p->get() with p of type BaseClass will call MyClass::get). If the more-derived type doesn't have the same top-address such as Complex1 and Complex2 above, when compared to Data1, then the compiler needs to generate a stub function (usually called a "thunk") to adjust the value of the pointer returned. It places the address to that thunk in the entry corresponding to the parent's virtual function in the virtual table. However, it also adds a new entry for calls made which return the new top-address.