User Changes 3.0

From Free Pascal wiki
Revision as of 01:05, 2 March 2020 by Trev (talk | contribs) (Fixed syntax highlighting; deleted category included in page template)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

English (en)

About this page

Listed below are intentional changes made to the FPC compiler (3.0) since the previous release that may break existing code. The list includes reasons why these changes have been implemented, and suggestions for how you might adapt your code if you find that previously working code has been adversely affected by these recent changes.

All systems

Implementation changes

Exception type for object reference checking changed

  • Old behaviour: When object reference checking (-CR or {$OBJECTCHECKS ON}) is enabled and the unit SysUtils is used then an exception of class Exception with localizeable message Unknown runtime error 210 is created.
  • New behaviour: Now an exception of class EObjectCheck with localizeable message Object reference is Nil is created.
  • Reason: All other runtime errors in the 2xx range have appropriate exception types, so it is only natural to have an explicit type for runtime error 210 as well.
  • Remedy: If your code previously checked an exception for the message Unknown runtime error 210 you should now check for the exception class EObjectCheck.

Literal storage memory has been made read-only

  • Old behaviour: read-only data segments were de facto not supported, and all data could be modified at runtime even if it was not intended for modification (except in some cases on Darwin). This could cause nasty side-effects, e.g the following code:
uses sysutils;
   s: ansistring;
   s := 'ansi string';
   s := 'ansi string';

would modify the contents of data segment and print

  • New behaviour: Data that is not intended to be modified at runtime is put into a read-only segment. This includes literal constants used in expressions and typed constants declared in {$J-} state. Any code which modifies such data (as in the above example) will now crash.
  • Reason: This is consistent with the way other compilers (including Delphi) work. Keeping data read-only as much as possible improves a program's loading speed because read-only pages can be mapped directly to the executable file. This also improves program security.
  • Remedy: is very code-dependent. In the example above, it is sufficient to call UniqueString(s) before AnsiStrUpper

UNICODE define depends on default string type instead of on target platform

  • Old behaviour: The compiler defined the preprocessor symbol UNICODE when targeting a Windows platforms that only has a unicode OS API (Windows CE and NativeNT).
  • New behaviour: The UNICODE define is now only set if the default string type is unicodestring (as opposed to shortstring or ansistring). This happens when the new {$mode delphiunicode} or {$modeswitch unicodestrings} are active. The target platform no longer has any influence.
  • Reason: In Delphi 2009 and newer the type String is defined as UnicodeString, and this can be determined by the fact that these Delphi versions also define the UNICODE symbol.
  • Remedy: Use {$ifdef FPC_OS_UNICODE} instead of {$ifdef UNICODE} to determine whether or not the OS only supports a unicode (UTF-16) API.

RTTI changes

RTTI for Pointers and Class References

  • Old behavior: Pointers and Class References had tkUnknown RTTI.
  • New behavior: Pointers now have RTTI type tkPointer, and class references have the RTTI type tkClassRef. Each now contains a reference to a type they point to.
  • Reason: Both user requests and Delphi compatibility.
  • Remedy: The TTypeKind enumeration has more members than before. Adjust any code which uses TTypeKind accordingly.

RTTI for AnsiStrings

  • Old behavior: AnsiString RTTI previously lacked CodePage information.
  • New behavior: A new CodePage member has been added for the tkAString type.
  • Reason: This is required for serializing/deserializing of published AnsiString properties, and is now compatible with Delphi.
  • Remedy: not known

RTTI for Arrays

  • Old behavior: tkArray had no member in the TTypeData record, although internally the compiler stored these members: first dimension size, first dimension element count and first dimension element type. So for a 2 dimension array element the type was array for the second dimension.
  • New behavior: tkArray now has a TArrayTypeData structure in TTypeData. It has the following members: total array size including all dimensions, total element count, last dimension element type, number of dimensions, type information for each dimension range.
  • Reason: This provides more comprehensive RTTI, and is compatible with Delphi.
  • Remedy: If your code internally used the older RTTI array information you will need to adapt it to take account of the newly provided TArrayTypeData information.

RTTI for Records

  • Old behavior: Records RTTI stored field Offsets as 32bit integers.
  • New behavior: Records RTTI stores field Offsets as platform-dependent integers (the same size as pointers).
  • Reason: Internally the compiler stores Offsets as platform-dependent integers. The new behaviour is Delphi-compatibile.
  • Remedy: You need to adjust your code if you used field offsets of record RTTI. This is also true if your code processes any vInitTable field within the VMT of a class.

RTTI for Procedural Variables

  • Old behavior: tkProcVar lacked any member in the TTypeData record and the compiler stored no information about procedural variables.
  • New behavior: tkProcVar now has a new TProcedureSignature structure in TTypeData which contains information about the procedure's calling convention, result type and parameters (where applicable).
  • Reason: User request. More informative RTTI. Delphi compatibility.
  • Remedy: not known
