Differences Between Clang-enhanced C++ Compilers and Previous-Generation C++ Compilers

From RAD Studio
Jump to: navigation, search

Go Up to Clang-enhanced C++ Compilers


This topic provides an overview of the differences between Clang-enhanced C++ compilers and their immediate predecessor, BCC32.

Command-Line Options

Clang-enhanced C++ compilers use an almost completely different set of command-line options, and a different way to express multiple values for the same option.

Stricter C++ Compiler

Clang-enhanced C++ compilers are more compliant with C++ language standards than BCC32. They provide C++11 support, but they are also more strict. See Stricter C++ Compilers (Clang-enhanced C++ Compilers).

Warnings and Error Messages

In addition to new, more specific and detailed warnings and error messages, Clang-enhanced C++ compilers phrase messages for conditions detected by BCC32 in a different way.

For more information, see Errors and Warnings of Clang-enhanced C++ Compilers.

Predefined Macros

Using Clang-enhanced C++ compilers you can get all the predefined macros directly from the preprocessor.

RTLVersion Macro

The RTLVersion constant is not supported by Clang-enhanced C++ compilers. Instead, you may use RTLVersionC.

NO_STRICT Macro

The NO_STRICT type checking scheme is not supported in Clang-enhanced C++ compilers. If you have existing projects that use the NO_STRICT conditional define, you need to remove it.

For more information and instructions for removing NO_STRICT, see: C++ Applications Use STRICT Type Checking.

#include Paths and Lookup

You might need to #include headers differently with Clang-enhanced compilers.

For example, Clang-enhanced C++ compilers do not find headers specified with semi-absolute paths as BCC32 does. Given that 'myOtherFile' is located at C/myProjectsDir/myOtherApp, the following references in a .CPP file are accepted by both Clang-enhanced C++ compilers and BCC32:

#include "c:/myProjectsDir/myApp/mySource.h" // Absolute path.
#include "../myApp/mySource.h" // Relative path.

However, the following yields an error with Clang-enhanced C++ compilers, but it is accepted by BCC32:

#include "/myProjectsDir/myApp/mySource.h" // Semi-absolute path.

Clang-enhanced C++ compilers emit the following error:

[<compiler> Fatal Error] myOtherFile.cpp(27): '/myProject/myApp/mySource.h' file not found

For more information, see Clang-enhanced C++ Compilers, #include Paths and Lookup.

Precompiled Headers

Compared to BCC32, precompiled headers work a little differently for Clang-enhanced C++ compilers. Each C++ project can have only one precompiled header, and a default precompiled header (named projectPCHn.h) is generated for each new C++ project.

For more information, see the following topics:

Object and Library File Format

  • BCC32 and its associated tools use OMF in .obj and .lib files.
  • Clang-enhanced C++ compilers use ELF in .o and .a files.

This difference means, for example, that when you migrate a 32-bit Windows applications you must change references to .lib and .obj files to be .a and .o, respectively.

__property: Compound and Chained Assignment

Clang-enhanced C++ compilers support compound assignment of __property, while BCC32 does not.

The objects of the keyword __property are not like fields or members. They should be used in simple assignments.

Although both BCC32 and the RAD Studio Clang-enhanced C++ compilers allow __property to be used in compound assignments such as:

Form1->Caption += DateToStr(Now());

BCC32 only invokes the getter, not the setter. Therefore we recommend that you avoid such constructs when targeting multiple platforms.

None of these compilers support the usage of __property in chained assignment, as in:

Button2->Caption = Button1->Caption = DateToStr(Now()); // Error

Deprecated BCC32 Extensions and Keywords

No-underscore and single-underscore compiler keyword extensions are either unsupported or deprecated in Clang-enhanced C++ compilers. Use the double-underscore versions (they are also supported in BCC32):

  • cdecl, _cdecl:    Use __cdecl.
  • pascal, _pascal:    Use __pascal.
  • _fastcall:    Use __fastcall, which is now Microsoft-style, not Borland-style.
  • _stdcall:    Use __stdcall.
  • _fortran, __fortran:    Not supported, obsolete.
  • asm, _asm, __asm:     Inline assembly is not supported.
  • _export:    Use __export.
  • _import:    Use __import.
  • _declspec:    Use __declspec.

Unsupported BCC32 Attributes

See Workaround for C++11 Attributes (noreturn and final).

Unicode Identifiers Are Not Supported

Although Unicode is supported in literal strings and file names, Unicode in identifiers is not allowed.

Inline Assembly

Clang-enhanced C++ compilers allow inline assembly with these caveats:

  • You cannot mix assembly with C++ code.
  • Do not touch the stack pointer (RSP).
  • The assembler must use the AT&T line-by-line syntax, not the more familiar block-of-Intel syntax. For more information, see GCC-Inline-Assembly-HOWTO.

Clang-enhanced C++ compilers support inline assembly in a different style than the inline assembly supported by BCC32:

  • Different Assembly syntax:
    The Assembly syntax supported by Clang-enhanced C++ compilers is line-by-line AT&T syntax, not the more familiar block-of-Intel syntax.
  • Potential exception handling and debugging problems:
The exception handling of the compiler places additional burdens on hand-written Assembly code intermixed with C++. Functions written entirely in assembly (with a separate assembler like NASM or MASM) can be linked into your program. However, there are inherent issues (potential exception handling and debugging problems) that you should know before you start.
The reasons for these issues for inline assembly can be summarized as: pdata. Lack of support for inline assembly is fairly common; for exceptions (and debugging) to work, code has to generate data structures (pdata) that describe each function and what must be unwound if an exception is thrown. After you insert inline assembly, the compiler is unaware of finer details (like any extra stack space the inline assembly allocated). Inline assembly (that is, mixing assembly and C/C++ code) makes it impossible for the compiler to accurately generate the pdata structures. For more information about pdata, see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx

For a code example illustrating how to use inline assembly with a Clang-enhanced C++ compiler, see Inline Assembly with BCC64 (C++).

For more information about assembly with Clang-enhanced C++ compilers, see:

Try Blocks Cannot Handle Some Exceptions

Synchronous exceptions are exceptions raised using a throw statement in your program or in the libraries that your program uses. Compilers know where and when these exceptions raise.
Asynchronous exceptions are exceptions that come from the operating system and may raise at any time, such as divisions by zero or access violations.

Standard C and C++ are designed to handle synchronous exceptions only. However, when your C++Builder applications link to the RTL, you are adding your applications the ability to catch asynchronous exceptions as well.

However, Clang is designed for synchronous exceptions only, and it does not support non-call exception handling. If a try block contains no throw statements and no calls to functions that may contain throw statements, Clang ignores any catch and finally blocks associated with that try block. That is, if a try block cannot throw any synchronous exception, you cannot catch any asynchronous exception in that try block either.

For example:

float a = 1;
float b = 0;
try {
    try {
        a = a / b;  // The RTL throws an asynchronous exception (division by zero).
    }
    __finally {
        // Execution never reaches this point.
    }
}
catch (...) {
    // Execution never reaches this point.
}

Instead of catching these special exceptions that Clang-enhanced compilers cannot handle, you should do either of the following:

  • Move the code that may raise an asynchronous exception to its own function and call that function from your try block.
  • Try to prevent these exceptions from ever raising. For example, you could check the value of b before you perform the division.
Note: If you do not handle asynchronous exceptions, the default exception handler of the GUI framework of your application catches them, and your application raises an External Exception EEFFACE.

See Also