Usage example
program RTTIInfo;

{$mode objfpc}{$H+}

  CP866String = type AnsiString(866);
  TProc = procedure(var A: Integer; S: String); stdcall;
  TColor = (red, green, blue);
  TArr = array[TColor,0..3] of Integer;
  PArr = ^TArr;

procedure DescribeProcedure(Info: PTypeInfo);
  ParamFlagToStr: array[TParamFlag] of AnsiString = (
  CallConvToStr: array[TCallConv] of AnsiString = (
  Data: PTypeData;
  Param: PProcedureParam;
  ParamFlag: TParamFlag;
  I: Integer;
  Res, S, TypeName: String;
  if Info^.Kind <> tkProcedure then
  Data := GetTypeData(Info);
  if Data^.ProcSig.CC <> ccStdCall then
  if Data^.ProcSig.ResultType <> nil then
    Res := 'function ' + Info^.Name;
    TypeName := ': ' + Data^.ProcSig.ResultType^.Name;
    Res := 'procedure ' + Info^.Name;
    TypeName := '';
  if Data^.ProcSig.ParamCount > 0 then
    Res := Res + '(';
    for I := 0 to Data^.ProcSig.ParamCount - 1 do
      Param := Data^.ProcSig.GetParam(I);
      S := '';
      for ParamFlag in TParamFlags(Param^.Flags) do
        S := S + ParamFlagToStr[ParamFlag] + ' ';
      S := S + Param^.Name + ': ' + Param^.ParamType^.Name;
      if I > 0 then
        Res := Res + '; ';
      Res := Res + S;
    Res := Res + ')';
  Res := Res + TypeName + '; ' + CallConvToStr[Data^.ProcSig.CC] + ';';

procedure DescribeAnsiString(Info: PTypeInfo);
  Data: PTypeData;
  if Info^.Kind <> tkAString then
  Data := GetTypeData(Info);
  if Data^.CodePage = 0 then
    WriteLn('type AnsiString(',Data^.CodePage,');');

procedure DescribeArray(Info: PTypeInfo);
  Data: PTypeData;
  Res: String;
  I: Integer;
  if Info^.Kind <> tkArray then
  Data := GetTypeData(Info);
  Res := 'array[';
  for I := 0 to Data^.ArrayData.DimCount - 1 do
    if I > 0 then
      Res := Res + ', ';
    Res := Res + Data^.ArrayData.Dims[I]^.Name;
  Res := Res + '] of ' + Data^.ArrayData.ElType^.Name + ';';

procedure DescribePointer(Info: PTypeInfo);
  Data: PTypeData;
  if Info^.Kind <> tkPointer then
  Data := GetTypeData(Info);
  if Data^.RefType = nil then
    WriteLn('^', Data^.RefType^.Name, ';');


Unit changes


TBookmark TBookmarkstr and TDataset.Bookmark change to Delphi2009+ compatible definitions
  • Old behaviour: TDataset.Bookmark was of type TBookmarkstr, TBookmarkstr=string, Tbookmark=pointer
  • New behaviour: TDataset.Bookmark is of type TBookmark, TBookmarkstr=ansistring, TBookmark=TBytes. TBookmarkstr will trigger a deprecated warning.
  • Reason: D2009+ compatibility, where probably the fact that string became a 2-byte encoding was the trigger.
  • Remedy: Adjust typing in descendents and using code accordingly.
TBufDataset.SaveToFile, SaveToStream: Binary Format (dfBinary) of saved data changes
  • Old behaviour: Record data was saved to stream just as they exist in the TBufDataset memory record buffer.
  • New behaviour: Record data are saved field by field. Each variable length field begins with a 4 byte length indicator followed by data. Fixed length fields are stored without prefixed length indicator. LoadFromFile, LoadFromStream support both formats (OLD and NEW).
  • Reason: BLOBs were not saved correctly in the OLD format: instead of BLOB data, a pointer to memory where BLOB data resided was saved.
  • Remedy: if you need the OLD behavior in saving, you must register your own DataPacketReader using RegisterDatapacketReader procedure.
unit OldBinaryDatapacketReader;

{$mode objfpc}{$H+}


  Classes, SysUtils, BufDataset;


  { TOldFpcBinaryDatapacketReader }

  TOldFpcBinaryDatapacketReader = class(TFpcBinaryDatapacketReader)
    constructor Create(AStream : TStream); override;


{ TOldFpcBinaryDatapacketReader }

constructor TOldFpcBinaryDatapacketReader.Create(AStream: TStream);
  FVersion := 10;

  RegisterDatapacketReader(TOldFpcBinaryDatapacketReader, dfBinary);
TDataPacketReader class structure changes
  • Old behaviour:
  • New behaviour: reference to TCustomBufDataset is passed only once in constructor of TDataPacketReader and stored in instance TDataPacketReader.
  • Reason: simplify design and make it more flexible
  • Remedy: if you use your own TDataPacketReader descendant update method signatures
TSQLScript supports :, backtick quotes and explicit COMMIT/COMMIT RETAIN
  • Old behaviour:
    • TSQLScript parsed words starting with : in SQL as if they were sqldb parameters; running the resulting statements would very likely fail, making the class unusable.
    • With UseCommit set, once a COMMIT directive was found, CommitRetaining is run instead of Commit. This lead to problems with scripts that need a hard commit (e.g. Firebird DDL followed by DML).
    • TSQLScript did not support backtick quotes (`), e.g. for MySQL
  • New behaviour:
  • Parser improvement: comments starting with -- are detected as comments
    • words starting with : are not parsed as sqldb parameters.
    • if UseCommit is set, COMMIT WORK or COMMIT leads to Commit; the new directive COMMIT RETAIN (or no directive) leads to CommitRetaining being executed
    • TSQLScript supports backtick quotes (`), e.g. for MySQL
  • Reason: usability, compatibility with scripts generated by 3rd party packages.
  • Remedy:
    • if your code depended on : parameter parsing, you could use a TSQLEventScript class and manipulate the SQL.
    • commit behaviour: check your scripts for any unexpected COMMIT RETAIN statements.
TMySQLxxConnection ( VARCHAR columns are always mapped to TStringFields
  • Old behaviour: varchar columns with length > 8192 (dsMaxStringSize) were re-mapped to TMemoFields
  • New behaviour: varchar columns are always mapped to TStringFields
  • Reason: Honour server definition and map column data types as reported by server
  • Remedy: If you use varchar with length > 8192 and you have field definitions stored in lfm, update them.
TSQLite3Connection INTEGER PRIMARY KEY columns are mapped to TAutoIncFields
  • Old behaviour: INTEGER columns, which are also PRIMARY KEY were mapped to TIntegerField
  • New behaviour: INTEGER columns, which are also PRIMARY KEY are now mapped to TAutoIncField
  • Reason: Tables with INTEGER columns, which are also PRIMARY KEY are in SQLite alias for ROWID. And ROWID columns have autoincrement capability. For more details see: and
  • Remedy:
TSQLite3Connection: Boolean True values are stored as 1 not as -1
  • Old behaviour: Boolean True parameters was bind as integer = -1.
  • New behaviour: Boolean True parameters are bind as integer = 1. As expected by SQLite: "SQLite does not have a separate Boolean storage class. Instead, Boolean values are stored as integers 0 (false) and 1 (true)."
  • Reason: Align with SQLite specification and also with others DB components (like SQLite3DataSet), which expect True=1
  • Remedy: Check your applications and if your tables contain boolean columns which are part of primary key or you use in WHERE clause constructs like "boolean_column=:boolean_param" then you must take attention to fix database or use construct like: "ABS(boolean_column)=:boolean_param"

FileNameCaseSensitive and FileNameCasePreserving in unit System

  • Old behaviour: There was only one constant (FileNameCaseSensitive) which signalized behaviour of the respective target platform with regard to the case in filenames. This was often set to true also on platforms not really treating filenames in case sensitive manner (e.g. Win32 and Win64).
  • New behaviour: FileNameCaseSensitive is set to true only on platforms which really treat filenames in case sensitive manner and FileNameCasePreserving constant is added to unit system of all platforms to signalize whether the case in filenames supplied when creating or renaming them is preserved or not. This might possibly break existing user code relying on the previous (sometimes incorrect) value of FileNameCaseSensitive.
  • Reason: In reality, there are two distinct types of behaviour. If a platform is case sensitive, searching for file "a" will never result in finding file "A" whereas case insensitive platform will happily return "A" if such a file is found on the disk. If a platform is case preserving, it will store file "a" as "a" on disk whereas case non-preserving platform may convert the filenames to uppercase before storing them on disk (i.e. file "a" is in reality stored as "A"). Case non-preserving platforms are never case sensitive, but case preserving platforms may or may not be case sensitive at the same time.
  • Remedy: Review your existing code using FileNameCaseSensitive, check which of the two properties described above fit the particular purpose in your case and change to FileNameCasePreserving where appropriate.

Some longtime deprecated functions in unit Unix have been removed.

  • Old behaviour: Unix.(f)statfs, and Unix.fsync symbols existed in unit Unix
  • New behaviour: Unix.(f)statfs, and Unix.fsync were removed
  • Reason: These were helper functions and leftovers from the 1.0.x->2.0.0 conversion, deprecated since 2007. Shell had non standarized conventions
  • Remedy: All but shell: use the same functions with an "fp" prefix. Shell: use fpsystem. If you checked the return value for other values than -1, a modification of the error checking might be necessary. Refer to your *nix documention, or have a look at the transformfpsystemtoshell function in tests/util/redir.pp in the FPC sources to see what a quick fix looks like.

statfs has been renamed to fpstatfs

  • Old behaviour: One overload of fpstatfs was not renamed from statfs to fpstatfs (around 2.4.0)
  • New behaviour: The function has been renamed.
  • Reason: Should have been done in 2.4.0 to begin with, but was postponed several times to coincide with a major version change.
  • Remedy: Use fpstatfs

RTLeventsync has been removed

  • Old behaviour: The thread manager record contained an rtleventsync field, and the RTL had an RTLeventsync routine. No functionality for this routine was implemented in the FPC-supplied thread manager for any platform.
  • New behaviour: The field and routine have been removed.
  • Reason: The functionality was not available on any platform by default, and we're not aware of any third party thread manager that implemented them or third party code that relied on it. Additionally, the routine was documented as "Obsolete. Don't use.", without any explanation of what it was supposed to do.
  • Remedy: Remove any such calls from your code.

TVersionInfo (fileinfo unit) re-implemented in a platform independent way

  • Old behaviour: GetVersionSetting method would read file information.
  • New behaviour: The ReadFileInfo call will read the information. The global GetProgramVersion call will extract the program major/minor/revision/build version in 1 single call.
  • Reason: The unit now uses FPC resources on all platforms, and can now be used to read external resources.
  • Remedy: Use the ReadFileInfo call to get the version information. Add relevant units for desired resource support to your uses clause; e.g. if you need to read Windows .exe file info, add winpeimagereader

shlobj symbols removed from unit Windows

  • Old behaviour: When unit windows was split between the windows and shlobj units, not all shlobj symbols were removed from Windows.
  • New behaviour: shlobj symbols has been removed from the windows unit. Code relying on that will fail to compile if it doesn't import shlobj.
  • Reason: shlobj and windows versions were not compatible and lead to errors.
  • Remedy: put shlobj in your uses clause, if not there already.

process OnForkEvent implementation

  • Old behaviour: Signature was a simple procedure.
  • New behaviour: TNotifyEvent -compatible signature for the call.
  • Reason: It was impossible to know the TProcess instance for which the fork was called, and hence impossible to parametrize the procedure.
  • Remedy: Change the signature of your callback to match a TNotifyEvent

Extention -> Extension typo fix

  • Old behaviour: The incorrect term Extention (typo) was used in the interface of several units: fpimage, sndfile.
  • New behaviour: The correct term Extension is now used.
  • Reason: Why have code with incorrect English?
  • Remedy: Change extention to extension.

SysUtils: File names starting with a period are not considered to be extensions

  • Old behaviour: File names that start with a period were considered to only have an extension and no base file name by ExtractFileExt() and ChangeFileExt()
  • New behaviour: By default, the portion of the filename starting with the period up till the next period (if any) or end of the file name is now considered to be the file name, and the rest is considered by the extension. Note that this behaviour is not Delphi-compatible.
  • Reason: Change behaviour to match file system/OS conventions.
  • Remedy: There is a new a variable FirstDotAtFileNameStartIsExtension. By default, it is set to false, which corresponds to the new behaviour. If it is set to true, the aforementioned routines revert to the old behaviour.

System: Error messages are now written to stderr

  • Old behaviour: On error, the binaries halted and wrote an error message to standard output.
  • New behaviour: On error, the binaries halt and write an error message to standard error .
  • Reason: Change behaviour to match OS conventions. Diagnostic output should be written to standard error.
  • Remedy: A system unit variable WriteErrorsToStdErr can be set to 'False' and then the output is written to standard output, as it was.

TZipper: writes zip files with zip standard / instead of \ directory separators

  • Old behaviour: on Windows (only), TZipper would write \ to the zip file when paths were used. This does not conform to the zip standard though many utilities would accept this. However, it is not according to the standard and leads to problems with e.g. LibreOffice reading .xlsx files generated by fpspreadsheet.
  • New behaviour: TZipper writes / when paths are used; it still accepts \ for reading on Windows. Note: on Windows, TZipper still accepts / as path separator when reading zip files for compatibility with buggy third party code.
  • Reason: standards compliance, interoperability.
  • Remedy: if you need to interoperate with 3rd party tools that require zip files with \, please copy all code in \packages\paszlib\src and edit procedures SetArchiveFileName, SetDiskFileName

Language Changes

AnsiStrings are now codepage-aware

  • Old behaviour: The codepage of an AnsiString was always be assumed to be the default system (single byte) code page. The predefined Utf8String type was just an alias for AnsiString and did not behave differently in any way.
  • New behaviour: Every AnsiString constant or variable now also has an associated code page, which governs how its data is interpreted. The predefined Utf8String type is now tagged with the UTF-8 codepage identifier.
  • Reason: Delphi 2009+ compatibility.
  • Remedy: This new feature generally works transparently, but there are some caveats:
    • Avoid using AnsiString variables to store data not encoded using the DefaultSystemCodePage encoding without also setting the corresponding code page (such as currently done in Lazarus). For example, assume an AnsiString with a dynamic code page different from CP_UTF8 (e.g. CP_ACP) contains UTF-8 data. If it is then converted to a different code page, e.g. because it's passed to a routine expecting a UnicodeString or Utf8String parameter, then the UTF-8 data in the string will be "converted" from CP_ACP to UTF-8, thereby corrupting the string data (if CP_ACP is different from UTF-8).
    • Routines that are declared with a plain AnsiString parameter will cause passed custom code page strings to be converted to DefaultSystemCodePage, possibly resulting in data loss. We have a list of RTL routines that have been updated to correctly handle strings encoded in any code page.
  • More information: FPC Unicode support

Variant overload preference for string types

  • Old behaviour: Preference for string types was (from better to worse): ShortString, AnsiString, WideString, UnicodeString
  • New behaviour: Preference for string types now (from better to worse): WideString, UnicodeString, AnsiString, ShortString
  • Reason: Unicode characters and codepage information will not be lost during the conversion; unicode Delphi compatibility.
  • Remedy: Use explicit conversion (e.g. ShortString(V)) if it is needed to pass variant to routine with a particular string type argument.

Variant conversion preference for widechar

  • Old behaviour: If a widechar was passed to a variant parameter, it would be wrapped as a word (D7 compatible).
  • New behaviour: A widechar passed to a variant parameter is now convert it to a unicodestring (D2009+ compatible).
  • Reason: Newer Delphi version compatibility.
  • Remedy: Use explicit conversion (e.g. integer(V)) if needed. We decided against differentiating this behaviour between {$mode delphi} and {$mode delphiunicode} because the compatibility advantage does not outweigh implementation complexity.

Default values in implementation but not in interface/forward declaration

  • Old behaviour: The implementation of a routine could declare default values even if the interface declaration did not have any.
  • New behaviour: Default values, if any, must be specified in the interface. They can be repeated in the implementation, but that is not required (just like it was not in the past).
  • Reason: Default parameters specified only in the implementation are not, and cannot, be propagated to the interface since a unit's interface can be used before the implementation has been parsed (see, Delphi compatibility.
  • Remedy: Always specify default parameter values (also) in the interface/forward declaration of a routine.

Default values are now properly typechecked

  • Old behaviour: The compiler did not detect default values for parameters of which the type did not in any way correspond to the parameter type.
  • New behaviour: The compiler now properly checks whether the type of the constant matches the parameter's type when parsing default values.
  • Reason: Proper type checking is one of the fundamental properties of the Pascal language; Delphi compatibility.
  • Remedy: Add a typecast around default values that now result in compiler errors, or correct the type of such parameters.

"strict protected" visibility modifier

  • Old behaviour: strict protected did not correctly limit the visibility of symbols declared in different units.
  • New behaviour: strict protected symbols can now only be accessed from descendent classes, regardless of where they are defined.
  • Reason: Fix behaviour to conform to specification/documentation, Delphi compatibility.
  • Remedy: Use protected or public if less strict accessibility checks are desired.

Support for type helpers added

  • Old behaviour: In modes ObjFPC and MacPas it was possible to declare a unique type of a type helper.
  • New behaviour: The compiler now interprets the keyword helper as a helper type if it immediately follows the type keyword (but only if the mode is ObjFPC or MacPas or the mode switch Class is set).
  • Example:
{$mode objfpc}
  helper = LongInt;

  otherhelper = type helper;

The above code will no longer compile.

  • Reason: type helper is a more logical way to declare helpers for primitive types than Delphi's record helper is.
  • Remedy: Escape the keyword helper using a &. E.g.:
{$mode objfpc}
  helper = LongInt;

  otherhelper = type &helper;

"strict protected" and "protected" visibility modifier in extended records

  • Old behaviour: strict protected and protected could be used used in extended records.
  • New behaviour: strict protected and protected are no longer allowed in extended records.
  • Reason: The only difference between (strict) protected and (strict) private is that the former allows you to access members of a parent class or object. As records don't support inheritence it makes no sense to support (strict) protected in them. This is also Delphi-compatible.
  • Remedy: Use private instead of protected and strict private instead of strict protected.

"static" directive on non-class methods

  • Old behaviour: It was possible to use the static on normal, non-class methods
  • New behaviour: The compiler now generates an error if static is used on normal, non-class methods (except in object types)
  • Reason: It is only correct to leave out the Self parameter if it is a class method. This is also Delphi compatible.
  • Remedy: Prepend the class keyword to the method.

"static" directive on class operators

  • Old behaviour: It was possible to use the static on class operators.
  • New behaviour: The compiler now generates an error if static is used on class operators.
  • Reason: Class operators are by definition static, thus the static would be redundant. This is also Delphi compatible.
  • Remedy: Remove the static keyword from class operators.

Classes implementing forward-declared interfaces

  • Old behaviour: It was possible to declare classes as implementing a forward-declared interface.
  • New behaviour: Classes can no longer implement forward-declared interfaces.
  • Reason: This occasionally caused crashes, the compiler did not check in such a case whether the class actually implemented the methods of that interface. Recent versions of Delphi also reject such constructs.
  • Remedy: If there is a cyclic dependency between a class and an interface, use a forward declaration for the class instead.

Using the function name as alias for loading its current result value in MacPas mode

  • Old behaviour: Inside a function the name of the function could be used on the right hand side (RHS) of an expression in order to refer to the current value of the function result.
  • New behaviour: Using the name of a function on the RHS of an expression inside that function's body now always results in a recursive function call.
  • Reason: The old behaviour existed because under some circumstances CodeWarrior behaved that way. Under other circumstances it however behaves according to the new rule and there appears to be no definition available of when it does what. Since it is easier to fix a compilation error than to find out where an intended recursive function call is not doing anything, we opted to change the behaviour.
  • Remedy: Either use a temporary local variable to hold the function result if you want to reuse it on the RHS of other expressions, or add {$modeswitch result} and use the result pseudo-variable as an alias for the function result.

nostackframe forbidden for Pascal subroutines

  • Old behaviour: The nostackframe directive could be applied to all types of subroutines.
  • New behaviour: The nostackframe directive is allowed only for pure assembler subroutines,
  • Reason: Depending on the architecture, ABI and code of the subroutine, nostackframe might have worked or caused random crashes. This was unpredictable and makes no sense.
  • Remedy: Remove the nostackframe from Pascal subroutines. In any case, if the compiler can omit the stack frame, it will do so.

Conversion preference of pansichar to various string types

  • Old behaviour: In {$h-} mode, the compiler preferred pansichar->shortstring to pchar->ansistring conversions, and gave pansichar->ansistring and pchar->unicodestring the same conversion preference.
  • New behaviour: The compiler now always prefers pansichar->ansistring to pansichar->shortstring, and also prefers pansichar->ansistring to pansichar->unicodestring (which it in turn prefers to pansichar->shortstring).
  • Reason: Prevent truncation of long pchars, make it easier to add unicodestring overloads to the RTL without causing can't decide which overloaded function to call errors when using pchars, Delphi compatibility.
  • Remedy: Use strpas() to explicitly truncate pchars to shortstrings if desired.

Comparative operators can have any result type

  • Old behaviour: Overloaded comparative operators could only have a Boolean result type.
  • New behaviour: Overloaded comparative operators can have any result type.
  • Reason: The result type is checked by the regular type checking mechanism. For example, overloaded comparative operators that return non-Boolean results cannot be used in IF, WHILE or UNTIL expressions, but it is still possible to use them in other situations. This is also Delphi compatible.
  • Example:
SQLResult := Database.Query(
    [ PersonsTable.FirstName, PersonsTable.LastName ],
    [ PersonsTable ],
      PersonsTable.Country = 'NL',
      PersonsTable.Age >= 25
  • Remedy: Not applicable.

True and False are not keywords anymore

  • Old behaviour: True and False were keywords and as a result it was not possible to use them as identifiers.
  • New behaviour: True and False are now predefined constants in the system unit's scope and can be used as identifiers.
  • Example:
  False = 0;
  True = 1;
  • Reason: Compatibility with other Pascal compilers.
  • Remedy: Not applicable.

For-in loop variable cannot be assigned to anymore

  • Old behaviour: Inside a for X in Y loop it was possible to assign a value to X. This was different from the for X:=A to B loop, where assigning to the loop variable X was not allowed.
  • New behaviour: The variable X of a for X in Y loop cannot be changed.
  • Reason: Compatibility with for X:=A to B loop.
  • Remedy: Use a temporary variable instead.

Casting integer variables to floating point

  • Old behaviour: Explicitly typecasting an integer variable to a floating point type of the same size caused the bit pattern of the integer to be reinterpreted as a floating point value.
  • New behaviour: Such explicit typecasts now result in a conversion of the integer value to an equal floating point value (to the extent that the floating point type can represent the integer value)..
  • Example: The following program now prints twice " 1.3890388970000000E+009", while previously the first writeln printed " 6.86276399744918E-315"
  i: int64;
  • Reason: Consistency with the behaviour of a compile-time integer to floating point conversions, as demonstrated by the above example.
  • Remedy: Add an intermediate typecast to a record type to reinterpret the actual bit pattern.

Unix platforms

cthreads: critical sections and recursive mutex support

  • Old behaviour: If the cthreads unit thread manager was used on a platform without recursive mutex support, critical sections were non-reentrant.
  • New behaviour: Initialising a critical section under the above circumstances will now result in a run time error.
  • Reason: One of the basic properties of (Delphi/Windows-compatible) critical sections is that they are reentrant, and that is how they are generally used in Pascal code.
  • Remedy: Use an RTLEvent instead if reentrancy is not required.

Darwin platforms

Location of certain function result types on Darwin/i386 and iPhoneSim/i386

  • Old behaviour: Small records and method pointers were always returned according to the official ABI.
  • New behaviour: When a calling convention other than cdecl, cppdecl or mwpascal is used, the same convention as on other platforms is now used.
  • Reason: Better compatibility with assembler code written for other platforms.
  • Remedy: Update your assembler code, or better: if possible, convert it to Pascal.

Default assembler for Darwin/i386/x86_64/ARM and iPhoneSimulator/i386/x86_64

  • Old behaviour: The default assembler for these platforms was the as binary.
  • New behaviour: The default assembler for these platforms now is the clang binary.
  • Reason: Xcode 7 no longer includes the old assembler, and the as binary now simply invokes clang. Additionally, Xcode 7 now requires the compiler to specify the OS variant (OS X, iOS) and version to the assembler, which was not possible with the as binary that shipped with older Xcode versions. In order to disambiguate between an assembler that does and that does not support these options, we now explicitly invoke clang with these options.
  • Remedy: If you have an older version of Xcode and wish to use the old assembler, you can use the -Aas-darwin command line option.

Default debug format for Darwin/i386

  • Old behaviour: The default debug format for Darwin/i386 was Stabs.
  • New behaviour: The default debug format for Darwin/i386 is DWARF 2.
  • Reason: The assembler included with Xcode 7 and later no longer supports Stabs.
  • Remedy: If you have an older version of Xcode and wish to use Stabs, you can use -Aas-darwin -gs to force the use of the old assembler in combination with Stabs.

MacOSAll unit: changed parameter and opaque types

  • Change: The headers have been updated to the Mac OS X 10.8 SDK, and in this process a number of signatures have been changed/corrected, and several opaque types have been changed from ^SInt32 into pointers to different/incompatible empty records.
  • Reason: The reasons for the signature changes are detailed below. The opaque types have been made incompatible so that the compiler can give error messages when trying to use one opaque type instead of another (e.g., in the past the compiler did not complain when passing a ControlRef to a routine that expected a WindowPtr).
  • Remedy: Adjust your code to conform to the new signatures. Regarding the opaque types, that means that these types are no longer assignment-compatible. Some of the more prominent ones that may affect existing, correct, code are HIObject and ControlRef=HIViewRef. This may require adding typecasts to keep code compiling (the same typecasts are required in C)
  • Changes: (apart from the opaque type changes)
    • CGGLContextCreate : fixed first parameter (was "var", now is value parameter)
    • CFHostGetAddressing: var hasBeenResolved: boolean -> booleanptr because can be nil
    • CFHostGetNames: var hasBeenResolved: boolean -> booleanptr because can be nil
    • ColorSyncIterateInstalledProfiles: var seed: UInt32 -> UInt32Ptr because can be nil
    • AudioStreamGetPropertyInfo: outSize and outWritable changed to pointer because can be nil
    • cblas (several var-parametes changed to pointers because they represent arrays):
      • cblas_sswap, cblas_dswap: X, Y
      • cblas_scopy, cblas_dcopy: Y
      • cblas_saxpy, cblas_daxpy: Y
      • catlas_saxpby, catlas_daxpby: Y
      • catlas_sset, catlas_dset: X
      • cblas_sscal, cblas_dscal: X
      • cblas_sgemv, cblas_dgemv: X
      • cblas_strmv, cblas_dtrmv: X
      • cblas_stbmv, cblas_dtbmv: X
      • cblas_stpmv, cblas_dtpmv: Ap, X
      • cblas_strsv, cblas_dtrsv: X
      • cblas_stbsv, cblas_dtbsv: X
      • cblas_stpsv, cblas_dtpsv: Ap, X
      • cblas_ssymv, cblas_dsymv: X
      • cblas_ssbmv, cblas_dsbmv: Y
      • cblas_sspmv, cblas_dspmv: Ap, Y
      • cblas_sger, cblas_dger: A
      • cblas_ssyr, cblas_dsyr: A
      • cblas_sspr, cblas_dspr: Ap
      • cblas_ssyr2, cblas_dsyr2: A
      • cblas_sspr2, cblas_dspr2: A
      • cblas_sgemm, cblas_sgemm: C
      • cblas_ssymm, cblas_Dsymm: C
      • cblas_ssyrk, cblas_dsyrk: C
      • cblas_ssyr2k, cblas_dsyr2k: C
      • cblas_strmm, cblas_dtrmm: B
      • cblas_strsm, cblas_strsm: B
    • vBLAS (idem)
      • SDOT: X, Y
      • SNRM2: X
      • SASUM: X
      • ISAMAX: X
      • SSWAP: X, Y
      • SCOPY: X, Y
      • SAXPY: X, Y
      • SROT: X, Y
      • SSCAL: X
      • SGEMV, A, X, Y
      • SGEMM: A, B, C
    • vDSP (idem)
      • vDSP_sve_svesq, vDSP_sve_svesqD: __vDSP_A
      • vDSP_normalize, vDSP_normalizeD: __vDSP_A, __vDSP_C

Windows 9x series

Windows 9x series unsupported

  • Old behaviour: While 2.6.x formally didn't support the Windows 9x Series, 3rd party maintenance kept most FPC 2.6.x versions working with the Windows 9x series (Windows 95, 98/98SE, ME), and problems were the exception rather than the rule.
  • New behaviour: Starting from this compiler version, the Windows 9x series is not supported anymore.
  • Reason: the Windows 9x series has been discontinued for a long time; there is no support (including support for newer Windows features) and no Microsoft online documentation. Supporting this platform has been increasingly difficult due to this and the number of users/developers interested in performing the development/test work.
  • Remedy: users that want to use FPC for Win9x development can continue to use earlier compiler versions (e.g. FPC 2.6.4).


Exception handling has been changed to be ABI-conformant

  • Old behaviour: Exceptions were handled using platform-independent mechanism based on SetJmp/LongJmp.
  • New behaviour: Exceptions are handled using OS-provided means. The most important differences from generic handling are as follows:
    • Every executable contains a .pdata section describing layout of function stack frames. This data is used to perform stack back-tracing. As a consequence, the backtraces generated when exception occurs are no longer dependent of code optimization settings. However, they may be different from ones produced by gdb.
    • GNU binutils have troubles creating executables with .pdata sections. In particular, ld version < 2.22 crashes at such executables, and using GNU as together with internal linker will strip all .pdata, resulting in a non-working executable.
    • An exception is handled in two phases. First phase determines the target frame (i.e. the 'except' statement that will handle the exception), the second phase does actual stack unwinding and executing code in 'finally' statements. In contrast, the generic mechanism is single-phase: it starts unwinding immediately and proceeds until an 'except' statement handles the exception or the stack runs out.
  • Reason: Multiple compatibility issues with Windows and third-party DLLs (see and related issues)
  • Remedy: No changes are necessary unless your code relies on specific exception handling details. Build programs using FPC's internal assembler and linker, do not use GNU binutils. The entire feature can be disabled by cycling the compiler with OPT=-dDISABLE_WIN64_SEH in command line.

winwidestringalloc has been deprecated

  • Old behaviour: The winwidestringalloc variable enabled switching the WideString behaviour on Windows between COM BSTR (if set to true) and an internal UnicodeString-like container (if set to false).
  • New behaviour: The winwidestringalloc"" has been deprecated and will be removed completely from the RTL code in the future.
  • Reason: This setting predates the availability of the separate UnicodeString types, and was meant to enable Windows targets to use reference counted long strings. Nowadays, the UnicodeString type is available as an alternative on all platforms.
  • Remedy: Check whether you set winwidestringalloc := false in your program code and if so, replace all WideString declarations with UnicodeString.


Define UNICODE was changed to FPC_OS_UNICODE

  • Old behaviour: For arm-wince and i386-wince UNICODE was defined by default.
  • New behaviour: For arm-wince and i386-wince FPC_OS_UNICODE is defined by default.
  • Reason: For upcoming support for setting String to UnicodeString, the define UNICODE now is defined if the type String is currently defined as UnicodeString. This is also increases Delphi compatibility, as UNICODE is defined from Delphi 2009 on.
  • Remedy: Check for FPC_OS_UNICODE to decide whether the OS only provides a Unicode API (in the sense of Wide- or UnicodeString) and use UNICODE to decide whether the type String is currently defined as UnicodeString or not.


Stabs support has been disabled for 64 bit targets

  • Old behaviour: While the default debug information format for 64 bit targets was DWARF (except for AIX, where it's Stabx), it was possible to switch it to Stabs via the -gs command line parameter.
  • New behaviour: Only the DWARF debug format is still supported on 64 bit targets (except for AIX, where Stabx is used).
  • Reason: Stabs is not well-defined for 64 bit targets, nor well-supported by gdb on those same targets. This can lead to problems
  • Remedy: Do not use -gs when compiling for 64 bit targets. If you do so anyway, the compiler will display a warning and keep the previously set (supported) debug format.

Previous release notes