View Issue Details

IDProjectCategoryView StatusLast Update
0033603FPCCompilerpublic2019-07-13 18:23
ReporterOndrej PokornyAssigned To 
PrioritynormalSeverityminorReproducibilityN/A
Status newResolutionopen 
Product Version3.1.1Product Build 
Target VersionFixed in Version 
Summary0033603: [Feature, patch] Introduce the AS operator for arbitrary enumeration types
DescriptionThe following patch introduces the AS operator for arbitrary enumeration types - a new built-in conversion from integer to enum with range check.

A test unit for FPC test suite is included as well.
Steps To Reproducetype
  TMyEnum = (zero, one, two);
var
  E: TMyEnum;
begin
  E := 1 as TMyEnum; // OK
  E := -1 as TMyEnum; // error 219
end;
Additional InformationAs discussed in fpc-mailing list:

http://lists.freepascal.org/pipermail/fpc-devel/2017-July/038029.html
http://lists.freepascal.org/pipermail/fpc-devel/2017-July/038030.html
Tagscompiler, enumeration, Feature, patch, range checks
Fixed in Revision
FPCOldBugId
FPCTarget
Attached Files
  • AS-enum-01.patch (3,068 bytes)
    Index: compiler/ncnv.pas
    ===================================================================
    --- compiler/ncnv.pas	(revision 38690)
    +++ compiler/ncnv.pas	(working copy)
    @@ -4281,6 +4281,18 @@
                       end;
                   end;
               end
    +        else if (right.resultdef.typ=enumdef) then
    +          begin
    +            { left must be an ordinal }
    +            if not is_ordinal(left.resultdef) then
    +              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
    +            case nodetype of
    +              isn:
    +                resultdef:=pasbool8type;
    +              asn:
    +                resultdef:=right.resultdef;
    +            end;
    +          end
             else
               CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
           end;
    @@ -4450,6 +4462,15 @@
                   call := ccallnode.createinternres('fpc_do_as',
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef)
    +            else if (right.resultdef.typ=enumdef) then
    +            begin
    +              Writeln(tenumdef(right.resultdef).min, ':', tenumdef(right.resultdef).max);
    +              call := ccallnode.createinternres('fpc_do_as_enum',
    +                ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
    +                  ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
    +                    ccallparanode.create(left, nil))),
    +                resultdef)
    +            end
                 else
                   begin
                     if is_class(left.resultdef) then
    Index: rtl/inc/compproc.inc
    ===================================================================
    --- rtl/inc/compproc.inc	(revision 38690)
    +++ rtl/inc/compproc.inc	(working copy)
    @@ -798,6 +798,7 @@
     
     procedure fpc_AbstractErrorIntern;compilerproc;
     procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
    +function fpc_do_as_enum(value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
     
     {$ifdef FPC_HAS_FEATURE_FILEIO}
     Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
    Index: rtl/inc/system.inc
    ===================================================================
    --- rtl/inc/system.inc	(revision 38690)
    +++ rtl/inc/system.inc	(working copy)
    @@ -1528,6 +1528,19 @@
     
     
     {*****************************************************************************
    +                       (I as TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_as_enum(value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
    +begin
    +  if (value>=minvalue) and (value<=maxvalue) then
    +    result:=value
    +  else
    +    handleerroraddrframeInd(219,get_pc_addr,get_frame);
    +end;
    +
    +
    +{*****************************************************************************
                            SetJmp/LongJmp support.
     *****************************************************************************}
     
    
    AS-enum-01.patch (3,068 bytes)
  • ValidEnumAS.lpr (1,567 bytes)
  • AS-IS-enum-02.patch (6,628 bytes)
    Index: compiler/ncnv.pas
    ===================================================================
    --- compiler/ncnv.pas	(revision 38690)
    +++ compiler/ncnv.pas	(working copy)
    @@ -4281,6 +4281,18 @@
                       end;
                   end;
               end
    +        else if (right.resultdef.typ=enumdef) then
    +          begin
    +            { left must be an ordinal }
    +            if not is_ordinal(left.resultdef) then
    +              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
    +            case nodetype of
    +              isn:
    +                resultdef:=pasbool8type;
    +              asn:
    +                resultdef:=right.resultdef;
    +            end;
    +          end
             else
               CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
           end;
    @@ -4309,6 +4321,8 @@
             procname: string;
             statement : tstatementnode;
             tempnode : ttempcreatenode;
    +        v,res: Tconstexprint;
    +        leftconv: tnode;
           begin
             result:=nil;
             { Passing a class type to an "is" expression cannot result in a class
    @@ -4354,6 +4368,35 @@
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef);
               end
    +        else if (right.resultdef.typ=enumdef) then
    +          begin
    +            if left.nodetype=ordconstn then
    +              begin
    +                v:=Tordconstnode(left).value;
    +                res.signed:=false;
    +                res.overflow:=false;
    +                if v.signed and ((v.svalue<tenumdef(right.resultdef).min) or (v.svalue>tenumdef(right.resultdef).max)) then
    +                  res.uvalue:=0 { false }
    +                else
    +                if not v.signed and ((v.uvalue<tenumdef(right.resultdef).min) or (v.uvalue>tenumdef(right.resultdef).max)) then
    +                  res.uvalue:=0 { false }
    +                else
    +                  res.uvalue:=1; { true }
    +                result := cordconstnode.create(res, resultdef, false);
    +              end
    +            else
    +              begin
    +                if left.resultdef.typ<>orddef then
    +                  leftconv := ctypeconvnode.create_internal(left, s32inttype)
    +                else
    +                  leftconv := left;
    +                result := ccallnode.createinternres('fpc_do_is_enum',
    +                  ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
    +                    ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
    +                      ccallparanode.create(leftconv, nil))),
    +                  resultdef);
    +              end;
    +          end
             else
               begin
                 if is_class(left.resultdef) then
    @@ -4432,6 +4475,8 @@
         function tasnode.pass_1 : tnode;
           var
             procname: string;
    +        leftconv: tnode;
    +        v: Tconstexprint;
           begin
             result:=nil;
             { Passing a class type to an "as" expression cannot result in a class
    @@ -4450,6 +4495,31 @@
                   call := ccallnode.createinternres('fpc_do_as',
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef)
    +            else if (right.resultdef.typ=enumdef) then
    +              begin
    +                if left.nodetype=ordconstn then
    +                  begin
    +                    v:=Tordconstnode(left).value;
    +                    if v.signed and ((v.svalue<tenumdef(right.resultdef).min) or (v.svalue>tenumdef(right.resultdef).max)) then
    +                      Message(parser_e_range_check_error)
    +                    else
    +                    if not v.signed and ((v.uvalue<tenumdef(right.resultdef).min) or (v.uvalue>tenumdef(right.resultdef).max)) then
    +                      Message(parser_e_range_check_error);
    +                    call := ctypeconvnode.create_internal(left, resultdef);
    +                  end
    +                else
    +                  begin
    +                    if left.resultdef.typ<>orddef then
    +                      leftconv := ctypeconvnode.create_internal(left, s32inttype)
    +                    else
    +                      leftconv := left;
    +                    call := ccallnode.createinternres('fpc_do_as_enum',
    +                      ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
    +                        ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
    +                          ccallparanode.create(leftconv, nil))),
    +                      resultdef)
    +                  end;
    +              end
                 else
                   begin
                     if is_class(left.resultdef) then
    Index: rtl/inc/compproc.inc
    ===================================================================
    --- rtl/inc/compproc.inc	(revision 38690)
    +++ rtl/inc/compproc.inc	(working copy)
    @@ -798,6 +798,8 @@
     
     procedure fpc_AbstractErrorIntern;compilerproc;
     procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
    +function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
    +function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
     
     {$ifdef FPC_HAS_FEATURE_FILEIO}
     Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
    Index: rtl/inc/system.inc
    ===================================================================
    --- rtl/inc/system.inc	(revision 38690)
    +++ rtl/inc/system.inc	(working copy)
    @@ -1528,6 +1528,29 @@
     
     
     {*****************************************************************************
    +                       (I as TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
    +begin
    +  if (value>=minvalue) and (value<=maxvalue) then
    +    result:=value
    +  else
    +    handleerroraddrframeInd(219,get_pc_addr,get_frame);
    +end;
    +
    +
    +{*****************************************************************************
    +                       (I is TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
    +begin
    +  result := (value>=minvalue) and (value<=maxvalue);
    +end;
    +
    +
    +{*****************************************************************************
                            SetJmp/LongJmp support.
     *****************************************************************************}
     
    
    AS-IS-enum-02.patch (6,628 bytes)
  • ValidEnumIS.lpr (945 bytes)
  • ValidEnumAS-2.lpr (2,258 bytes)
  • AS-IS-enum-03.patch (95,365 bytes)
    Index: compiler/msg/errore.msg
    ===================================================================
    --- compiler/msg/errore.msg	(revision 38690)
    +++ compiler/msg/errore.msg	(working copy)
    @@ -2012,6 +2012,7 @@
     % require specialisation for methods or nested subroutines.
     type_e_seg_procvardef_wrong_memory_model=04124_E_Procedure variables in that memory model do not store segment information
     type_w_empty_constant_range_set=04125_W_The first value of a set constructur range is greater then the second value, so the range describes an empty set.
    +type_e_as_is_enums_with_assign_not_possible=04126_E_as or is cannot be used on enums with assignments
     % If a set is constructed like this: \var{s:=[9..7];]}, then an empty set is generated. As this is something normally not desired, the compiler warns about it.
     % \end{description}
     #
    Index: compiler/msgidx.inc
    ===================================================================
    --- compiler/msgidx.inc	(revision 38690)
    +++ compiler/msgidx.inc	(working copy)
    @@ -572,6 +572,7 @@
       type_e_function_reference_kind=04123;
       type_e_seg_procvardef_wrong_memory_model=04124;
       type_w_empty_constant_range_set=04125;
    +  type_e_as_is_enums_with_assign_not_possible=04126;
       sym_e_id_not_found=05000;
       sym_f_internal_error_in_symtablestack=05001;
       sym_e_duplicate_id=05002;
    @@ -1099,9 +1100,9 @@
       option_info=11024;
       option_help_pages=11025;
     
    -  MsgTxtSize = 81837;
    +  MsgTxtSize = 81895;
     
       MsgIdxMax : array[1..20] of longint=(
    -    27,106,347,126,96,59,142,34,221,67,
    +    27,106,347,127,96,59,142,34,221,67,
         61,20,30,1,1,1,1,1,1,1
       );
    Index: compiler/msgtxt.inc
    ===================================================================
    --- compiler/msgtxt.inc	(revision 38690)
    +++ compiler/msgtxt.inc	(working copy)
    @@ -1,8 +1,8 @@
     const msgtxt_codepage=20127;
     {$ifdef Delphi}
    -const msgtxt : array[0..000340] of string[240]=(
    +const msgtxt : array[0..000341] of string[240]=(
     {$else Delphi}
    -const msgtxt : array[0..000340,1..240] of char=(
    +const msgtxt : array[0..000341,1..240] of char=(
     {$endif Delphi}
       '01000_T_Compiler: $1'#000+
       '01001_D_Compiler OS: $1'#000+
    @@ -723,412 +723,412 @@
       'information'#000+
       '04125_W_The first value o','f a set constructur range is greater then t'+
       'he second value, so the range describes an empty set.'#000+
    +  '04126_E_as or is cannot be used on enums with assignments'#000+
       '05000_E_Identifier not found "$1"'#000+
       '05001_F_Internal Error in SymTableStack()'#000+
    -  '05002_E_Duplicate identifier "$1"'#000+
    -  '05003_H_Identifier already define','d in $1 at line $2'#000+
    +  '05002_E_D','uplicate identifier "$1"'#000+
    +  '05003_H_Identifier already defined in $1 at line $2'#000+
       '05004_E_Unknown identifier "$1"'#000+
       '05005_E_Forward declaration not solved "$1"'#000+
       '05007_E_Error in type definition'#000+
       '05009_E_Forward type not resolved "$1"'#000+
    -  '05010_E_Only static variables can be used in static methods or outside'+
    -  ' me','thods'#000+
    +  '05010_E_Only st','atic variables can be used in static methods or outsi'+
    +  'de methods'#000+
       '05012_E_Record or object or class type expected'#000+
       '05013_E_Instances of classes or objects with an abstract method are no'+
       't allowed'#000+
       '05014_W_Label not defined "$1"'#000+
    -  '05015_E_Label used but not defined "$1"'#000+
    +  '05015_E_Label use','d but not defined "$1"'#000+
       '05016_E_Illegal label declaration'#000+
    -  '0','5017_E_GOTO and LABEL are not supported (use switch -Sg)'#000+
    +  '05017_E_GOTO and LABEL are not supported (use switch -Sg)'#000+
       '05018_E_Label not found'#000+
       '05019_E_identifier isn'#039't a label'#000+
       '05020_E_label already defined'#000+
    -  '05021_E_illegal type declaration of set elements'#000+
    -  '05022_E_Forward class definition not resolved "','$1"'#000+
    +  '05021_E_illegal type declaration of se','t elements'#000+
    +  '05022_E_Forward class definition not resolved "$1"'#000+
       '05023_H_Unit "$1" not used in $2'#000+
       '05024_H_Parameter "$1" not used'#000+
       '05025_N_Local variable "$1" not used'#000+
       '05026_H_Value parameter "$1" is assigned but never used'#000+
    -  '05027_N_Local variable "$1" is assigned but never used'#000+
    -  '05028_H_Local $1 "$2" i','s not used'#000+
    +  '05027_N_Local variab','le "$1" is assigned but never used'#000+
    +  '05028_H_Local $1 "$2" is not used'#000+
       '05029_N_Private field "$1.$2" is never used'#000+
       '05030_N_Private field "$1.$2" is assigned but never used'#000+
       '05031_N_Private method "$1.$2" never used'#000+
       '05032_E_Set type expected'#000+
    -  '05033_W_Function result does not seem to be set'#000+
    -  '05034_W_Type',' "$1" is not aligned correctly in current record for C'#000+
    +  '05','033_W_Function result does not seem to be set'#000+
    +  '05034_W_Type "$1" is not aligned correctly in current record for C'#000+
       '05035_E_Unknown record field identifier "$1"'#000+
       '05036_W_Local variable "$1" does not seem to be initialized'#000+
    -  '05037_W_Variable "$1" does not seem to be initialized'#000+
    -  '05038_E_identifier idents ','no member "$1"'#000+
    +  '05037_W_Variable "$1" ','does not seem to be initialized'#000+
    +  '05038_E_identifier idents no member "$1"'#000+
       '05039_H_Found declaration: $1'#000+
       '05040_E_Data element too large'#000+
       '05042_E_No matching implementation for interface method "$1" found'#000+
       '05043_W_Symbol "$1" is deprecated'#000+
    -  '05044_W_Symbol "$1" is not portable'#000+
    -  '05055_W_Symbol "$1" is not ','implemented'#000+
    +  '05044','_W_Symbol "$1" is not portable'#000+
    +  '05055_W_Symbol "$1" is not implemented'#000+
       '05056_E_Can'#039't create unique type from this type'#000+
       '05057_H_Local variable "$1" does not seem to be initialized'#000+
       '05058_H_Variable "$1" does not seem to be initialized'#000+
    -  '05059_W_Function result variable does not seem to be initialized'#000+
    -  '0','5060_H_Function result variable does not seem to be initialized'#000+
    +  '05059_W_','Function result variable does not seem to be initialized'#000+
    +  '05060_H_Function result variable does not seem to be initialized'#000+
       '05061_W_Variable "$1" read but nowhere assigned'#000+
       '05062_H_Found abstract method: $1'#000+
    -  '05063_W_Symbol "$1" is experimental'#000+
    -  '05064_W_Forward declaration "$1" not resolved, assumed ext','ernal'#000+
    +  '05063_W_Symbol "$1" is experimental'#000,
    +  '05064_W_Forward declaration "$1" not resolved, assumed external'#000+
       '05065_W_Symbol "$1" is belongs to a library'#000+
       '05066_W_Symbol "$1" is deprecated: "$2"'#000+
       '05067_E_Cannot find an enumerator for the type "$1"'#000+
    -  '05068_E_Cannot find a "MoveNext" method in enumerator "$1"'#000+
    -  '05069_E_Cannot find a "Current" propert','y in enumerator "$1"'#000+
    +  '05068_E_Cannot find a "MoveNext" method ','in enumerator "$1"'#000+
    +  '05069_E_Cannot find a "Current" property in enumerator "$1"'#000+
       '05070_E_Mismatch between number of declared parameters and number of c'+
       'olons in message string.'#000+
       '05071_N_Private type "$1.$2" never used'#000+
    -  '05072_N_Private const "$1.$2" never used'#000+
    -  '05073_N_Private property "$1.$2" never used',#000+
    +  '05072_N_Private const "$1.','$2" never used'#000+
    +  '05073_N_Private property "$1.$2" never used'#000+
       '05074_W_Unit "$1" is deprecated'#000+
       '05075_W_Unit "$1" is deprecated: "$2"'#000+
       '05076_W_Unit "$1" is not portable'#000+
       '05077_W_Unit "$1" is belongs to a library'#000+
    -  '05078_W_Unit "$1" is not implemented'#000+
    +  '05078_W_Unit "$1" is not implemente','d'#000+
       '05079_W_Unit "$1" is experimental'#000+
    -  '05080_E_No full defini','tion of the formally declared class "$1" is in'+
    -  ' scope. Add the unit containing its full definition to the uses clause'+
    -  '.'#000+
    -  '05081_E_Gotos into initialization or finalization blocks of units are '+
    -  'not allowed'#000+
    -  '05082_E_Invalid external name "$1" for f','ormal class "$2"'#000+
    +  '05080_E_No full definition of the formally declared class "$1" is in s'+
    +  'cope. Add the unit containing its full definition to the uses clause.'#000+
    +  '05081_E_Gotos into initialization or finalization blocks of unit','s ar'+
    +  'e not allowed'#000+
    +  '05082_E_Invalid external name "$1" for formal class "$2"'#000+
       '05083_E_Complete class definition with external name "$1" here'#000+
       '05084_W_Possible library conflict: symbol "$1" from library "$2" also '+
       'found in library "$3"'#000+
    -  '05085_E_Cannot add implicit constructor '#039'Create'#039' because ident'+
    -  'ifier ','already used by "$1"'#000+
    +  '05085_E_Ca','nnot add implicit constructor '#039'Create'#039' because ide'+
    +  'ntifier already used by "$1"'#000+
       '05086_E_Cannot generate default constructor for class, because parent '+
       'has no parameterless constructor'#000+
       '05087_D_Adding helper for $1'#000+
    -  '05088_E_Found declaration: $1'#000+
    -  '05089_W_Local variable "$1" of a managed type does not se','em to be in'+
    -  'itialized'#000+
    +  '05088_E_Found declaration: $1',#000+
    +  '05089_W_Local variable "$1" of a managed type does not seem to be init'+
    +  'ialized'#000+
       '05090_W_Variable "$1" of a managed type does not seem to be initialize'+
       'd'#000+
       '05091_H_Local variable "$1" of a managed type does not seem to be init'+
       'ialized'#000+
    -  '05092_H_Variable "$1" of a managed type does not seem to be initializ',
    -  'ed'#000+
    +  '05092_H_Var','iable "$1" of a managed type does not seem to be initiali'+
    +  'zed'#000+
       '05093_W_function result variable of a managed type does not seem to be'+
       ' initialized'#000+
       '05094_H_Function result variable of a managed type does not seem to be'+
       ' initialized'#000+
    -  '05095_W_Duplicate identifier "$1"'#000+
    -  '06009_E_Parameter list size exceeds 6','5535 bytes'#000+
    +  '05095_W_Dupli','cate identifier "$1"'#000+
    +  '06009_E_Parameter list size exceeds 65535 bytes'#000+
       '06012_E_File types must be var parameters'#000+
       '06013_E_The use of a far pointer isn'#039't allowed there'#000+
       '06015_E_EXPORT declared functions cannot be called'#000+
    -  '06016_W_Possible illegal call of constructor or destructor'#000+
    -  '06017_N_Inefficient code',#000+
    +  '06016_W_Possible illegal ','call of constructor or destructor'#000+
    +  '06017_N_Inefficient code'#000+
       '06018_W_unreachable code'#000+
       '06020_E_Abstract methods cannot be called directly'#000+
       '06027_DL_Register $1 weight $2 $3'#000+
       '06029_DL_Stack frame is omitted'#000+
    -  '06031_E_Object or class methods cannot be inline.'#000+
    +  '06031_E_Object or class methods cannot ','be inline.'#000+
       '06032_E_Procvar calls cannot be inline.'#000+
    -  '06033_E','_No code for inline procedure stored'#000+
    +  '06033_E_No code for inline procedure stored'#000+
       '06035_E_Element zero of an ansi/wide- or longstring cannot be accessed'+
       ', use (set)length instead'#000+
    -  '06037_E_Constructors or destructors cannot be called inside a '#039'wit'+
    -  'h'#039' clause'#000+
    -  '06038_E_Cannot call message han','dler methods directly'#000+
    +  '06037_E_Constructors or destructors cannot be cal','led inside a '#039'w'+
    +  'ith'#039' clause'#000+
    +  '06038_E_Cannot call message handler methods directly'#000+
       '06039_E_Jump in or outside of an exception block'#000+
       '06040_E_Control flow statements are not allowed in a finally block'#000+
    -  '06041_W_Parameters size exceeds limit for certain cpu'#039's'#000+
    -  '06042_W_Local variable size exceed limit for c','ertain cpu'#039's'#000+
    +  '06041_W_Parameters size exceeds limit for ce','rtain cpu'#039's'#000+
    +  '06042_W_Local variable size exceed limit for certain cpu'#039's'#000+
       '06043_E_Local variables size exceeds supported limit'#000+
       '06044_E_BREAK not allowed'#000+
       '06045_E_CONTINUE not allowed'#000+
    -  '06046_F_Unknown compilerproc "$1". Check if you use the correct run ti'+
    -  'me library.'#000+
    -  '06047_F_Cannot find system type "$1".',' Check if you use the correct r'+
    -  'un time library.'#000+
    +  '06046_F_Unknown compilerproc "$1". Check if you use the corre','ct run '+
    +  'time library.'#000+
    +  '06047_F_Cannot find system type "$1". Check if you use the correct run'+
    +  ' time library.'#000+
       '06048_H_Inherited call to abstract method ignored'#000+
       '06049_E_Goto label "$1" not defined or optimized away'#000+
    -  '06050_F_Cannot find type "$1" in unit "$2". Check if you use the corre'+
    -  'ct run time librar','y.'#000+
    +  '06050_F_Cannot find type "$1" ','in unit "$2". Check if you use the cor'+
    +  'rect run time library.'#000+
       '06051_E_Interprocedural gotos are allowed only to outer subroutines'#000+
       '06052_E_Label must be defined in the same scope as it is declared'#000+
    -  '06053_E_Leaving procedures containing explicit or implicit exceptions '+
    -  'frames using goto is not allowed'#000,
    +  '06053_E_Leaving procedures containing explici','t or implicit exception'+
    +  's frames using goto is not allowed'#000+
       '06054_E_In ISO mode, the mod operator is defined only for positive quo'+
       'tient'#000+
       '06055_DL_Auto inlining: $1'#000+
       '06056_E_The function used, is not supported by the selected instructio'+
    -  'n set: $1'#000+
    -  '06057_F_Maximum number of units ($1) reached for the curr','ent target'#000+
    +  'n set: $1',#000+
    +  '06057_F_Maximum number of units ($1) reached for the current target'#000+
       '06058_N_Call to subroutine "$1" marked as inline is not inlined'#000+
       '07000_DL_Starting $1 styled assembler parsing'#000+
       '07001_DL_Finished $1 styled assembler parsing'#000+
    -  '07002_E_Non-label pattern contains @'#000+
    -  '07004_E_Error building record offset',#000+
    +  '07002_E_Non-lab','el pattern contains @'#000+
    +  '07004_E_Error building record offset'#000+
       '07005_E_OFFSET used without identifier'#000+
       '07006_E_TYPE used without identifier'#000+
       '07007_E_Cannot use local variable or parameters here'#000+
       '07008_E_need to use OFFSET here'#000+
    -  '07009_E_need to use $ here'#000+
    +  '07009_E_need to use ','$ here'#000+
       '07010_E_Cannot use multiple relocatable symbols'#000+
    -  '070','11_E_Relocatable symbol can only be added'#000+
    +  '07011_E_Relocatable symbol can only be added'#000+
       '07012_E_Invalid constant expression'#000+
       '07013_E_Relocatable symbol is not allowed'#000+
       '07014_E_Invalid reference syntax'#000+
    -  '07015_E_You cannot reach $1 from that code'#000+
    -  '07016_E_Local symbols/labels are not allowed',' as references'#000+
    +  '07015_E_You cannot reach $1 f','rom that code'#000+
    +  '07016_E_Local symbols/labels are not allowed as references'#000+
       '07017_E_Invalid base and index register usage'#000+
       '07018_W_Possible error in object field handling'#000+
       '07019_E_Wrong scale factor specified'#000+
    -  '07020_E_Multiple index register usage'#000+
    +  '07020_E_Multiple index register usag','e'#000+
       '07021_E_Invalid operand type'#000+
    -  '07022_E_Invalid string as o','pcode operand: $1'#000+
    +  '07022_E_Invalid string as opcode operand: $1'#000+
       '07023_W_@CODE and @DATA not supported'#000+
       '07024_E_Null label references are not allowed'#000+
       '07025_E_Divide by zero in asm evaluator'#000+
       '07026_E_Illegal expression'#000+
    -  '07027_E_escape sequence ignored: $1'#000+
    +  '07027_E_escap','e sequence ignored: $1'#000+
       '07028_E_Invalid symbol reference'#000+
    -  '07','029_W_Fwait can cause emulation problems with emu387'#000+
    +  '07029_W_Fwait can cause emulation problems with emu387'#000+
       '07030_W_$1 without operand translated into $1P'#000+
       '07031_W_ENTER instruction is not supported by Linux kernel'#000+
    -  '07032_W_Calling an overload function in assembler'#000+
    -  '07033_E_Unsupported symbol type',' for operand'#000+
    +  '07032_W_Calling an over','load function in assembler'#000+
    +  '07033_E_Unsupported symbol type for operand'#000+
       '07034_E_Constant value out of bounds'#000+
       '07035_E_Error converting decimal $1'#000+
       '07036_E_Error converting octal $1'#000+
       '07037_E_Error converting binary $1'#000+
    -  '07038_E_Error converting hexadecimal $1'#000+
    +  '07038_E_Error converting he','xadecimal $1'#000+
       '07039_H_$1 translated to $2'#000+
    -  '07040_W_$1 is ass','ociated to an overloaded function'#000+
    +  '07040_W_$1 is associated to an overloaded function'#000+
       '07041_E_Cannot use SELF outside a method'#000+
       '07042_E_Cannot use OLDEBP outside a nested procedure'#000+
    -  '07043_W_Procedures cannot return any value in asm code'#000+
    +  '07043_W_Procedures cannot return any value in asm code',#000+
       '07044_E_SEG not supported'#000+
    -  '07045_E_Size suffix and destina','tion or source size do not match'#000+
    +  '07045_E_Size suffix and destination or source size do not match'#000+
       '07046_W_Size suffix and destination or source size do not match'#000+
       '07047_E_Assembler syntax error'#000+
       '07048_E_Invalid combination of opcode and operands'#000+
    -  '07049_E_Assembler syntax error in operand'#000+
    -  '07050_E_Assembler s','yntax error in constant'#000+
    +  '070','49_E_Assembler syntax error in operand'#000+
    +  '07050_E_Assembler syntax error in constant'#000+
       '07051_E_Invalid String expression'#000+
       '07052_W_constant with symbol $1 for address which is not on a pointer'#000+
       '07053_E_Unrecognized opcode $1'#000+
    -  '07054_E_Invalid or missing opcode'#000+
    -  '07055_E_Invalid combination of prefix and opcod','e: $1'#000+
    +  '07054_E_Invalid or miss','ing opcode'#000+
    +  '07055_E_Invalid combination of prefix and opcode: $1'#000+
       '07056_E_Invalid combination of override and opcode: $1'#000+
       '07057_E_Too many operands on line'#000+
       '07058_W_NEAR ignored'#000+
       '07059_W_FAR ignored'#000+
       '07060_E_Duplicate local symbol $1'#000+
    -  '07061_E_Undefined local symbol $1'#000+
    -  '07062_E_Unknown label identifier $1'#000,
    +  '07061_E_Unde','fined local symbol $1'#000+
    +  '07062_E_Unknown label identifier $1'#000+
       '07063_E_Invalid register name'#000+
       '07064_E_Invalid floating point register name'#000+
       '07066_W_Modulo not supported'#000+
       '07067_E_Invalid floating point constant $1'#000+
    -  '07068_E_Invalid floating point expression'#000+
    +  '07068_E_Invalid floating point expr','ession'#000+
       '07069_E_Wrong symbol type'#000+
    -  '07070_E_Cannot index a lo','cal var or parameter with a register'#000+
    +  '07070_E_Cannot index a local var or parameter with a register'#000+
       '07071_E_Invalid segment override expression'#000+
       '07072_W_Identifier $1 supposed external'#000+
       '07073_E_Strings not allowed as constants'#000+
    -  '07074_E_No type of variable specified'#000+
    -  '07075_E_assembler code not returned to t','ext section'#000+
    +  '07074_E_No type of v','ariable specified'#000+
    +  '07075_E_assembler code not returned to text section'#000+
       '07076_E_Not a directive or local symbol $1'#000+
       '07077_E_Using a defined name as a local label'#000+
       '07078_E_Dollar token is used without an identifier'#000+
    -  '07079_W_32bit constant created for address'#000+
    -  '07080_N_.align is target specific, use .balig','n or .p2align'#000+
    +  '07079_W_32bit constant created',' for address'#000+
    +  '07080_N_.align is target specific, use .balign or .p2align'#000+
       '07081_E_Cannot directly access fields of pointer-based parameters'#000+
       '07082_E_Can'#039't access fields of objects/classes directly'#000+
    -  '07083_E_No size specified and unable to determine the size of the oper'+
    -  'ands'#000+
    -  '07084_E_Cannot use RESULT in ','this function'#000+
    +  '07083_E_No size specified and unable to determ','ine the size of the op'+
    +  'erands'#000+
    +  '07084_E_Cannot use RESULT in this function'#000+
       '07086_W_"$1" without operand translated into "$1 %st,%st(1)"'#000+
       '07087_W_"$1 %st(n)" translated into "$1 %st,%st(n)"'#000+
       '07088_W_"$1 %st(n)" translated into "$1 %st(n),%st"'#000+
    -  '07089_E_Char < not allowed here'#000+
    -  '07090_E_Char > not allowed he','re'#000+
    +  '070','89_E_Char < not allowed here'#000+
    +  '07090_E_Char > not allowed here'#000+
       '07093_W_ALIGN not supported'#000+
       '07094_E_Inc and Dec cannot be together'#000+
       '07095_E_Invalid register list for MOVEM or FMOVEM'#000+
       '07096_E_Reglist invalid for opcode'#000+
    -  '07097_E_Higher cpu mode required ($1)'#000+
    -  '07098_W_No size specified and unable to determi','ne the size of the op'+
    -  'erands, using DWORD as default'#000+
    +  '07097_E_Higher cpu mode req','uired ($1)'#000+
    +  '07098_W_No size specified and unable to determine the size of the oper'+
    +  'ands, using DWORD as default'#000+
       '07099_E_Syntax error while trying to parse a shifter operand'#000+
       '07100_E_Address of packed component is not at a byte boundary'#000+
    -  '07101_W_No size specified and unable to determine the size of the',' op'+
    +  '07101_W','_No size specified and unable to determine the size of the op'+
       'erands, using BYTE as default'#000+
       '07102_W_Use of +offset(%ebp) for parameters invalid here'#000+
       '07103_W_Use of +offset(%ebp) is not compatible with regcall convention'+
       #000+
    -  '07104_W_Use of -offset(%ebp) is not recommended for local variable acc'+
    -  'ess'#000+
    -  '07105','_W_Use of -offset(%esp), access may cause a crash or value may '+
    -  'be lost'#000+
    +  '07104_W_Use of -offse','t(%ebp) is not recommended for local variable a'+
    +  'ccess'#000+
    +  '07105_W_Use of -offset(%esp), access may cause a crash or value may be'+
    +  ' lost'#000+
       '07106_E_VMTOffset must be used in combination with a virtual method, a'+
       'nd "$1" is not virtual'#000+
    -  '07107_E_Generating PIC, but reference is not PIC-safe'#000+
    -  '07108_E_All registers ','in a register set must be of the same kind and'+
    -  ' width'#000+
    +  '07107_E_Generating',' PIC, but reference is not PIC-safe'#000+
    +  '07108_E_All registers in a register set must be of the same kind and w'+
    +  'idth'#000+
       '07109_E_A register set cannot be empty'#000+
       '07110_W_@GOTPCREL is useless and potentially dangerous for local symbo'+
       'ls'#000+
    -  '07111_W_Constant with general purpose segment register'#000+
    -  '07112_E_Invalid offs','et value for $1'#000+
    +  '07111_W_Constant ','with general purpose segment register'#000+
    +  '07112_E_Invalid offset value for $1'#000+
       '07113_E_Invalid register for $1'#000+
       '07114_E_SEH directives are allowed only in pure assembler procedures'#000+
       '07115_E_Directive "$1" is not supported for the current target'#000+
    -  '07116_E_This function'#039's result location cannot be encoded di','rect'+
    +  '07','116_E_This function'#039's result location cannot be encoded direct'+
       'ly in a single operand when "nostackframe" is used'#000+
       '07117_E_GOTPCREL references in Intel assembler syntax cannot contain a'+
       ' base or index register, and their offset must 0.'#000+
    -  '07118_E_The current target does not support GOTPCREL relocations'#000,
    +  '07118_E','_The current target does not support GOTPCREL relocations'#000+
       '07119_W_Exported/global symbols should be accessed via the GOT'#000+
       '07120_W_Check size of memory operand "$1"'#000+
       '07121_W_Check size of memory operand "$1: memory-operand-size is $2 bi'+
    -  'ts, but expected [$3 bits]"'#000+
    -  '07122_W_Check size of memory operand ','"$1: memory-operand-size is $2 '+
    -  'bits, but expected [$3 bits + $4 byte offset]"'#000+
    +  'ts, but',' expected [$3 bits]"'#000+
    +  '07122_W_Check size of memory operand "$1: memory-operand-size is $2 bi'+
    +  'ts, but expected [$3 bits + $4 byte offset]"'#000+
       '07123_W_Check "$1: offset of memory operand is negative "$2 byte"'#000+
    -  '07124_W_Check "$1: size of memory operand is empty, but es exists diff'+
    -  'erent definitions of the m','emory size =>> map to $2 (smallest option)'+
    +  '07124_W_Check "$1: size of memory oper','and is empty, but es exists di'+
    +  'fferent definitions of the memory size =>> map to $2 (smallest option)'+
       '"'#000+
       '07125_E_Invalid register used in memory reference expression: "$1"'#000+
       '07126_E_SEG used without identifier'#000+
    -  '07127_E_@CODE and @DATA can only be used with the SEG operator'#000+
    -  '07128_E_Not enough space (16 b','its required) for the segment constant'+
    -  ' of symbol $1'#000+
    +  '07127_E_@CODE and @DATA can only be',' used with the SEG operator'#000+
    +  '07128_E_Not enough space (16 bits required) for the segment constant o'+
    +  'f symbol $1'#000+
       '07129_E_Invalid value of .code directive constant'#000+
       '07130_W_No size specified and unable to determine the size of the cons'+
    -  'tant, using BYTE as default'#000+
    -  '07131_W_No size specified and unable to ','determine the size of the co'+
    -  'nstant, using WORD as default'#000+
    +  'tant, usin','g BYTE as default'#000+
    +  '07131_W_No size specified and unable to determine the size of the cons'+
    +  'tant, using WORD as default'#000+
       '07132_E_Cannot override ES segment'#000+
       '07133_W_Reference is not valid here (expected "$1")'#000+
       '07134_E_Address sizes do not match'#000+
    -  '07135_E_Instruction "POP CS" is not valid for the current ta','rget'#000+
    +  '07','135_E_Instruction "POP CS" is not valid for the current target'#000+
       '07136_W_Instruction "POP CS" is not portable (it only works on 8086 an'+
       'd 8088 CPUs)'#000+
       '07137_E_Label $1 can only be declared public before it'#039's defined'#000+
    -  '07138_E_Local label $1 cannot be declared public'#000+
    -  '07139_E_Cannot use multiple segment ov','errides'#000+
    +  '07138_E_Local label $1 cannot',' be declared public'#000+
    +  '07139_E_Cannot use multiple segment overrides'#000+
       '07140_W_Multiple segment overrides (only the last one will take effect'+
       ')'#000+
       '07141_W_Segment base $1 will be generated, but is ignored by the CPU i'+
       'n 64-bit mode'#000+
    -  '08000_F_Too many assembler files'#000+
    -  '08001_F_Selected assembler output not suppo','rted'#000+
    +  '08000_F_Too many a','ssembler files'#000+
    +  '08001_F_Selected assembler output not supported'#000+
       '08002_F_Comp not supported'#000+
       '08003_F_Direct not support for binary writers'#000+
       '08004_E_Allocating of data is only allowed in bss section'#000+
       '08005_F_No binary writer selected'#000+
    -  '08006_E_Asm: Opcode $1 not in table'#000+
    -  '08007_E_Asm: $1 invalid combinatio','n of opcode and operands'#000+
    +  '08006_E_Asm:',' Opcode $1 not in table'#000+
    +  '08007_E_Asm: $1 invalid combination of opcode and operands'#000+
       '08008_E_Asm: 16 Bit references not supported'#000+
       '08009_E_Asm: Invalid effective address'#000+
       '08010_E_Asm: Immediate or reference expected'#000+
    -  '08011_E_Asm: $1 value exceeds bounds $2'#000+
    +  '08011_E_Asm: $1 value exceed','s bounds $2'#000+
       '08012_E_Asm: Short jump is out of range $1'#000+
    -  '080','13_E_Asm: Undefined label $1'#000+
    +  '08013_E_Asm: Undefined label $1'#000+
       '08014_E_Asm: Comp type not supported for this target'#000+
       '08015_E_Asm: Extended type not supported for this target'#000+
       '08016_E_Asm: Duplicate label $1'#000+
    -  '08017_E_Asm: Redefined label $1'#000+
    +  '08017_E_Asm',': Redefined label $1'#000+
       '08018_E_Asm: First defined here'#000+
    -  '08019','_E_Asm: Invalid register $1'#000+
    +  '08019_E_Asm: Invalid register $1'#000+
       '08020_E_Asm: 16 or 32 Bit references not supported'#000+
       '08021_E_Asm: 64 Bit operands not supported'#000+
    -  '08022_E_Asm: AH,BH,CH or DH cannot be used in an instruction requiring'+
    -  ' REX prefix'#000+
    -  '08023_E_Missing .seh_endprologue dir','ective'#000+
    +  '08022_E_Asm: AH,BH,CH or DH cannot be used in an instruction',' requiri'+
    +  'ng REX prefix'#000+
    +  '08023_E_Missing .seh_endprologue directive'#000+
       '08024_E_Function prologue exceeds 255 bytes'#000+
       '08025_E_.seh_handlerdata directive without preceding .seh_handler'#000+
       '08026_F_Relocation count for section $1 exceeds 65535'#000+
    -  '08027_N_Change of bind type of symbol $1 from $2 to $3 after use'#000+
    -  '0802','8_H_Change of bind type of symbol $1 from $2 to $3 after use'#000+
    +  '08027_N_Cha','nge of bind type of symbol $1 from $2 to $3 after use'#000+
    +  '08028_H_Change of bind type of symbol $1 from $2 to $3 after use'#000+
       '08029_E_Asm: 32 Bit references not supported'#000+
       '08030_F_Code segment too large'#000+
       '08031_F_Data segment too large'#000+
    -  '08032_E_Instruction not supported by the selected instruction set'#000+
    -  '08033_','E_Asm: conditional branch destination is out of range'#000+
    +  '08032_E_Instru','ction not supported by the selected instruction set'#000+
    +  '08033_E_Asm: conditional branch destination is out of range'#000+
       '09000_W_Source operating system redefined'#000+
       '09001_I_Assembling (pipe) $1'#000+
       '09002_E_Can'#039't create assembler file: $1'#000+
    -  '09003_E_Can'#039't create object file: $1 (error code: $2)'#000+
    -  '09004_E_Can'#039't create ','archive file: $1'#000+
    +  '09003_E_Can'#039't cre','ate object file: $1 (error code: $2)'#000+
    +  '09004_E_Can'#039't create archive file: $1'#000+
       '09005_E_Assembler $1 not found, switching to external assembling'#000+
       '09006_T_Using assembler: $1'#000+
       '09007_E_Error while assembling exitcode $1'#000+
    -  '09008_E_Can'#039't call the assembler, error $1 switching to external a'+
    -  'ssembling'#000+
    -  '09009_I_Ass','embling $1'#000+
    +  '09008_E_Can'#039't call the assemb','ler, error $1 switching to external'+
    +  ' assembling'#000+
    +  '09009_I_Assembling $1'#000+
       '09010_I_Assembling with smartlinking $1'#000+
       '09011_W_Object $1 not found, Linking may fail !'#000+
       '09012_W_Library $1 not found, Linking may fail !'#000+
       '09013_E_Error while linking'#000+
    -  '09014_E_Can'#039't call the linker, switching to external linking'#000+
    -  '090','15_I_Linking $1'#000+
    +  '09014_','E_Can'#039't call the linker, switching to external linking'#000+
    +  '09015_I_Linking $1'#000+
       '09016_E_Util $1 not found, switching to external linking'#000+
       '09017_T_Using util $1'#000+
       '09018_E_Creation of Executables not supported'#000+
    -  '09019_E_Creation of Dynamic/Shared Libraries not supported'#000+
    -  '09035_E_Creation of Static Libraries not',' supported'#000+
    +  '09019_E_Creation of Dynamic/Shared Librar','ies not supported'#000+
    +  '09035_E_Creation of Static Libraries not supported'#000+
       '09020_I_Closing script $1'#000+
       '09021_E_resource compiler "$1" not found, switching to external mode'#000+
       '09022_I_Compiling resource $1'#000+
    -  '09023_T_unit $1 cannot be statically linked, switching to smart linkin'+
    -  'g'#000+
    -  '09024_T_unit $1 cannot be smart ','linked, switching to static linking'#000+
    +  '09023_T_unit $1 cannot be statically linked, s','witching to smart link'+
    +  'ing'#000+
    +  '09024_T_unit $1 cannot be smart linked, switching to static linking'#000+
       '09025_T_unit $1 cannot be shared linked, switching to static linking'#000+
       '09026_E_unit $1 cannot be smart or static linked'#000+
    -  '09027_E_unit $1 cannot be shared or static linked'#000+
    -  '09028_D_Calling resource compiler "$','1" with "$2" as command line'#000+
    +  '09027_E_unit $1 cannot be sh','ared or static linked'#000+
    +  '09028_D_Calling resource compiler "$1" with "$2" as command line'#000+
       '09029_E_Error while compiling resources'#000+
       '09030_E_Can'#039't call the resource compiler "$1", switching to extern'+
       'al mode'#000+
       '09031_E_Can'#039't open resource file "$1"'#000+
    -  '09032_E_Can'#039't write resource file "$1"'#000+
    -  '09033_N_File "$1" no','t found for backquoted cat command'#000+
    +  '0','9032_E_Can'#039't write resource file "$1"'#000+
    +  '09033_N_File "$1" not found for backquoted cat command'#000+
       '09034_W_"$1" not found, this will probably cause a linking failure'#000+
       '09128_F_Can'#039't post process executable $1'#000+
       '09129_F_Can'#039't open executable $1'#000+
    -  '09130_X_Size of Code: $1 bytes'#000+
    -  '09131_X_Size of initialized data:',' $1 bytes'#000+
    +  '09130_','X_Size of Code: $1 bytes'#000+
    +  '09131_X_Size of initialized data: $1 bytes'#000+
       '09132_X_Size of uninitialized data: $1 bytes'#000+
       '09133_X_Stack space reserved: $1 bytes'#000+
       '09134_X_Stack space committed: $1 bytes'#000+
    -  '09200_F_Executable image size is too big for $1 target.'#000+
    -  '09201_W_Object file "$1" contains 32-bit absolute ','relocation to symb'+
    -  'ol "$2".'#000+
    +  '09200_F_Executable image size is too big for $1 ','target.'#000+
    +  '09201_W_Object file "$1" contains 32-bit absolute relocation to symbol'+
    +  ' "$2".'#000+
       '09202_E_Program segment too large (exceeds 64k by $1 bytes)'#000+
       '09203_E_Code segment "$1" too large (exceeds 64k by $2 bytes)'#000+
    -  '09204_E_Data segment "$1" too large (exceeds 64k by $2 bytes)'#000+
    -  '09205_E_Segment "$1" too larg','e (exceeds 64k by $2 bytes)'#000+
    +  '09204_E_Data segment "$1" too lar','ge (exceeds 64k by $2 bytes)'#000+
    +  '09205_E_Segment "$1" too large (exceeds 64k by $2 bytes)'#000+
       '09206_E_Group "$1" too large (exceeds 64k by $2 bytes)'#000+
       '09207_E_Cannot create a .COM file, because the program contains segmen'+
       't relocations'#000+
    -  '09208_W_Program "$1" uses experimental CheckPointer option'#000+
    -  '09209_E_Multip','le defined symbol "$1"'#000+
    +  '09208_W_Program',' "$1" uses experimental CheckPointer option'#000+
    +  '09209_E_Multiple defined symbol "$1"'#000+
       '09210_E_COMDAT selection mode $1 not supported (section: "$1")'#000+
       '09211_E_Associative section expected for COMDAT section "$1"'#000+
    -  '09212_E_COMDAT section selection mode doesn'#039't match for section "$'+
    -  '1" and symbol "$2"'#000+
    -  '09213_E_','Associative COMDAT section for section "$1" not found'#000+
    +  '09212_E_COMDAT section selection mo','de doesn'#039't match for section '+
    +  '"$1" and symbol "$2"'#000+
    +  '09213_E_Associative COMDAT section for section "$1" not found'#000+
       '09214_D_Discarding duplicate symbol "$1" due to COMDAT selection mode'#000+
    -  '09215_D_Discarding duplicate symbol "$1" with same size due to COMDAT '+
    -  'selection mode'#000+
    -  '09216_D_Discarding duplicate sy','mbol "$1" with same content due to CO'+
    -  'MDAT selection mode'#000+
    +  '09215_D_Discarding duplicate symbol "$1" with same size du','e to COMDA'+
    +  'T selection mode'#000+
    +  '09216_D_Discarding duplicate symbol "$1" with same content due to COMD'+
    +  'AT selection mode'#000+
       '09217_D_Replacing duplicate symbol "$1" with smaller size due to COMDA'+
       'T selection mode'#000+
    -  '09218_E_Size of duplicate COMDAT symbol "$1" differs'#000+
    -  '09219_E_Content of duplicate COMDAT symbol ','"$1" differs'#000+
    +  '09218_E_Size of duplicate COMDAT symbo','l "$1" differs'#000+
    +  '09219_E_Content of duplicate COMDAT symbol "$1" differs'#000+
       '09220_E_COMDAT selection mode for symbol "$1" differs'#000+
       '10000_T_Unitsearch: $1'#000+
       '10001_T_PPU Loading $1'#000+
    @@ -1135,192 +1135,191 @@
       '10002_U_PPU Name: $1'#000+
       '10003_U_PPU Flags: $1'#000+
       '10004_U_PPU Crc: $1'#000+
    -  '10005_U_PPU Time: $1'#000+
    +  '10005_','U_PPU Time: $1'#000+
       '10006_U_PPU File too short'#000+
    -  '10007_U_PPU Inva','lid Header (no PPU at the begin)'#000+
    +  '10007_U_PPU Invalid Header (no PPU at the begin)'#000+
       '10008_U_PPU Invalid Version $1'#000+
       '10009_U_PPU is compiled for another processor'#000+
       '10010_U_PPU is compiled for another target'#000+
       '10011_U_PPU Source: $1'#000+
    -  '10012_U_Writing $1'#000+
    +  '10012_','U_Writing $1'#000+
       '10013_F_Can'#039't Write PPU-File'#000+
    -  '10014_F_Error re','ading PPU-File'#000+
    +  '10014_F_Error reading PPU-File'#000+
       '10015_F_unexpected end of PPU-File'#000+
       '10016_F_Invalid PPU-File entry: $1'#000+
       '10017_F_PPU Dbx count problem'#000+
       '10018_E_Illegal unit name: $1 (expecting $2)'#000+
    -  '10019_F_Too much units'#000+
    +  '10019_F_Too much units',#000+
       '10020_F_Circular unit reference between $1 and $2'#000+
    -  '10021_F','_Can'#039't compile unit $1, no sources available'#000+
    +  '10021_F_Can'#039't compile unit $1, no sources available'#000+
       '10022_F_Can'#039't find unit $1 used by $2'#000+
       '10023_W_Unit $1 was not found but $2 exists'#000+
       '10024_F_Unit $1 searched but $2 found'#000+
    -  '10025_W_Compiling the system unit requires the -Us switch'#000+
    -  '10026_F_There wer','e $1 errors compiling module, stopping'#000+
    +  '10025_W_Compiling',' the system unit requires the -Us switch'#000+
    +  '10026_F_There were $1 errors compiling module, stopping'#000+
       '10027_U_Load from $1 ($2) unit $3'#000+
       '10028_U_Recompiling $1, checksum changed for $2'#000+
       '10029_U_Recompiling $1, source found only'#000+
    -  '10030_U_Recompiling unit, static lib is older than ppufile'#000+
    -  '10031_U_Recompilin','g unit, shared lib is older than ppufile'#000+
    +  '10030_U_Recompiling',' unit, static lib is older than ppufile'#000+
    +  '10031_U_Recompiling unit, shared lib is older than ppufile'#000+
       '10032_U_Recompiling unit, obj and asm are older than ppufile'#000+
       '10033_U_Recompiling unit, obj is older than asm'#000+
    -  '10034_U_Parsing interface of $1'#000+
    +  '10034_U_Parsing interface of $1'#000,
       '10035_U_Parsing implementation of $1'#000+
    -  '10036_U_Second load f','or unit $1'#000+
    +  '10036_U_Second load for unit $1'#000+
       '10037_U_PPU Check file $1 time $2'#000+
       '10040_W_Can'#039't recompile unit $1, but found modified include files'#000+
       '10041_U_File $1 is newer than the one used for creating PPU file $2'#000+
    -  '10042_U_Trying to use a unit which was compiled with a differ','ent FPU'+
    +  '100','42_U_Trying to use a unit which was compiled with a different FPU'+
       ' mode'#000+
       '10043_U_Loading interface units from $1'#000+
       '10044_U_Loading implementation units from $1'#000+
       '10045_U_Interface CRC changed for unit $1'#000+
    -  '10046_U_Implementation CRC changed for unit $1'#000+
    +  '10046_U_Implementation CRC changed for uni','t $1'#000+
       '10047_U_Finished compiling unit $1'#000+
    -  '10048_U_Adding dep','endency: $1 depends on $2'#000+
    +  '10048_U_Adding dependency: $1 depends on $2'#000+
       '10049_U_No reload, is caller: $1'#000+
       '10050_U_No reload, already in second compile: $1'#000+
       '10051_U_Flag for reload: $1'#000+
       '10052_U_Forced reloading'#000+
    -  '10053_U_Previous state of $1: $2'#000+
    -  '10054_U_Already compiling $1, setting second c','ompile'#000+
    +  '10053_U_Previous stat','e of $1: $2'#000+
    +  '10054_U_Already compiling $1, setting second compile'#000+
       '10055_U_Loading unit $1'#000+
       '10056_U_Finished loading unit $1'#000+
       '10057_U_Registering new unit $1'#000+
       '10058_U_Re-resolving unit $1'#000+
    -  '10059_U_Skipping re-resolving unit $1, still loading used units'#000+
    +  '10059_U_Skipping re-resolving unit $1, still loading used',' units'#000+
       '10060_U_Unloading resource unit $1 (not needed)'#000+
    -  '100','61_E_Unit $1 was compiled using a different whole program optimiz'+
    -  'ation feedback input ($2, $3); recompile it without wpo or use the sam'+
    -  'e wpo feedback input file for this compilation invocation'#000+
    -  '10062_U_Indirect interface (objects/classes) CR','C changed for unit $1'+
    -  #000+
    +  '10061_E_Unit $1 was compiled using a different whole program optimizat'+
    +  'ion feedback input ($2, $3); recompile it without wpo or use the same '+
    +  'wpo feedback input file for this compilation ','invocation'#000+
    +  '10062_U_Indirect interface (objects/classes) CRC changed for unit $1'#000+
       '10063_U_PPU is compiled for another i8086 memory model'#000+
       '10064_U_Loading unit $1 from package $2'#000+
    -  '10065_F_Internal type "$1" was not found. Check if you use the correct'+
    -  ' run time library.'#000+
    -  '10066_F_Internal type "$1" does no','t look as expected. Check if you u'+
    -  'se the correct run time library.'#000+
    +  '10065_F_Internal type "$1" was not found. Check if you use the co','rre'+
    +  'ct run time library.'#000+
    +  '10066_F_Internal type "$1" does not look as expected. Check if you use'+
    +  ' the correct run time library.'#000+
       '11000_O_$1 [options] <inputfile> [options]'#000+
       '11001_W_Only one source file supported, changing source file to compil'+
    -  'e from "$1" into "$2"'#000+
    -  '11002_W_DEF file can be created only f','or OS/2'#000+
    +  'e ','from "$1" into "$2"'#000+
    +  '11002_W_DEF file can be created only for OS/2'#000+
       '11003_E_nested response files are not supported'#000+
       '11004_F_No source file name in command line'#000+
       '11005_N_No option inside $1 config file'#000+
       '11006_E_Illegal parameter: $1'#000+
    -  '11007_H_-? writes help pages'#000+
    +  '11007_H_-? w','rites help pages'#000+
       '11008_F_Too many config files nested'#000+
    -  '1100','9_F_Unable to open file $1'#000+
    +  '11009_F_Unable to open file $1'#000+
       '11010_D_Reading further options from $1'#000+
       '11011_W_Target is already set to: $1'#000+
       '11012_W_Shared libs not supported on DOS platform, reverting to static'+
       #000+
    -  '11013_F_In options file $1 at line $2 too many #IF(N)DEFs encount','ere'+
    +  '11013_F','_In options file $1 at line $2 too many #IF(N)DEFs encountere'+
       'd'#000+
       '11014_F_In options file $1 at line $2 unexpected #ENDIFs encountered'#000+
       '11015_F_Open conditional at the end of the options file'#000+
    -  '11016_W_Debug information generation is not supported by this executab'+
    -  'le'#000+
    +  '11016_W_Debug information generation is not supporte','d by this execut'+
    +  'able'#000+
       '11017_H_Try recompiling with -dGDB'#000+
    -  '11','018_W_You are using the obsolete switch $1'#000+
    +  '11018_W_You are using the obsolete switch $1'#000+
       '11019_W_You are using the obsolete switch $1, please use $2'#000+
       '11020_N_Switching assembler to default source writing assembler'#000+
    -  '11021_W_Assembler output selected "$1" is not compatible with "$2"'#000+
    -  '11022_','W_"$1" assembler use forced'#000+
    +  '11021_W_Assembl','er output selected "$1" is not compatible with "$2"'#000+
    +  '11022_W_"$1" assembler use forced'#000+
       '11026_T_Reading options from file $1'#000+
       '11027_T_Reading options from environment $1'#000+
       '11028_D_Handling option "$1"'#000+
       '11029_O_*** press enter ***'#000+
    -  '11030_H_Start of reading config file $1'#000+
    -  '11031_H_End of reading config file',' $1'#000+
    +  '11030_H_Start of',' reading config file $1'#000+
    +  '11031_H_End of reading config file $1'#000+
       '11032_D_interpreting option "$1"'#000+
       '11036_D_interpreting firstpass option "$1"'#000+
       '11033_D_interpreting file option "$1"'#000+
       '11034_D_Reading config file "$1"'#000+
    -  '11035_D_found source file name "$1"'#000+
    +  '11035_D_found source file name ','"$1"'#000+
       '11039_E_Unknown codepage "$1"'#000+
    -  '11040_F_Config file $1 ','is a directory'#000+
    +  '11040_F_Config file $1 is a directory'#000+
       '11041_W_Assembler output selected "$1" cannot generate debug info, deb'+
       'ugging disabled'#000+
       '11042_W_Use of ppc386.cfg is deprecated, please use fpc.cfg instead'#000+
    -  '11043_F_In options file $1 at line $2 #ELSE directive without #IF(N)DE'+
    -  'F',' found'#000+
    +  '11043_F_In op','tions file $1 at line $2 #ELSE directive without #IF(N)'+
    +  'DEF found'#000+
       '11044_F_Option "$1" is not, or not yet, supported on the current targe'+
       't platform'#000+
       '11045_F_The feature "$1" is not, or not yet, supported on the selected'+
       ' target platform'#000+
    -  '11046_N_DWARF debug information cannot be used with smart linking',' on'+
    +  '11046_N','_DWARF debug information cannot be used with smart linking on'+
       ' this target, switching to static linking'#000+
       '11047_W_Option "$1" is ignored for the current target platform.'#000+
       '11048_W_Disabling external debug information because it is unsupported'+
    -  ' for the selected target/debug format combination.'#000+
    -  '11049_N_DW','ARF debug information cannot be used with smart linking wi'+
    -  'th external assembler, disabling static library creation.'#000+
    -  '11050_E_Invalid value for MACOSX_DEPLOYMENT_TARGET environment variabl'+
    -  'e: $1'#000+
    -  '11051_E_Invalid value for IPHONEOS_DEPLOYMENT_TA','RGET environment var'+
    -  'iable: $1'#000+
    +  ' fo','r the selected target/debug format combination.'#000+
    +  '11049_N_DWARF debug information cannot be used with smart linking with'+
    +  ' external assembler, disabling static library creation.'#000+
    +  '11050_E_Invalid value for MACOSX_DEPLOYMENT_TARGET environment var','ia'+
    +  'ble: $1'#000+
    +  '11051_E_Invalid value for IPHONEOS_DEPLOYMENT_TARGET environment varia'+
    +  'ble: $1'#000+
       '11052_E_You must use a FPU type of VFPV2, VFPV3 or VFPV3_D16 when usin'+
       'g the EABIHF ABI target'#000+
    -  '11053_W_The selected debug format is not supported on the current targ'+
    -  'et, not changing the current setting'#000+
    -  '11054_E_a','rgument to "$1" is missing'#000+
    +  '11053_W_The selected debug format is not supported on the ','current ta'+
    +  'rget, not changing the current setting'#000+
    +  '11054_E_argument to "$1" is missing'#000+
       '11055_E_malformed parameter: $1'#000+
       '11056_W_Smart linking requires external linker'#000+
       '11057_E_Creating .COM files is not supported in the current memory mod'+
    -  'el. Only the tiny memory model supports making .COM files.'#000+
    -  '11058','_W_Experimental CheckPointer option not enabled because it is i'+
    -  'ncomptatible with -Ur option.'#000+
    +  'el. On','ly the tiny memory model supports making .COM files.'#000+
    +  '11058_W_Experimental CheckPointer option not enabled because it is inc'+
    +  'omptatible with -Ur option.'#000+
       '11059_E_Unsupported target architecture -P$1, invoke the "fpc" compile'+
       'r driver instead.'#000+
    -  '11060_E_Feature switches are only supported while compiling',' the syst'+
    +  '1','1060_E_Feature switches are only supported while compiling the syst'+
       'em unit.'#000+
       '12000_F_Cannot open whole program optimization feedback file "$1"'#000+
       '12001_D_Processing whole program optimization information in wpo feedb'+
       'ack file "$1"'#000+
    -  '12002_D_Finished processing the whole program optimization information'+
    -  ' i','n wpo feedback file "$1"'#000+
    +  '12002_D_Finish','ed processing the whole program optimization informati'+
    +  'on in wpo feedback file "$1"'#000+
       '12003_E_Expected section header, but got "$2" at line $1 of wpo feedba'+
       'ck file'#000+
       '12004_W_No handler registered for whole program optimization section "'+
    -  '$2" at line $1 of wpo feedback file, ignoring'#000+
    -  '12005_D_Found whole p','rogram optimization section "$1" with informati'+
    -  'on about "$2"'#000+
    +  '$2" at li','ne $1 of wpo feedback file, ignoring'#000+
    +  '12005_D_Found whole program optimization section "$1" with information'+
    +  ' about "$2"'#000+
       '12006_F_The selected whole program optimizations require a previously '+
       'generated feedback file (use -Fw to specify)'#000+
    -  '12007_E_No collected information necessary to perform "$1" whole',' pro'+
    +  '12007_','E_No collected information necessary to perform "$1" whole pro'+
       'gram optimization found'#000+
       '12008_F_Specify a whole program optimization feedback file to store th'+
       'e generated info in (using -FW)'#000+
    -  '12009_E_Not generating any whole program optimization information, yet'+
    -  ' a feedback file was specified (using -F','W)'#000+
    +  '12009_E_Not generating any whole program optimizatio','n information, y'+
    +  'et a feedback file was specified (using -FW)'#000+
       '12010_E_Not performing any whole program optimizations, yet an input f'+
       'eedback file was specified (using -Fw)'#000+
    -  '12011_D_Skipping whole program optimization section "$1", because not '+
    +  '12011_D_Skipping whole program optimization section "$1", because not ',
       'needed by the requested optimizations'#000+
    -  '12012_W_Overriding p','reviously read information for "$1" from feedbac'+
    -  'k input file using information in section "$2"'#000+
    +  '12012_W_Overriding previously read information for "$1" from feedback '+
    +  'input file using information in section "$2"'#000+
       '12013_E_Cannot extract symbol liveness information from program when s'+
    -  'tripping symbols, use -Xs-'#000+
    -  '12014_E_Cannot extract symbol liveness informati','on from program when'+
    -  ' when not linking'#000+
    +  'tripping symbols,',' use -Xs-'#000+
    +  '12014_E_Cannot extract symbol liveness information from program when w'+
    +  'hen not linking'#000+
       '12015_F_Cannot find "$1" or "$2" to extract symbol liveness informatio'+
       'n from linked program'#000+
    -  '12016_E_Error during reading symbol liveness information produced by "'+
    -  '$1"'#000+
    -  '12017_F_Error executing "$1" (exitco','de: $2) to extract symbol inform'+
    -  'ation from linked program'#000+
    +  '12016_E_Error during reading symbol liveness informa','tion produced by'+
    +  ' "$1"'#000+
    +  '12017_F_Error executing "$1" (exitcode: $2) to extract symbol informat'+
    +  'ion from linked program'#000+
       '12018_E_Collection of symbol liveness information can only help when u'+
       'sing smart linking, use -CX -XX'#000+
    -  '12019_E_Cannot create specified whole program optimisation feedback fi'+
    -  'le "$1"'#000+
    -  '13','001_F_Can'#039't find package $1'#000+
    +  '12019_E_Cannot create ','specified whole program optimisation feedback '+
    +  'file "$1"'#000+
    +  '13001_F_Can'#039't find package $1'#000+
       '13002_U_PCP file for package $1 found'#000+
       '13003_E_Duplicate package $1'#000+
       '13004_E_Unit $1 can not be part of a package'#000+
    -  '13005_N_Unit $1 is implicitely imported into package $2'#000+
    -  '13006_F_Failed to create PCP file $2 for pac','kage $1'#000+
    +  '13005_N_Unit $1 is implicitely imported in','to package $2'#000+
    +  '13006_F_Failed to create PCP file $2 for package $1'#000+
       '13007_F_Failed to read PCP file for package $1'#000+
       '13008_T_PCP loading $1'#000+
       '13009_U_PCP Name: $1'#000+
    @@ -1327,28 +1326,28 @@
       '13010_U_PCP Flags: $1'#000+
       '13011_U_PCP Crc: $1'#000+
       '13012_U_PCP Time: $1'#000+
    -  '13013_U_PCP File too short'#000+
    +  '13013_U_PCP File too',' short'#000+
       '13014_U_PCP Invalid Header (no PCP at the begin)'#000+
    -  '13','015_U_PCP Invalid Version $1'#000+
    +  '13015_U_PCP Invalid Version $1'#000+
       '13016_U_PCP is compiled for another processor'#000+
       '13017_U_PCP is compiled for another target'#000+
       '13018_U_Writing $1'#000+
       '13019_F_Can'#039't Write PCP-File'#000+
    -  '13020_F_Error reading PCP-File'#000+
    +  '13020_F_Error re','ading PCP-File'#000+
       '13021_F_unexpected end of PCP-File'#000+
    -  '13022_F_','Invalid PCP-File entry: $1'#000+
    +  '13022_F_Invalid PCP-File entry: $1'#000+
       '13023_U_Trying to use a unit which was compiled with a different FPU m'+
       'ode'#000+
       '13024_T_Packagesearch: $1'#000+
       '13025_U_Required package $1'#000+
       '13026_U_Contained unit $1'#000+
    -  '13027_E_Unit $1 is already contained in package $2'#000+
    -  '13028_W_','Unit $1 is imported from indirectly required package $2'#000+
    +  '1','3027_E_Unit $1 is already contained in package $2'#000+
    +  '13028_W_Unit $1 is imported from indirectly required package $2'#000+
       '13029_U_PPL filename $1'#000+
       '11023_Free Pascal Compiler version $FPCFULLVERSION [$FPCDATE] for $FPC'+
       'CPU'#010+
    -  'Copyright (c) 1993-2018 by Florian Klaempfl and others'#000+
    -  '11024_Free Pascal Compiler vers','ion $FPCVERSION'#010+
    +  'Copyright (c) 1993-2018 by F','lorian Klaempfl and others'#000+
    +  '11024_Free Pascal Compiler version $FPCVERSION'#010+
       #010+
       'Compiler date      : $FPCDATE'#010+
       'Compiler CPU target: $FPCCPU'#010+
    @@ -1357,10 +1356,10 @@
       'ment):'#010+
       '  $OSTARGETS'#010+
       #010+
    -  'Supported CPU instruction sets:'#010+
    +  'Supported CPU instruct','ion sets:'#010+
       '  $INSTRUCTIONSETS'#010+
       #010+
    -  'Supported FPU instruction se','ts:'#010+
    +  'Supported FPU instruction sets:'#010+
       '  $FPUINSTRUCTIONSETS'#010+
       #010+
       'Supported inline assembler modes:'#010+
    @@ -1372,153 +1371,153 @@
       'Supported ABI targets:'#010+
       '  $ABITARGETS'#010+
       #010+
    -  'Supported Optimizations:'#010+
    +  'Supported Optimi','zations:'#010+
       '  $OPTIMIZATIONS'#010+
       #010+
    -  'Supported Whole Program Optimiz','ations:'#010+
    +  'Supported Whole Program Optimizations:'#010+
       '  All'#010+
       '  $WPOPTIMIZATIONS'#010+
       #010+
       'Supported Microcontroller types:$\n  $CONTROLLERTYPES$\n'#010+
       'This program comes under the GNU General Public Licence'#010+
    -  'For more information read COPYING.v2'#010+
    +  'For more information read COPYING.v','2'#010+
       #010+
       'Please report bugs in our bug tracker on:'#010+
    -  '             ','    http://bugs.freepascal.org'#010+
    +  '                 http://bugs.freepascal.org'#010+
       #010+
       'More information may be found on our WWW pages (including directions'#010+
       'for mailing lists useful for asking questions or discussing potential'#010+
    -  'new features, etc.):'#010+
    +  'new feature','s, etc.):'#010+
       '                 http://www.freepascal.org'#000+
    -  '11025','_F*0*_Only options valid for the default or selected platform a'+
    -  're listed.'#010+
    +  '11025_F*0*_Only options valid for the default or selected platform are'+
    +  ' listed.'#010+
       '**0*_Put + after a boolean switch option to enable it, - to disable it'+
       '.'#010+
    -  '**1@<x>_Read compiler options from <x> in addition to the default fpc.'+
    -  'cfg'#010+
    -  '**1a_The compiler do','es not delete the generated assembler file'#010+
    +  '**1@<x>_Read compiler options from <','x> in addition to the default fp'+
    +  'c.cfg'#010+
    +  '**1a_The compiler does not delete the generated assembler file'#010+
       '**2a5_Don'#039't generate Big Obj COFF files for GNU Binutils older tha'+
       'n 2.25 (Windows, NativeNT)'#010+
    -  '**2al_List sourcecode lines in assembler file'#010+
    -  '**2an_List node info in assembler file (-dEXTDEBUG compile','r)'#010+
    +  '**2al_List sourcecode lines in assembler file'#010,
    +  '**2an_List node info in assembler file (-dEXTDEBUG compiler)'#010+
       '**2ao_Add an extra option to external assembler call (ignored for inte'+
       'rnal)'#010+
       '*L2ap_Use pipes instead of creating temporary assembler files'#010+
    -  '**2ar_List register allocation/release info in assembler file'#010+
    -  '**2at_List temp allocation/release in','fo in assembler file'#010+
    +  '**2ar_List register allocation/release in','fo in assembler file'#010+
    +  '**2at_List temp allocation/release info in assembler file'#010+
       '**1A<x>_Output format:'#010+
       '**2Adefault_Use default assembler'#010+
       '3*2Aas_Assemble using GNU AS'#010+
       '3*2Amacho_Mach-O (Darwin, Intel 32 bit) using internal writer'#010+
    -  '8*2Anasm_Assemble using Nasm'#010+
    +  '8*2Anasm_Asse','mble using Nasm'#010+
       '8*2Anasmobj_Assemble using Nasm'#010+
    -  '3*2Anasm_A','ssemble using Nasm'#010+
    +  '3*2Anasm_Assemble using Nasm'#010+
       '3*2Anasmcoff_COFF (Go32v2) file using Nasm'#010+
       '3*2Anasmelf_ELF32 (Linux) file using Nasm'#010+
       '3*2Anasmwin32_Win32 object file using Nasm'#010+
    -  '3*2Anasmwdosx_Win32/WDOSX object file using Nasm'#010+
    -  '3*2Anasmdarwin_macho32 object file using Nas','m (experimental)'#010+
    +  '3*2Anasmwdosx_Win32/WDOSX object fi','le using Nasm'#010+
    +  '3*2Anasmdarwin_macho32 object file using Nasm (experimental)'#010+
       '3*2Awasm_Obj file using Wasm (Watcom)'#010+
       '3*2Anasmobj_Obj file using Nasm'#010+
       '3*2Amasm_Obj file using Masm (Microsoft)'#010+
       '3*2Atasm_Obj file using Tasm (Borland)'#010+
    -  '3*2Aelf_ELF (Linux) using internal writer'#010+
    -  '3*2Acoff_COFF (Go32v2) using in','ternal writer'#010+
    +  '3*2Aelf_ELF (Li','nux) using internal writer'#010+
    +  '3*2Acoff_COFF (Go32v2) using internal writer'#010+
       '3*2Apecoff_PE-COFF (Win32) using internal writer'#010+
       '3*2Ayasm_Assemble using Yasm (experimental)'#010+
       '4*2Aas_Assemble using GNU AS'#010+
       '4*2Agas_Assemble using GNU GAS'#010+
    -  '4*2Agas-darwin_Assemble darwin Mach-O64 using GNU GAS'#010+
    -  '4*2Amasm_Win64 obje','ct file using ml64 (Microsoft)'#010+
    +  '4*2Agas-darwin_','Assemble darwin Mach-O64 using GNU GAS'#010+
    +  '4*2Amasm_Win64 object file using ml64 (Microsoft)'#010+
       '4*2Apecoff_PE-COFF (Win64) using internal writer'#010+
       '4*2Aelf_ELF (Linux-64bit) using internal writer'#010+
       '4*2Ayasm_Assemble using Yasm (experimental)'#010+
    -  '4*2Anasm_Assemble using Nasm (experimental)'#010+
    -  '4*2Anasmwin64_Assemble W','in64 object file using Nasm (experimental)'#010+
    +  '4*2Anasm_A','ssemble using Nasm (experimental)'#010+
    +  '4*2Anasmwin64_Assemble Win64 object file using Nasm (experimental)'#010+
       '4*2Anasmelf_Assemble Linux-64bit object file using Nasm (experimental)'+
       #010+
    -  '4*2Anasmdarwin_Assemble darwin macho64 object file using Nasm (experim'+
    -  'ental)'#010+
    +  '4*2Anasmdarwin_Assemble darwin macho64 object file using Nasm (exper','i'+
    +  'mental)'#010+
       '6*2Aas_Unix o-file using GNU AS'#010+
    -  '6*2Agas_GNU Motor','ola assembler'#010+
    +  '6*2Agas_GNU Motorola assembler'#010+
       '6*2Amit_MIT Syntax (old GAS)'#010+
       '6*2Amot_Standard Motorola assembler'#010+
       'A*2Aas_Assemble using GNU AS'#010+
       'P*2Aas_Assemble using GNU AS'#010+
       'S*2Aas_Assemble using GNU AS'#010+
    -  '**1b_Generate browser info'#010+
    +  '**1b_Generate br','owser info'#010+
       '**2bl_Generate local symbol info'#010+
    -  '**1B_Build all',' modules'#010+
    +  '**1B_Build all modules'#010+
       '**1C<x>_Code generation options:'#010+
       '**2C3_Turn on ieee error checking for constants'#010+
       '**2Ca<x>_Select ABI; see fpc -i or fpc -ia for possible values'#010+
    -  '**2Cb_Generate code for a big-endian variant of the target architectur'+
    -  'e'#010+
    -  '**2Cc<x>_Set de','fault calling convention to <x>'#010+
    +  '**2Cb_Generate code for a big','-endian variant of the target architect'+
    +  'ure'#010+
    +  '**2Cc<x>_Set default calling convention to <x>'#010+
       '**2CD_Create also dynamic library (not supported)'#010+
       '**2Ce_Compilation with emulated floating point opcodes'#010+
    -  '**2Cf<x>_Select fpu instruction set to use; see fpc -i or fpc -if for '+
    -  'possible values'#010+
    -  '**2CF<x>_Minimal ','floating point constant precision (default, 32, 64)'+
    -  #010+
    +  '**2Cf<x>_Select fpu instruction set to use; s','ee fpc -i or fpc -if fo'+
    +  'r possible values'#010+
    +  '**2CF<x>_Minimal floating point constant precision (default, 32, 64)'#010+
       '**2Cg_Generate PIC code'#010+
       '**2Ch<n>[,m]_<n> bytes min heap size (between 1023 and 67107840) and o'+
       'ptionally [m] max heap size'#010+
    -  '**2Ci_IO-checking'#010+
    -  'A*2CI<x>_Select instruction set on ARM: ARM or T','HUMB'#010+
    +  '**2Ci_IO','-checking'#010+
    +  'A*2CI<x>_Select instruction set on ARM: ARM or THUMB'#010+
       '**2Cn_Omit linking stage'#010+
       'P*2CN_Generate nil-pointer checks (AIX-only)'#010+
       '**2Co_Check overflow of integer operations'#010+
       '**2CO_Check for possible overflow of integer operations'#010+
    -  '**2Cp<x>_Select instruction set; see fpc -i or fpc -ic for possibl','e '+
    +  '**2Cp<x>','_Select instruction set; see fpc -i or fpc -ic for possible '+
       'values'#010+
       '**2CP<x>=<y>_ packing settings'#010+
       '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or DEFAULT or NORMAL, 2, 4 '+
       'and 8'#010+
    -  '**3CPPACKENUM=<y>_ <y> enum packing: 0, 1, 2 and 4 or DEFAULT or NORMA'+
    -  'L'#010+
    -  '**3CPPACKRECORD=<y>_ <y> record packing: 0 or DEFAUL','T or NORMAL, 1, '+
    -  '2, 4, 8, 16 and 32'#010+
    +  '**3CPPACKENUM=<y>_ <y> enum packing: 0, 1, 2 and 4 or DEFAULT or N','OR'+
    +  'MAL'#010+
    +  '**3CPPACKRECORD=<y>_ <y> record packing: 0 or DEFAULT or NORMAL, 1, 2,'+
    +  ' 4, 8, 16 and 32'#010+
       '**2Cr_Range checking'#010+
       '**2CR_Verify object method call validity'#010+
       '**2Cs<n>_Set stack checking size to <n>'#010+
    -  '**2Ct_Stack checking (for testing only, see manual)'#010+
    +  '**2Ct_Stack checking (for testing only, see m','anual)'#010+
       '8*2CT<x>_Target-specific code generation options'#010+
    -  '3*','2CT<x>_Target-specific code generation options'#010+
    +  '3*2CT<x>_Target-specific code generation options'#010+
       '4*2CT<x>_Target-specific code generation options'#010+
       'p*2CT<x>_Target-specific code generation options'#010+
    -  'P*2CT<x>_Target-specific code generation options'#010+
    -  'J*2CT<x>_Target-specific code generation optio','ns'#010+
    +  'P*2CT<x>_Target-specific code generat','ion options'#010+
    +  'J*2CT<x>_Target-specific code generation options'#010+
       'A*2CT<x>_Target-specific code generation options'#010+
       'p*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
       ' (AIX)'#010+
    -  'P*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
    -  ' (AIX)'#010+
    -  'J*3CTautogetterprefix=X_  Automati','cally create getters for propertie'+
    -  's with prefix X (empty string disables)'#010+
    +  'P*3CTsmalltoc_ Generate smaller TOCs at the expense o','f execution spe'+
    +  'ed (AIX)'#010+
    +  'J*3CTautogetterprefix=X_  Automatically create getters for properties '+
    +  'with prefix X (empty string disables)'#010+
       'J*3CTautosetterprefix=X_  Automatically create setters for properties '+
    -  'with prefix X (empty string disables)'#010+
    -  '8*3CTcld_                 Emit a CLD instruction before us','ing the x8'+
    -  '6 string instructions'#010+
    +  'with prefix X (empty string disables)'#010,
    +  '8*3CTcld_                 Emit a CLD instruction before using the x86 '+
    +  'string instructions'#010+
       '3*3CTcld_                 Emit a CLD instruction before using the x86 '+
       'string instructions'#010+
    -  '4*3CTcld_                 Emit a CLD instruction before using the x86 '+
    -  'string instructions'#010+
    -  '8*3CTfarprocspushoddbp_     ','  Increment BP before pushing it in the '+
    -  'prologue of far functions'#010+
    +  '4*3CTcld_                 Emit a CLD instruction before usin','g the x8'+
    +  '6 string instructions'#010+
    +  '8*3CTfarprocspushoddbp_       Increment BP before pushing it in the pr'+
    +  'ologue of far functions'#010+
       'J*3CTcompactintarrayinit_ Generate smaller (but potentially slower) co'+
       'de for initializing integer array constants'#010+
    -  'J*3CTenumfieldinit_       Initialize enumeration fields in c','onstruct'+
    +  'J*','3CTenumfieldinit_       Initialize enumeration fields in construct'+
       'ors to enumtype(0), after calling inherited constructors'#010+
       'J*3CTinitlocals_          Initialize local variables that trigger a JV'+
    -  'M bytecode verification error if used uninitialized (slows down code)'#010+
    -  'J*3CTlowercaseprocstart_  Lowercase',' the first character of procedure'+
    -  '/function/method names'#010+
    +  'M bytecode verification error if used uninitial','ized (slows down code'+
    +  ')'#010+
    +  'J*3CTlowercaseprocstart_  Lowercase the first character of procedure/f'+
    +  'unction/method names'#010+
       'A*3CTthumbinterworking_ Generate Thumb interworking-safe code if possi'+
       'ble'#010+
       'J*2Cv_Var/out parameter copy-out checking'#010+
    -  '**2CX_Create also smartlinked library'#010+
    -  '**1d<x>_Defines the symbol <x>',#010+
    +  '**2CX_Crea','te also smartlinked library'#010+
    +  '**1d<x>_Defines the symbol <x>'#010+
       '**1D_Generate a DEF file'#010+
       '**2Dd<x>_Set description to <x>'#010+
       '**2Dv<x>_Set DLL version to <x>'#010+
    @@ -1526,148 +1525,148 @@
       '**1e<x>_Set path to executable'#010+
       '**1E_Same as -Cn'#010+
       '**1fPIC_Same as -Cg'#010+
    -  '**1F<x>_Set file names and paths:'#010+
    -  '**2Fa<x>[,y]_(for a program',') load units <x> and [y] before uses is p'+
    -  'arsed'#010+
    +  '**1','F<x>_Set file names and paths:'#010+
    +  '**2Fa<x>[,y]_(for a program) load units <x> and [y] before uses is par'+
    +  'sed'#010+
       '**2Fc<x>_Set input codepage to <x>'#010+
       '**2FC<x>_Set RC compiler binary name to <x>'#010+
       '**2Fd_Disable the compiler'#039's internal directory cache'#010+
    -  '**2FD<x>_Set the directory where to search for compiler util','ities'#010+
    +  '**','2FD<x>_Set the directory where to search for compiler utilities'#010+
       '**2Fe<x>_Redirect error output to <x>'#010+
       '**2Ff<x>_Add <x> to framework path (Darwin only)'#010+
       '**2FE<x>_Set exe/unit output path to <x>'#010+
       '**2Fi<x>_Add <x> to include path'#010+
    -  '**2Fl<x>_Add <x> to library path'#010+
    +  '**2Fl<x>_Add <x','> to library path'#010+
       '**2FL<x>_Use <x> as dynamic linker'#010+
    -  '**2Fm','<x>_Load unicode conversion table from <x>.txt in the compiler '+
    -  'dir'#010+
    +  '**2Fm<x>_Load unicode conversion table from <x>.txt in the compiler di'+
    +  'r'#010+
       '**2FM<x>_Set the directory where to search for unicode binary files'#010+
       '**2Fo<x>_Add <x> to object path'#010+
    -  '**2Fr<x>_Load error message file <x>'#010+
    -  '**2FR<x>_Set resource (.res) linker ','to <x>'#010+
    +  '**2Fr<x>_Load e','rror message file <x>'#010+
    +  '**2FR<x>_Set resource (.res) linker to <x>'#010+
       '**2Fu<x>_Add <x> to unit path'#010+
       '**2FU<x>_Set unit output path to <x>, overrides -FE'#010+
       '**2FW<x>_Store generated whole-program optimization feedback in <x>'#010+
    -  '**2Fw<x>_Load previously stored whole-program optimization feedback fr'+
    -  'om <x>'#010+
    -  '*g1g_G','enerate debug information (default format for target)'#010+
    +  '**2Fw<x>_Load previously ','stored whole-program optimization feedback '+
    +  'from <x>'#010+
    +  '*g1g_Generate debug information (default format for target)'#010+
       '*g2gc_Generate checks for pointers (experimental, only available on so'+
       'me targets, might generate false positive)'#010+
    -  '*g2gh_Use heaptrace unit (for memory leak/corruption debugging)'#010+
    -  '*g2gl_Use',' line info unit (show more info with backtraces)'#010+
    +  '*g2gh_Use heapt','race unit (for memory leak/corruption debugging)'#010+
    +  '*g2gl_Use line info unit (show more info with backtraces)'#010+
       '*g2go<x>_Set debug information options'#010+
       '*g3godwarfsets_ Enable DWARF '#039'set'#039' type debug information (bre'+
       'aks gdb < 6.5)'#010+
    -  '*g3gostabsabsincludes_ Store absolute/full include file paths in Stabs'+
    -  #010+
    -  '*g3g','odwarfmethodclassprefix_ Prefix method names in DWARF with class'+
    -  ' name'#010+
    +  '*g3gostabsabsincl','udes_ Store absolute/full include file paths in Sta'+
    +  'bs'#010+
    +  '*g3godwarfmethodclassprefix_ Prefix method names in DWARF with class n'+
    +  'ame'#010+
       '*g3godwarfcpp_ Simulate C++ debug information in DWARF'#010+
       '*g2gp_Preserve case in stabs symbol names'#010+
    -  '*g2gs_Generate Stabs debug information'#010+
    -  '*g2gt_Trash local variables (to de','tect uninitialized uses; multiple '+
    -  #039't'#039' changes the trashing value)'#010+
    +  '*g2gs_Generate ','Stabs debug information'#010+
    +  '*g2gt_Trash local variables (to detect uninitialized uses; multiple '#039+
    +  't'#039' changes the trashing value)'#010+
       '*g2gv_Generates programs traceable with Valgrind'#010+
       '*g2gw_Generate DWARFv2 debug information (same as -gw2)'#010+
    -  '*g2gw2_Generate DWARFv2 debug information'#010+
    -  '*g2gw3_Generate DWARFv3 deb','ug information'#010+
    +  '*g2gw2_Gene','rate DWARFv2 debug information'#010+
    +  '*g2gw3_Generate DWARFv3 debug information'#010+
       '*g2gw4_Generate DWARFv4 debug information (experimental)'#010+
       '**1i_Information'#010+
       '**2iD_Return compiler date'#010+
       '**2iSO_Return compiler OS'#010+
       '**2iSP_Return compiler host processor'#010+
    -  '**2iTO_Return target OS'#010+
    +  '**','2iTO_Return target OS'#010+
       '**2iTP_Return target processor'#010+
    -  '**2iV','_Return short compiler version'#010+
    +  '**2iV_Return short compiler version'#010+
       '**2iW_Return full compiler version'#010+
       '**2ia_Return list of supported ABI targets'#010+
       '**2ic_Return list of supported CPU instruction sets'#010+
    -  '**2if_Return list of supported FPU instruction sets'#010+
    -  '**2ii_Return list of suppor','ted inline assembler modes'#010+
    +  '**2if_Return list of ','supported FPU instruction sets'#010+
    +  '**2ii_Return list of supported inline assembler modes'#010+
       '**2io_Return list of supported optimizations'#010+
       '**2ir_Return list of recognized compiler and RTL features'#010+
       '**2it_Return list of supported targets'#010+
    -  '**2iu_Return list of supported microcontroller types'#010+
    -  '**2iw_Return list ','of supported whole program optimizations'#010+
    +  '**2iu_Return ','list of supported microcontroller types'#010+
    +  '**2iw_Return list of supported whole program optimizations'#010+
       '**1I<x>_Add <x> to include path'#010+
       '**1k<x>_Pass <x> to the linker'#010+
       '**1l_Write logo'#010+
       '**1M<x>_Set language mode to <x>'#010+
    -  '**2Mfpc_Free Pascal dialect (default)'#010+
    +  '**2Mfpc_Free Pascal dialect (','default)'#010+
       '**2Mobjfpc_FPC mode with Object Pascal support'#010+
    -  '**','2Mdelphi_Delphi 7 compatibility mode'#010+
    +  '**2Mdelphi_Delphi 7 compatibility mode'#010+
       '**2Mtp_TP/BP 7.0 compatibility mode'#010+
       '**2Mmacpas_Macintosh Pascal dialects compatibility mode'#010+
       '**2Miso_ISO 7185 mode'#010+
    -  '**2Mextendedpascal_ISO 10206 mode'#010+
    -  '**2Mdelphiunicode_Delphi 2009 and later compatibility m','ode'#010+
    +  '**2Mextendedpascal_ISO 10206 mo','de'#010+
    +  '**2Mdelphiunicode_Delphi 2009 and later compatibility mode'#010+
       '**1n_Do not read the default config files'#010+
       '**1o<x>_Change the name of the executable produced to <x>'#010+
       '**1O<x>_Optimizations:'#010+
       '**2O-_Disable optimizations'#010+
    -  '**2O1_Level 1 optimizations (quick and debugger friendly)'#010+
    -  '**2O2_Level 2 optimizations',' (-O1 + quick optimizations)'#010+
    +  '**2O1_Level 1 optimizations',' (quick and debugger friendly)'#010+
    +  '**2O2_Level 2 optimizations (-O1 + quick optimizations)'#010+
       '**2O3_Level 3 optimizations (-O2 + slow optimizations)'#010+
       '**2O4_Level 4 optimizations (-O3 + optimizations which might have unex'+
       'pected side effects)'#010+
    -  '**2Oa<x>=<y>_Set alignment'#010+
    -  '**2Oo[NO]<x>_Enable or disable optimiz','ations; see fpc -i or fpc -io '+
    -  'for possible values'#010+
    +  '**2Oa<x','>=<y>_Set alignment'#010+
    +  '**2Oo[NO]<x>_Enable or disable optimizations; see fpc -i or fpc -io fo'+
    +  'r possible values'#010+
       '**2Op<x>_Set target cpu for optimizing; see fpc -i or fpc -ic for poss'+
       'ible values'#010+
    -  '**2OW<x>_Generate whole-program optimization feedback for optimization'+
    -  ' <x>; see fpc -i or fpc -iw for possib','le values'#010+
    +  '**2OW<x>_Generate whole-program optimization feedb','ack for optimizati'+
    +  'on <x>; see fpc -i or fpc -iw for possible values'#010+
       '**2Ow<x>_Perform whole-program optimization <x>; see fpc -i or fpc -iw'+
       ' for possible values'#010+
       '**2Os_Optimize for size rather than speed'#010+
    -  '**1pg_Generate profile code for gprof (defines FPC_PROFILE)'#010+
    -  'F*1P<x>_Target CPU / compiler related',' options:'#010+
    +  '**1pg_Generate profile code for gprof (','defines FPC_PROFILE)'#010+
    +  'F*1P<x>_Target CPU / compiler related options:'#010+
       'F*2PB_Show default compiler binary'#010+
       'F*2PP_Show default target cpu'#010+
       'F*2P<x>_Set target CPU (aarch64,arm,avr,i386,i8086,jvm,m68k,mips,mipse'+
       'l,powerpc,powerpc64,sparc,x86_64)'#010+
    -  '**1R<x>_Assembler reading style:'#010+
    -  '**2Rdefault_Use default asse','mbler for target'#010+
    +  '**1','R<x>_Assembler reading style:'#010+
    +  '**2Rdefault_Use default assembler for target'#010+
       '3*2Ratt_Read AT&T style assembler'#010+
       '3*2Rintel_Read Intel style assembler'#010+
       '4*2Ratt_Read AT&T style assembler'#010+
       '4*2Rintel_Read Intel style assembler'#010+
    -  '8*2Ratt_Read AT&T style assembler'#010+
    +  '8*2Ratt_Read AT&T style',' assembler'#010+
       '8*2Rintel_Read Intel style assembler'#010+
    -  '6*2RMOT_Re','ad Motorola style assembler'#010+
    +  '6*2RMOT_Read Motorola style assembler'#010+
       '**1S<x>_Syntax options:'#010+
       '**2S2_Same as -Mobjfpc'#010+
       '**2Sc_Support operators like C (*=,+=,/= and -=)'#010+
       '**2Sa_Turn on assertions'#010+
       '**2Sd_Same as -Mdelphi'#010+
    -  '**2Se<x>_Error options. <x> is a combination of the following:'#010+
    -  '**3*_','<n> : Compiler halts after the <n> errors (default is 1)'#010+
    +  '**2Se<x>_E','rror options. <x> is a combination of the following:'#010+
    +  '**3*_<n> : Compiler halts after the <n> errors (default is 1)'#010+
       '**3*_w : Compiler also halts after warnings'#010+
       '**3*_n : Compiler also halts after notes'#010+
    -  '**3*_h : Compiler also halts after hints'#010+
    -  '**2Sf_Enable certain features in compiler and RTL; see fp','c -i or fpc'+
    -  ' -ir for possible values)'#010+
    +  '**3*_h : Compiler also halts after hints',#010+
    +  '**2Sf_Enable certain features in compiler and RTL; see fpc -i or fpc -'+
    +  'ir for possible values)'#010+
       '**2Sg_Enable LABEL and GOTO (default in -Mtp and -Mdelphi)'#010+
       '**2Sh_Use reference counted strings (ansistring by default) instead of'+
       ' shortstrings'#010+
    -  '**2Si_Turn on inlining of procedures/functions declared as "','inline"'#010+
    +  '**','2Si_Turn on inlining of procedures/functions declared as "inline"'#010+
       '**2Sj_Allows typed constants to be writeable (default in all modes)'#010+
       '**2Sk_Load fpcylix unit'#010+
       '**2SI<x>_Set interface style to <x>'#010+
       '**3SIcom_COM compatible interface (default)'#010+
    -  '**3SIcorba_CORBA compatible interface'#010+
    -  '**2Sm_Support macros l','ike C (global)'#010+
    +  '**','3SIcorba_CORBA compatible interface'#010+
    +  '**2Sm_Support macros like C (global)'#010+
       '**2So_Same as -Mtp'#010+
       '**2Sr_Transparent file names in ISO mode'#010+
       '**2Ss_Constructor name must be init (destructor must be done)'#010+
    -  '**2Sv_Support vector processing (use CPU vector extensions if availabl'+
    -  'e)'#010+
    -  '**2Sx_Enable exception keyword','s (default in Delphi/ObjFPC modes)'#010+
    +  '**2Sv_Support vector processing (use CPU vect','or extensions if availa'+
    +  'ble)'#010+
    +  '**2Sx_Enable exception keywords (default in Delphi/ObjFPC modes)'#010+
       '**2Sy_@<pointer> returns a typed pointer, same as $T+'#010+
       '**1s_Do not call assembler and linker'#010+
       '**2sh_Generate script to link on host'#010+
    -  '**2st_Generate script to link on target'#010+
    -  '**2sr_Skip register allocation phas','e (use with -alr)'#010+
    +  '**2st_Generate sc','ript to link on target'#010+
    +  '**2sr_Skip register allocation phase (use with -alr)'#010+
       '**1T<x>_Target operating system:'#010+
       '3*2Tandroid_Android'#010+
       '3*2Taros_AROS'#010+
    @@ -1674,25 +1673,25 @@
       '3*2Tbeos_BeOS'#010+
       '3*2Tdarwin_Darwin/Mac OS X'#010+
       '3*2Tembedded_Embedded'#010+
    -  '3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+
    +  '3*2Temx_OS/2 via EMX (including EM','X/RSX extender)'#010+
       '3*2Tfreebsd_FreeBSD'#010+
    -  '3*2Tgo32v2_Version 2 o','f DJ Delorie DOS extender'#010+
    +  '3*2Tgo32v2_Version 2 of DJ Delorie DOS extender'#010+
       '3*2Thaiku_Haiku'#010+
       '3*2Tiphonesim_iPhoneSimulator from iOS SDK 3.2+ (older versions: -Tdar'+
       'win)'#010+
       '3*2Tlinux_Linux'#010+
       '3*2Tnativent_Native NT API (experimental)'#010+
    -  '3*2Tnetbsd_NetBSD'#010+
    +  '3*2Tnet','bsd_NetBSD'#010+
       '3*2Tnetware_Novell Netware Module (clib)'#010+
    -  '3*2Tne','twlibc_Novell Netware Module (libc)'#010+
    +  '3*2Tnetwlibc_Novell Netware Module (libc)'#010+
       '3*2Topenbsd_OpenBSD'#010+
       '3*2Tos2_OS/2 / eComStation'#010+
       '3*2Tsymbian_Symbian OS'#010+
       '3*2Tsolaris_Solaris'#010+
       '3*2Twatcom_Watcom compatible DOS extender'#010+
    -  '3*2Twdosx_WDOSX DOS extender'#010+
    +  '3*2Twdosx_WDOS','X DOS extender'#010+
       '3*2Twin32_Windows 32 Bit'#010+
    -  '3*2Twince_Windows ','CE'#010+
    +  '3*2Twince_Windows CE'#010+
       '4*2Taros_AROS'#010+
       '4*2Tdarwin_Darwin/Mac OS X'#010+
       '4*2Tdragonfly_DragonFly BSD'#010+
    @@ -1701,9 +1700,9 @@
       '4*2Tiphonesim_iPhoneSimulator'#010+
       '4*2Tlinux_Linux'#010+
       '4*2Tnetbsd_NetBSD'#010+
    -  '4*2Topenbsd_OpenBSD'#010+
    +  '4*2T','openbsd_OpenBSD'#010+
       '4*2Tsolaris_Solaris'#010+
    -  '4*2Twin64_Win64 (64 bi','t Windows systems)'#010+
    +  '4*2Twin64_Win64 (64 bit Windows systems)'#010+
       '6*2Tamiga_Commodore Amiga'#010+
       '6*2Tatari_Atari ST/STe/TT'#010+
       '6*2Tembedded_Embedded'#010+
    @@ -1711,9 +1710,9 @@
       '6*2Tnetbsd_NetBSD'#010+
       '6*2Tmacos_Mac OS'#010+
       '6*2Tpalmos_PalmOS'#010+
    -  '8*2Tembedded_Embedded'#010+
    +  '8*2Tembedded_Embedde','d'#010+
       '8*2Tmsdos_MS-DOS (and compatible)'#010+
    -  '8*2Twin16_Windows 16 B','it'#010+
    +  '8*2Twin16_Windows 16 Bit'#010+
       'A*2Tandroid_Android'#010+
       'A*2Taros_AROS'#010+
       'A*2Tdarwin_Darwin/iPhoneOS/iOS'#010+
    @@ -1722,10 +1721,10 @@
       'A*2Tlinux_Linux'#010+
       'A*2Tnds_Nintendo DS'#010+
       'A*2Tnetbsd_NetBSD'#010+
    -  'A*2Tpalmos_PalmOS'#010+
    +  'A*2Tpalmos_Pa','lmOS'#010+
       'A*2Tsymbian_Symbian'#010+
       'A*2Twince_Windows CE'#010+
    -  'a*2Tdarwin_D','arwin/iOS'#010+
    +  'a*2Tdarwin_Darwin/iOS'#010+
       'a*2Tlinux_Linux'#010+
       'J*2Tandroid_Android'#010+
       'J*2Tjava_Java'#010+
    @@ -1735,10 +1734,10 @@
       'M*2Tembedded_Embedded'#010+
       'M*2Tlinux_Linux'#010+
       'P*2Taix_AIX'#010+
    -  'P*2Tamiga_AmigaOS'#010+
    +  'P*2Tamiga_Amig','aOS'#010+
       'P*2Tdarwin_Darwin/Mac OS X'#010+
       'P*2Tembedded_Embedded'#010+
    -  'P*2Tl','inux_Linux'#010+
    +  'P*2Tlinux_Linux'#010+
       'P*2Tmacos_Mac OS (classic)'#010+
       'P*2Tmorphos_MorphOS'#010+
       'P*2Tnetbsd_NetBSD'#010+
    @@ -1748,148 +1747,147 @@
       'p*2Tembedded_Embedded'#010+
       'p*2Tlinux_Linux'#010+
       'S*2Tlinux_Linux'#010+
    -  'S*2Tsolaris_Solaris'#010+
    +  'S','*2Tsolaris_Solaris'#010+
       's*2Tlinux_Linux'#010+
       'V*2Tembedded_Embedded'#010+
    -  '*','*1u<x>_Undefines the symbol <x>'#010+
    +  '**1u<x>_Undefines the symbol <x>'#010+
       '**1U_Unit options:'#010+
       '**2Un_Do not check where the unit name matches the file name'#010+
       '**2Ur_Generate release unit files (never automatically recompiled)'#010+
    -  '**2Us_Compile a system unit'#010+
    -  '**1v<x>_Be verbose. <x> is a comb','ination of the following letters:'#010+
    +  '**2','Us_Compile a system unit'#010+
    +  '**1v<x>_Be verbose. <x> is a combination of the following letters:'#010+
       '**2*_e : Show errors (default)       0 : Show nothing (except errors)'#010+
       '**2*_w : Show warnings               u : Show unit info'#010+
    -  '**2*_n : Show notes                  t : Show tried/used files'#010+
    -  '**2*_h : Show hin','ts                  c : Show conditionals'#010+
    +  '**2*_n : Show notes   ','               t : Show tried/used files'#010+
    +  '**2*_h : Show hints                  c : Show conditionals'#010+
       '**2*_i : Show general info           d : Show debug info'#010+
       '**2*_l : Show linenumbers            r : Rhide/GCC compatibility mode'#010+
    -  '**2*_s : Show time stamps            q : Show message numbers'#010+
    -  '**2*_a : ','Show everything             x : Show info about invoked too'+
    -  'ls'#010+
    +  '**2*_s : Show',' time stamps            q : Show message numbers'#010+
    +  '**2*_a : Show everything             x : Show info about invoked tools'+
    +  #010+
       '**2*_b : Write file names messages   p : Write tree.log with parse tre'+
       'e'#010+
    -  '**2*_    with full path              v : Write fpcdebug.txt with'#010+
    -  '**2*_z : Write output to stderr          ','lots of debugging info'#010+
    +  '**2*_    with full path              v : Write f','pcdebug.txt with'#010+
    +  '**2*_z : Write output to stderr          lots of debugging info'#010+
       '**2*_m<x>,<y> : Do not show messages numbered <x> and <y>'#010+
       'F*1V<x>_Append '#039'-<x>'#039' to the used compiler binary name (e.g. f'+
       'or version)'#010+
    -  '**1W<x>_Target-specific options (targets)'#010+
    -  '3*2WA_Specify native type application (Wind','ows)'#010+
    +  '**1W<x>_Target-specific opt','ions (targets)'#010+
    +  '3*2WA_Specify native type application (Windows)'#010+
       '4*2WA_Specify native type application (Windows)'#010+
       'A*2WA_Specify native type application (Windows)'#010+
       '3*2Wb_Create a bundle instead of a library (Darwin)'#010+
    -  'P*2Wb_Create a bundle instead of a library (Darwin)'#010+
    -  'p*2Wb_Create a bundle instead of a ','library (Darwin)'#010+
    +  'P*2Wb_Create a bundle instead',' of a library (Darwin)'#010+
    +  'p*2Wb_Create a bundle instead of a library (Darwin)'#010+
       'a*2Wb_Create a bundle instead of a library (Darwin)'#010+
       'A*2Wb_Create a bundle instead of a library (Darwin)'#010+
       '4*2Wb_Create a bundle instead of a library (Darwin)'#010+
    -  '3*2WB_Create a relocatable image (Windows, Symbian)'#010+
    -  '3*2WB<x>_Set im','age base to <x> (Windows, Symbian)'#010+
    +  '3*2WB_Cre','ate a relocatable image (Windows, Symbian)'#010+
    +  '3*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
       '4*2WB_Create a relocatable image (Windows)'#010+
       '4*2WB<x>_Set image base to <x> (Windows)'#010+
       'A*2WB_Create a relocatable image (Windows, Symbian)'#010+
    -  'A*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
    -  '3*2WC_Specify conso','le type application (EMX, OS/2, Windows)'#010+
    +  'A*2WB<x>_Se','t image base to <x> (Windows, Symbian)'#010+
    +  '3*2WC_Specify console type application (EMX, OS/2, Windows)'#010+
       '4*2WC_Specify console type application (Windows)'#010+
       'A*2WC_Specify console type application (Windows)'#010+
    -  'P*2WC_Specify console type application (Classic Mac OS)'#010+
    -  '3*2WD_Use DEFFILE to export functions of DLL ','or EXE (Windows)'#010+
    +  'P*2WC_Specify console type application (Cla','ssic Mac OS)'#010+
    +  '3*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
       '4*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
       'A*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
       '3*2We_Use external resources (Darwin)'#010+
    -  '4*2We_Use external resources (Darwin)'#010+
    -  'a*2We_Use external reso','urces (Darwin)'#010+
    +  '4*2','We_Use external resources (Darwin)'#010+
    +  'a*2We_Use external resources (Darwin)'#010+
       'A*2We_Use external resources (Darwin)'#010+
       'P*2We_Use external resources (Darwin)'#010+
       'p*2We_Use external resources (Darwin)'#010+
    -  '3*2WF_Specify full-screen type application (EMX, OS/2)'#010+
    -  '3*2WG_Specify graphic type application (EMX, OS/2, Windo','ws)'#010+
    +  '3*2WF_Specify full-screen type application (EMX, OS/2',')'#010+
    +  '3*2WG_Specify graphic type application (EMX, OS/2, Windows)'#010+
       '4*2WG_Specify graphic type application (Windows)'#010+
       'A*2WG_Specify graphic type application (Windows)'#010+
       'P*2WG_Specify graphic type application (Classic Mac OS)'#010+
    -  '3*2Wi_Use internal resources (Darwin)'#010+
    +  '3*2Wi_Use internal resou','rces (Darwin)'#010+
       '4*2Wi_Use internal resources (Darwin)'#010+
    -  'a*2Wi_','Use internal resources (Darwin)'#010+
    +  'a*2Wi_Use internal resources (Darwin)'#010+
       'A*2Wi_Use internal resources (Darwin)'#010+
       'P*2Wi_Use internal resources (Darwin)'#010+
       'p*2Wi_Use internal resources (Darwin)'#010+
    -  '3*2WI_Turn on/off the usage of import sections (Windows)'#010+
    -  '4*2WI_Turn on/off the usage of import',' sections (Windows)'#010+
    +  '3*2WI_Turn on/off the usage of impor','t sections (Windows)'#010+
    +  '4*2WI_Turn on/off the usage of import sections (Windows)'#010+
       'A*2WI_Turn on/off the usage of import sections (Windows)'#010+
       '8*2Wh_Use huge code for units (ignored for models with CODE in a uniqu'+
       'e segment)'#010+
    -  '8*2Wm<x>_Set memory model'#010+
    +  '8*2Wm<x>_Set memory mode','l'#010+
       '8*3WmTiny_Tiny memory model'#010+
    -  '8*3WmSmall_Small memory mode','l (default)'#010+
    +  '8*3WmSmall_Small memory model (default)'#010+
       '8*3WmMedium_Medium memory model'#010+
       '8*3WmCompact_Compact memory model'#010+
       '8*3WmLarge_Large memory model'#010+
       '8*3WmHuge_Huge memory model'#010+
    -  '3*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
    +  '3*2WM<x>_Minimum Mac OS X deployment version: ','10.4, 10.5.1, ... (Dar'+
    +  'win)'#010+
    +  '4*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
       'n)'#010+
    -  '4*2WM<x>_Minimum Mac OS X deplo','yment version: 10.4, 10.5.1, ... (Dar'+
    -  'win)'#010+
       'p*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
       'n)'#010+
    -  'P*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
    -  'n)'#010+
    -  '3*2WN_Do not generate relocation code, needed for de','bugging (Windows'+
    -  ')'#010+
    +  'P*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Da','r'+
    +  'win)'#010+
    +  '3*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
       '4*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
       'A*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
    -  'A*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
    +  'A*2Wp<x>_Specify the con','troller type; see fpc -i or fpc -iu for poss'+
    +  'ible values'#010+
    +  'm*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
       'le values'#010+
    -  'm*','2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for poss'+
    -  'ible values'#010+
       'V*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
       'le values'#010+
    -  '3*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (iphonesim)'#010+
    -  '4*2WP<x>_Mini','mum iOS deployment version: 8.0, 8.0.2, ... (iphonesim)'+
    +  '3*2WP<x>_Minimum iOS dep','loyment version: 3.0, 5.0.1, ... (iphonesim)'+
       #010+
    +  '4*2WP<x>_Minimum iOS deployment version: 8.0, 8.0.2, ... (iphonesim)'#010+
       'a*2WP<x>_Minimum iOS deployment version: 7.0, 7.1.2, ... (Darwin)'#010+
    -  'A*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (Darwin)'#010+
    +  'A*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (Da','rwin)'#010+
       '3*2WR_Generate relocation code (Windows)'#010+
    -  '4*2WR_Gener','ate relocation code (Windows)'#010+
    +  '4*2WR_Generate relocation code (Windows)'#010+
       'A*2WR_Generate relocation code (Windows)'#010+
       '8*2Wt<x>_Set the target executable format'#010+
       '8*3Wtexe_Create a DOS .EXE file (default)'#010+
    -  '8*3Wtcom_Create a DOS .COM file (requires tiny memory model)'#010+
    -  'P*2WT_Specify MPW tool t','ype application (Classic Mac OS)'#010+
    +  '8*3Wtcom_Create a DOS .COM ','file (requires tiny memory model)'#010+
    +  'P*2WT_Specify MPW tool type application (Classic Mac OS)'#010+
       '**2WX_Enable executable stack (Linux)'#010+
       '**1X_Executable options:'#010+
       '**2X9_Generate linkerscript for GNU Binutils ld older than version 2.1'+
       '9.1 (Linux)'#010+
    -  '**2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, Free','BSD, L'+
    +  '**2X','c_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, L'+
       'inux)'#010+
       '**2Xd_Do not search default library path (sometimes required for cross'+
       '-compiling when not using -XR)'#010+
       '**2Xe_Use external linker'#010+
    -  '**2Xf_Substitute pthread library name for linking (BSD)'#010+
    -  '**2Xg_Create debuginfo in a separate file and',' add a debuglink sectio'+
    -  'n to executable'#010+
    +  '**2Xf_Substitute pthread library name for l','inking (BSD)'#010+
    +  '**2Xg_Create debuginfo in a separate file and add a debuglink section '+
    +  'to executable'#010+
       '**2XD_Try to link units dynamically      (defines FPC_LINK_DYNAMIC)'#010+
       '**2Xi_Use internal linker'#010+
       '**2XLA_Define library substitutions for linking'#010+
    -  '**2XLO_Define order of library linking'#010+
    -  '**2XLD_Exclude defau','lt order of standard libraries'#010+
    +  '*','*2XLO_Define order of library linking'#010+
    +  '**2XLD_Exclude default order of standard libraries'#010+
       '**2Xm_Generate link map'#010+
       '**2XM<x>_Set the name of the '#039'main'#039' program routine (default i'+
       's '#039'main'#039')'#010+
    -  '**2Xn_Use target system native linker instead of GNU ld (Solaris, AIX)'+
    -  #010+
    -  'F*2Xp<x>_First search for the compiler bin','ary in the directory <x>'#010+
    +  '**2Xn_Use target system native linker instead of GNU ld',' (Solaris, AI'+
    +  'X)'#010+
    +  'F*2Xp<x>_First search for the compiler binary in the directory <x>'#010+
       '**2XP<x>_Prepend the binutils names with the prefix <x>'#010+
       '**2Xr<x>_Set the linker'#039's rlink-path to <x> (needed for cross comp'+
    -  'ile, see the ld manual for more information) (BeOS, Linux)'#010+
    -  '**2XR<x>_Prepend <x> to all linker',' search paths (BeOS, Darwin, FreeB'+
    -  'SD, Linux, Mac OS, Solaris)'#010+
    +  'ile, see the ld manual for more inf','ormation) (BeOS, Linux)'#010+
    +  '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, FreeBSD'+
    +  ', Linux, Mac OS, Solaris)'#010+
       '**2Xs_Strip all symbols from executable'#010+
       '**2XS_Try to link units statically (default, defines FPC_LINK_STATIC)'#010+
    -  '**2Xt_Link with static libraries (-static is passed to linker)'#010+
    -  '**2Xv','_Generate table for Virtual Entry calls'#010+
    +  '**2Xt_Link',' with static libraries (-static is passed to linker)'#010+
    +  '**2Xv_Generate table for Virtual Entry calls'#010+
       '**2XV_Use VLink as external linker       (default on Amiga, MorphOS)'#010+
       '**2XX_Try to smartlink units             (defines FPC_LINK_SMART)'#010+
       '**1*_'#010+
    -  '**1?_Show this help'#010+
    +  '*','*1?_Show this help'#010+
       '**1h_Shows this help without waiting'
     );
    Index: compiler/ncnv.pas
    ===================================================================
    --- compiler/ncnv.pas	(revision 38690)
    +++ compiler/ncnv.pas	(working copy)
    @@ -4281,6 +4281,21 @@
                       end;
                   end;
               end
    +        else if (right.resultdef.typ=enumdef) then
    +          begin
    +            if (m_fpc in current_settings.modeswitches) and
    +               (tenumdef(right.resultdef).has_jumps) then
    +              CGMessage(type_e_as_is_enums_with_assign_not_possible);
    +            { left must be an ordinal }
    +            if not is_ordinal(left.resultdef) then
    +              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
    +            case nodetype of
    +              isn:
    +                resultdef:=pasbool8type;
    +              asn:
    +                resultdef:=right.resultdef;
    +            end;
    +          end
             else
               CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
           end;
    @@ -4309,6 +4324,8 @@
             procname: string;
             statement : tstatementnode;
             tempnode : ttempcreatenode;
    +        v,res: Tconstexprint;
    +        leftconv: tnode;
           begin
             result:=nil;
             { Passing a class type to an "is" expression cannot result in a class
    @@ -4354,6 +4371,35 @@
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef);
               end
    +        else if (right.resultdef.typ=enumdef) then
    +          begin
    +            if left.nodetype=ordconstn then
    +              begin
    +                v:=Tordconstnode(left).value;
    +                res.signed:=false;
    +                res.overflow:=false;
    +                if v.signed and ((v.svalue<tenumdef(right.resultdef).min) or (v.svalue>tenumdef(right.resultdef).max)) then
    +                  res.uvalue:=0 { false }
    +                else
    +                if not v.signed and ((v.uvalue<tenumdef(right.resultdef).min) or (v.uvalue>tenumdef(right.resultdef).max)) then
    +                  res.uvalue:=0 { false }
    +                else
    +                  res.uvalue:=1; { true }
    +                result := cordconstnode.create(res, resultdef, false);
    +              end
    +            else
    +              begin
    +                if left.resultdef.typ<>orddef then
    +                  leftconv := ctypeconvnode.create_internal(left, s32inttype)
    +                else
    +                  leftconv := left;
    +                result := ccallnode.createinternres('fpc_do_is_enum',
    +                  ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
    +                    ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
    +                      ccallparanode.create(leftconv, nil))),
    +                  resultdef);
    +              end;
    +          end
             else
               begin
                 if is_class(left.resultdef) then
    @@ -4432,6 +4478,8 @@
         function tasnode.pass_1 : tnode;
           var
             procname: string;
    +        leftconv: tnode;
    +        v: Tconstexprint;
           begin
             result:=nil;
             { Passing a class type to an "as" expression cannot result in a class
    @@ -4450,6 +4498,31 @@
                   call := ccallnode.createinternres('fpc_do_as',
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef)
    +            else if (right.resultdef.typ=enumdef) then
    +              begin
    +                if left.nodetype=ordconstn then
    +                  begin
    +                    v:=Tordconstnode(left).value;
    +                    if v.signed and ((v.svalue<tenumdef(right.resultdef).min) or (v.svalue>tenumdef(right.resultdef).max)) then
    +                      Message(parser_e_range_check_error)
    +                    else
    +                    if not v.signed and ((v.uvalue<tenumdef(right.resultdef).min) or (v.uvalue>tenumdef(right.resultdef).max)) then
    +                      Message(parser_e_range_check_error);
    +                    call := ctypeconvnode.create_internal(left, resultdef);
    +                  end
    +                else
    +                  begin
    +                    if left.resultdef.typ<>orddef then
    +                      leftconv := ctypeconvnode.create_internal(left, s32inttype)
    +                    else
    +                      leftconv := left;
    +                    call := ccallnode.createinternres('fpc_do_as_enum',
    +                      ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
    +                        ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
    +                          ccallparanode.create(leftconv, nil))),
    +                      resultdef)
    +                  end;
    +              end
                 else
                   begin
                     if is_class(left.resultdef) then
    Index: rtl/inc/compproc.inc
    ===================================================================
    --- rtl/inc/compproc.inc	(revision 38690)
    +++ rtl/inc/compproc.inc	(working copy)
    @@ -798,6 +798,8 @@
     
     procedure fpc_AbstractErrorIntern;compilerproc;
     procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
    +function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
    +function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
     
     {$ifdef FPC_HAS_FEATURE_FILEIO}
     Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
    Index: rtl/inc/system.inc
    ===================================================================
    --- rtl/inc/system.inc	(revision 38690)
    +++ rtl/inc/system.inc	(working copy)
    @@ -1528,6 +1528,29 @@
     
     
     {*****************************************************************************
    +                       (I as TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
    +begin
    +  if (value>=minvalue) and (value<=maxvalue) then
    +    result:=value
    +  else
    +    handleerroraddrframeInd(219,get_pc_addr,get_frame);
    +end;
    +
    +
    +{*****************************************************************************
    +                       (I is TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
    +begin
    +  result := (value>=minvalue) and (value<=maxvalue);
    +end;
    +
    +
    +{*****************************************************************************
                            SetJmp/LongJmp support.
     *****************************************************************************}
     
    
    AS-IS-enum-03.patch (95,365 bytes)
  • AS-IS-enum-04.patch (7,725 bytes)
    Index: compiler/msg/errore.msg
    ===================================================================
    --- compiler/msg/errore.msg	(revision 42321)
    +++ compiler/msg/errore.msg	(working copy)
    @@ -2038,6 +2038,7 @@
     % require specialisation for methods or nested subroutines.
     type_e_seg_procvardef_wrong_memory_model=04124_E_Procedure variables in that memory model do not store segment information
     type_w_empty_constant_range_set=04125_W_The first value of a set constructur range is greater then the second value, so the range describes an empty set.
    +type_e_as_is_enums_with_assign_not_possible=04126_E_as or is cannot be used on enums with assignments
     % If a set is constructed like this: \var{s:=[9..7];]}, then an empty set is generated. As this is something normally not desired, the compiler warns about it.
     % \end{description}
     #
    Index: compiler/ncnv.pas
    ===================================================================
    --- compiler/ncnv.pas	(revision 42321)
    +++ compiler/ncnv.pas	(working copy)
    @@ -4344,6 +4344,23 @@
                       end;
                   end;
               end
    +        else if (right.resultdef.typ=enumdef) then
    +          begin
    +            if (m_fpc in current_settings.modeswitches) and
    +               (tenumdef(right.resultdef).has_jumps) then
    +              CGMessage(type_e_as_is_enums_with_assign_not_possible);
    +            { left must be an ordinal }
    +            if not is_ordinal(left.resultdef) then
    +              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
    +            case nodetype of
    +              isn:
    +                resultdef:=pasbool8type;
    +              asn:
    +                resultdef:=right.resultdef;
    +              else
    +                InternalError(2019070201);
    +            end;
    +          end
             else
               CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
           end;
    @@ -4372,6 +4389,8 @@
             procname: string;
             statement : tstatementnode;
             tempnode : ttempcreatenode;
    +        v,res: Tconstexprint;
    +        leftconv: tnode;
           begin
             result:=nil;
             { Passing a class type to an "is" expression cannot result in a class
    @@ -4417,6 +4436,35 @@
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef);
               end
    +        else if (right.resultdef.typ=enumdef) then
    +          begin
    +            if left.nodetype=ordconstn then
    +              begin
    +                v:=Tordconstnode(left).value;
    +                res.signed:=false;
    +                res.overflow:=false;
    +                if v.signed and ((v.svalue<tenumdef(right.resultdef).min) or (v.svalue>tenumdef(right.resultdef).max)) then
    +                  res.uvalue:=0 { false }
    +                else
    +                if not v.signed and ((v.uvalue<tenumdef(right.resultdef).min) or (v.uvalue>tenumdef(right.resultdef).max)) then
    +                  res.uvalue:=0 { false }
    +                else
    +                  res.uvalue:=1; { true }
    +                result := cordconstnode.create(res, resultdef, false);
    +              end
    +            else
    +              begin
    +                if left.resultdef.typ<>orddef then
    +                  leftconv := ctypeconvnode.create_internal(left, s32inttype)
    +                else
    +                  leftconv := left;
    +                result := ccallnode.createinternres('fpc_do_is_enum',
    +                  ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
    +                    ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
    +                      ccallparanode.create(leftconv, nil))),
    +                  resultdef);
    +              end;
    +          end
             else
               begin
                 if is_class(left.resultdef) then
    @@ -4495,6 +4543,8 @@
         function tasnode.pass_1 : tnode;
           var
             procname: string;
    +        leftconv: tnode;
    +        v: Tconstexprint;
           begin
             result:=nil;
             { Passing a class type to an "as" expression cannot result in a class
    @@ -4513,6 +4563,31 @@
                   call := ccallnode.createinternres('fpc_do_as',
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef)
    +            else if (right.resultdef.typ=enumdef) then
    +              begin
    +                if left.nodetype=ordconstn then
    +                  begin
    +                    v:=Tordconstnode(left).value;
    +                    if v.signed and ((v.svalue<tenumdef(right.resultdef).min) or (v.svalue>tenumdef(right.resultdef).max)) then
    +                      Message(parser_e_range_check_error)
    +                    else
    +                    if not v.signed and ((v.uvalue<tenumdef(right.resultdef).min) or (v.uvalue>tenumdef(right.resultdef).max)) then
    +                      Message(parser_e_range_check_error);
    +                    call := ctypeconvnode.create_internal(left, resultdef);
    +                  end
    +                else
    +                  begin
    +                    if left.resultdef.typ<>orddef then
    +                      leftconv := ctypeconvnode.create_internal(left, s32inttype)
    +                    else
    +                      leftconv := left;
    +                    call := ccallnode.createinternres('fpc_do_as_enum',
    +                      ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
    +                        ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
    +                          ccallparanode.create(leftconv, nil))),
    +                      resultdef)
    +                  end;
    +              end
                 else
                   begin
                     if is_class(left.resultdef) then
    Index: rtl/inc/compproc.inc
    ===================================================================
    --- rtl/inc/compproc.inc	(revision 42321)
    +++ rtl/inc/compproc.inc	(working copy)
    @@ -794,6 +794,8 @@
     
     procedure fpc_AbstractErrorIntern;compilerproc;
     procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
    +function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
    +function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
     
     {$ifdef FPC_HAS_FEATURE_FILEIO}
     Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
    Index: rtl/inc/system.inc
    ===================================================================
    --- rtl/inc/system.inc	(revision 42321)
    +++ rtl/inc/system.inc	(working copy)
    @@ -1550,6 +1550,29 @@
     
     
     {*****************************************************************************
    +                       (I as TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
    +begin
    +  if (value>=minvalue) and (value<=maxvalue) then
    +    result:=value
    +  else
    +    handleerroraddrframeInd(219,get_pc_addr,get_frame);
    +end;
    +
    +
    +{*****************************************************************************
    +                       (I is TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
    +begin
    +  result := (value>=minvalue) and (value<=maxvalue);
    +end;
    +
    +
    +{*****************************************************************************
                            SetJmp/LongJmp support.
     *****************************************************************************}
     
    
    AS-IS-enum-04.patch (7,725 bytes)
  • AS-IS-enum-05.patch (6,222 bytes)
    Index: compiler/ncnv.pas
    ===================================================================
    --- compiler/ncnv.pas	(revision 42322)
    +++ compiler/ncnv.pas	(working copy)
    @@ -4344,6 +4344,20 @@
                       end;
                   end;
               end
    +        else if (right.resultdef.typ=enumdef) then
    +          begin
    +            { left must be an ordinal }
    +            if not is_ordinal(left.resultdef) then
    +              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
    +            case nodetype of
    +              isn:
    +                resultdef:=pasbool8type;
    +              asn:
    +                resultdef:=right.resultdef;
    +              else
    +                InternalError(2019070201);
    +            end;
    +          end
             else
               CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
           end;
    @@ -4372,6 +4386,8 @@
             procname: string;
             statement : tstatementnode;
             tempnode : ttempcreatenode;
    +        v,res: Tconstexprint;
    +        leftconv: tnode;
           begin
             result:=nil;
             { Passing a class type to an "is" expression cannot result in a class
    @@ -4417,6 +4433,32 @@
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef);
               end
    +        else if (right.resultdef.typ=enumdef) then
    +          begin
    +            if left.nodetype=ordconstn then
    +              begin
    +                v:=Tordconstnode(left).value;
    +                res.signed:=false;
    +                res.overflow:=false;
    +                if (v<tenumdef(right.resultdef).min) or (v>tenumdef(right.resultdef).max) then
    +                  res.uvalue:=0 { false }
    +                else
    +                  res.uvalue:=1; { true }
    +                result := cordconstnode.create(res, resultdef, false);
    +              end
    +            else
    +              begin
    +                if left.resultdef.typ<>orddef then
    +                  leftconv := ctypeconvnode.create_internal(left, s32inttype)
    +                else
    +                  leftconv := left;
    +                result := ccallnode.createinternres('fpc_do_is_enum',
    +                  ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
    +                    ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
    +                      ccallparanode.create(leftconv, nil))),
    +                  resultdef);
    +              end;
    +          end
             else
               begin
                 if is_class(left.resultdef) then
    @@ -4495,6 +4537,8 @@
         function tasnode.pass_1 : tnode;
           var
             procname: string;
    +        leftconv: tnode;
    +        v: Tconstexprint;
           begin
             result:=nil;
             { Passing a class type to an "as" expression cannot result in a class
    @@ -4513,6 +4557,28 @@
                   call := ccallnode.createinternres('fpc_do_as',
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef)
    +            else if (right.resultdef.typ=enumdef) then
    +              begin
    +                if left.nodetype=ordconstn then
    +                  begin
    +                    v:=Tordconstnode(left).value;
    +                    if (v<tenumdef(right.resultdef).min) or (v>tenumdef(right.resultdef).max) then
    +                      Message(parser_e_range_check_error);
    +                    call := ctypeconvnode.create_internal(left, resultdef);
    +                  end
    +                else
    +                  begin
    +                    if left.resultdef.typ<>orddef then
    +                      leftconv := ctypeconvnode.create_internal(left, s32inttype)
    +                    else
    +                      leftconv := left;
    +                    call := ccallnode.createinternres('fpc_do_as_enum',
    +                      ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
    +                        ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
    +                          ccallparanode.create(leftconv, nil))),
    +                      resultdef)
    +                  end;
    +              end
                 else
                   begin
                     if is_class(left.resultdef) then
    Index: rtl/inc/compproc.inc
    ===================================================================
    --- rtl/inc/compproc.inc	(revision 42322)
    +++ rtl/inc/compproc.inc	(working copy)
    @@ -794,6 +794,8 @@
     
     procedure fpc_AbstractErrorIntern;compilerproc;
     procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
    +function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
    +function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
     
     {$ifdef FPC_HAS_FEATURE_FILEIO}
     Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
    Index: rtl/inc/system.inc
    ===================================================================
    --- rtl/inc/system.inc	(revision 42322)
    +++ rtl/inc/system.inc	(working copy)
    @@ -1550,6 +1550,29 @@
     
     
     {*****************************************************************************
    +                       (I as TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
    +begin
    +  if (value>=minvalue) and (value<=maxvalue) then
    +    result:=value
    +  else
    +    handleerroraddrframeInd(219,get_pc_addr,get_frame);
    +end;
    +
    +
    +{*****************************************************************************
    +                       (I is TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
    +begin
    +  result := (value>=minvalue) and (value<=maxvalue);
    +end;
    +
    +
    +{*****************************************************************************
                            SetJmp/LongJmp support.
     *****************************************************************************}
     
    
    AS-IS-enum-05.patch (6,222 bytes)
  • AS-IS-enum-06.patch (11,952 bytes)
    Index: compiler/msg/errore.msg
    ===================================================================
    --- compiler/msg/errore.msg	(revision 42331)
    +++ compiler/msg/errore.msg	(working copy)
    @@ -2038,6 +2038,7 @@
     % require specialisation for methods or nested subroutines.
     type_e_seg_procvardef_wrong_memory_model=04124_E_Procedure variables in that memory model do not store segment information
     type_w_empty_constant_range_set=04125_W_The first value of a set constructur range is greater then the second value, so the range describes an empty set.
    +type_e_as_is_enums_with_assign_not_possible=04126_E_as or is cannot be used with non-contiguous enumerations
     % If a set is constructed like this: \var{s:=[9..7];]}, then an empty set is generated. As this is something normally not desired, the compiler warns about it.
     % \end{description}
     #
    Index: compiler/ncnv.pas
    ===================================================================
    --- compiler/ncnv.pas	(revision 42331)
    +++ compiler/ncnv.pas	(working copy)
    @@ -4344,6 +4344,20 @@
                       end;
                   end;
               end
    +        else if (right.resultdef.typ=enumdef) then
    +          begin
    +            { left must be an ordinal }
    +            if not is_ordinal(left.resultdef) then
    +              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
    +            case nodetype of
    +              isn:
    +                resultdef:=pasbool8type;
    +              asn:
    +                resultdef:=right.resultdef;
    +              else
    +                InternalError(2019070201);
    +            end;
    +          end
             else
               CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
           end;
    @@ -4372,6 +4386,8 @@
             procname: string;
             statement : tstatementnode;
             tempnode : ttempcreatenode;
    +        v,res: Tconstexprint;
    +        leftconv: tnode;
           begin
             result:=nil;
             { Passing a class type to an "is" expression cannot result in a class
    @@ -4417,6 +4433,32 @@
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef);
               end
    +        else if (right.resultdef.typ=enumdef) then
    +          begin
    +            if left.nodetype=ordconstn then
    +              begin
    +                v:=Tordconstnode(left).value;
    +                res.signed:=false;
    +                res.overflow:=false;
    +                if (v<tenumdef(right.resultdef).min) or (v>tenumdef(right.resultdef).max) then
    +                  res.uvalue:=0 { false }
    +                else
    +                  res.uvalue:=1; { true }
    +                result := cordconstnode.create(res, resultdef, false);
    +              end
    +            else
    +              begin
    +                if left.resultdef.typ<>orddef then
    +                  leftconv := ctypeconvnode.create_internal(left, s32inttype)
    +                else
    +                  leftconv := left;
    +                result := ccallnode.createinternres('fpc_do_is_enum',
    +                  ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
    +                    ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
    +                      ccallparanode.create(leftconv, nil))),
    +                  resultdef);
    +              end;
    +          end
             else
               begin
                 if is_class(left.resultdef) then
    @@ -4443,6 +4485,8 @@
         { you can't instantiate an abstract class                      }
         procedure tisnode.pass_generate_code;
           begin
    +        { It should still never be called though }
    +        InternalError(2019070501);
           end;
     
     
    @@ -4495,6 +4539,8 @@
         function tasnode.pass_1 : tnode;
           var
             procname: string;
    +        leftconv: tnode;
    +        v: Tconstexprint;
           begin
             result:=nil;
             { Passing a class type to an "as" expression cannot result in a class
    @@ -4513,6 +4559,28 @@
                   call := ccallnode.createinternres('fpc_do_as',
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef)
    +            else if (right.resultdef.typ=enumdef) then
    +              begin
    +                if left.nodetype=ordconstn then
    +                  begin
    +                    v:=Tordconstnode(left).value;
    +                    if (v<tenumdef(right.resultdef).min) or (v>tenumdef(right.resultdef).max) then
    +                      Message(parser_e_range_check_error);
    +                    call := ctypeconvnode.create_internal(left, resultdef);
    +                  end
    +                else
    +                  begin
    +                    if left.resultdef.typ<>orddef then
    +                      leftconv := ctypeconvnode.create_internal(left, s32inttype)
    +                    else
    +                      leftconv := left;
    +                    call := ccallnode.createinternres('fpc_do_as_enum',
    +                      ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
    +                        ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
    +                          ccallparanode.create(leftconv, nil))),
    +                      resultdef)
    +                  end;
    +              end
                 else
                   begin
                     if is_class(left.resultdef) then
    Index: compiler/x86/nx86cnv.pas
    ===================================================================
    --- compiler/x86/nx86cnv.pas	(revision 42331)
    +++ compiler/x86/nx86cnv.pas	(working copy)
    @@ -26,7 +26,7 @@
     interface
     
         uses
    -      node,ncgcnv,defutil;
    +      node,ncnv,ncgcnv,defutil,constexp;
     
         type
            tx86typeconvnode = class(tcgtypeconvnode)
    @@ -54,7 +54,15 @@
              { procedure second_char_to_char;override; }
            end;
     
    +       Tx86IsNode = class(TIsNode)
    +       protected
    +         min_, max_: TConstExprInt;
    +       public
    +         function pass_1: TNode; override;
    +         procedure pass_generate_code; override;
    +       end;
     
    +
     implementation
     
        uses
    @@ -63,7 +71,7 @@
           symconst,symdef,
           cgbase,cga,pass_1,pass_2,
           cpuinfo,
    -      ncnv,
    +      ncon,
           cpubase,
           cgutils,cgobj,hlcgobj,cgx86,
           tgobj;
    @@ -445,6 +453,98 @@
             location_freetemp(current_asmdata.CurrAsmList,left.location);
           end;
     
    +
    +{*****************************************************************************
    +                               TX86ISNODE
    +*****************************************************************************}
    +
    +    function Tx86IsNode.pass_1: TNode;
    +      var
    +        OldLeft: TNode;
    +        v, res: TConstExprInt;
    +      begin
    +        if (right.resultdef.typ in [orddef, enumdef]) then
    +          begin
    +            if left.nodetype=ordconstn then
    +              begin
    +                v := Tordconstnode(left).value;
    +                if (v < TEnumDef(right.resultdef).min) or (v > TEnumDef(right.resultdef).max) then
    +                  res := 0 { False }
    +                else
    +                  res := 1; { True }
    +                Result := cordconstnode.create(res, resultdef, false);
    +              end
    +            else
    +              begin
    +                if left.resultdef.typ<>orddef then
    +                  begin
    +                    { Wrap the left node in a new type conversion }
    +                    OldLeft := Left;
    +                    left := ctypeconvnode.create_internal(OldLeft, s32inttype);
    +                    left.fileinfo:=OldLeft.fileinfo;
    +                    firstpass(left); { This will also do the type check }
    +                  end;
    +
    +                if right.resultdef.typ = enumdef then
    +                  with right.resultdef as TEnumDef do
    +                    begin
    +                      min_ := min;
    +                      max_ := max;
    +                    end
    +                else
    +                  { Must be an orddef due to the check at the top }
    +                    with right.resultdef as TOrdDef do
    +                      begin
    +                        min_ := low;
    +                        max_ := high;
    +                      end;
    +
    +                { If the left node's domain is within the right node's domain, the
    +                  result is always True }
    +
    +                if (TOrdDef(left.resultdef).low >= min_) and (TOrdDef(left.resultdef).high <= max_) then
    +                  Result := cordconstnode.create(1, resultdef, false)
    +                else
    +                  { Delegate platform-specific work to pass_generate_code }
    +                  Result := nil;
    +              end;
    +          end
    +        else
    +          { Go to the default "is" handler }
    +          Result := inherited;
    +      end;
    +
    +
    +    procedure Tx86IsNode.pass_generate_code;
    +      var
    +        leftsize, rightsize, opcgsize: TCgSize;
    +        scratch_reg: TRegister;
    +      begin
    +        { The right side will never be smaller than the left side by this point }
    +        opcgsize := def_cgsize(right.resultdef);
    +
    +        secondpass(left);
    +
    +        scratch_reg := hlcg.getintregister(current_asmdata.CurrAsmList, right.resultdef);
    +
    +        if min_ = 0 then
    +          begin
    +            { If the lower bound is zero, we can do the range check without a scratch register }
    +            emit_const_ref(A_CMP, TCGSize2Opsize[opcgsize], aint(max_), left.location.reference);
    +          end
    +        else
    +          begin
    +            cg.a_load_ref_reg(current_asmdata.CurrAsmList, def_cgsize(left.resultdef), opcgsize, left.location.reference, scratch_reg);
    +            cg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SUB, opcgsize, aint(min_), scratch_reg);
    +            emit_const_reg(A_CMP, TCGSize2Opsize[opcgsize], aint(max_) - aint(min_), scratch_reg);
    +          end;
    +
    +        location_reset(location, LOC_FLAGS, OS_NO);
    +        location.resflags := F_BE;
    +      end;
    +
    +
     begin
    -  ctypeconvnode:=tx86typeconvnode
    +  ctypeconvnode:=tx86typeconvnode;
    +  cisnode := Tx86IsNode;
     end.
    Index: rtl/inc/compproc.inc
    ===================================================================
    --- rtl/inc/compproc.inc	(revision 42331)
    +++ rtl/inc/compproc.inc	(working copy)
    @@ -794,6 +794,8 @@
     
     procedure fpc_AbstractErrorIntern;compilerproc;
     procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
    +function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
    +function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
     
     {$ifdef FPC_HAS_FEATURE_FILEIO}
     Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
    Index: rtl/inc/system.inc
    ===================================================================
    --- rtl/inc/system.inc	(revision 42331)
    +++ rtl/inc/system.inc	(working copy)
    @@ -1550,6 +1550,29 @@
     
     
     {*****************************************************************************
    +                       (I as TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
    +begin
    +  if (value>=minvalue) and (value<=maxvalue) then
    +    result:=value
    +  else
    +    handleerroraddrframeInd(219,get_pc_addr,get_frame);
    +end;
    +
    +
    +{*****************************************************************************
    +                       (I is TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
    +begin
    +  result := (value>=minvalue) and (value<=maxvalue);
    +end;
    +
    +
    +{*****************************************************************************
                            SetJmp/LongJmp support.
     *****************************************************************************}
     
    
    AS-IS-enum-06.patch (11,952 bytes)
  • ValidOrdIs.lpr (34,873 bytes)
  • AS-IS-enum-11.patch (15,930 bytes)
    Index: compiler/msg/errore.msg
    ===================================================================
    --- compiler/msg/errore.msg	(revision 42345)
    +++ compiler/msg/errore.msg	(working copy)
    @@ -1681,7 +1681,7 @@
     type_e_strict_var_string_violation=04016_E_String types have to match exactly in $V+ mode
     % When compiling in \var{\{\$V+\}} mode, the string you pass as a parameter
     % should be of the exact same type as the declared parameter of the procedure.
    -type_e_succ_and_pred_enums_with_assign_not_possible=04017_E_Succ or Pred on enums with assignments not possible
    +type_e_succ_and_pred_enums_with_assign_not_possible=04017_E_Succ or Pred on non-contiguous enumerations is not possible
     % If you declare an enumeration type which has C-like assignments
     % in it, such as in the following:
     % \begin{verbatim}
    @@ -1769,7 +1769,7 @@
     type_e_typecast_wrong_size_for_assignment=04037_E_Typecast has different size ($1 -> $2) in assignment
     % Type casting to a type with a different size is not allowed when the variable is
     % used in an assignment.
    -type_e_array_index_enums_with_assign_not_possible=04038_E_Enums with assignments cannot be used as array index
    +type_e_array_index_enums_with_assign_not_possible=04038_E_Non-contiguous enumerations cannot be used as an array index
     % When you declared an enumeration type which has C-like
     % assignments, such as in the following:
     % \begin{verbatim}
    Index: compiler/ncnv.pas
    ===================================================================
    --- compiler/ncnv.pas	(revision 42345)
    +++ compiler/ncnv.pas	(working copy)
    @@ -27,7 +27,7 @@
     
         uses
            node,
    -       symtype,
    +       symtype,constexp,
            defutil,defcmp,
            nld
            ;
    @@ -291,6 +291,10 @@
            tasnodeclass = class of tasnode;
     
            tisnode = class(tasisnode)
    +       protected
    +         lower, upper: tconstexprint;
    +         function do_variable_enum_check: tnode; virtual;
    +       public
               constructor create(l,r : tnode);virtual;
               constructor create_internal(l,r : tnode);virtual;
               function pass_1 : tnode;override;
    @@ -317,7 +321,7 @@
     implementation
     
        uses
    -      globtype,systems,constexp,compinnr,
    +      globtype,systems,compinnr,
           cutils,verbose,globals,widestr,
           symconst,symdef,symsym,symcpu,symtable,
           ncon,ncal,nset,nadd,nmem,nmat,nbas,nutils,ninl,
    @@ -2922,7 +2926,7 @@
                     val.svalue:=swapendian(int64(val.svalue))
                   else
                     val.uvalue:=swapendian(qword(val.uvalue));
    -	  else
    +          else
                 internalerror(2014111201);
             end;
           end;
    @@ -4344,6 +4348,20 @@
                       end;
                   end;
               end
    +        else if (right.resultdef.typ in [orddef, enumdef]) then
    +          begin
    +            { left must be an ordinal }
    +            if not is_ordinal(left.resultdef) then
    +              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
    +            case nodetype of
    +              isn:
    +                resultdef:=pasbool8type;
    +              asn:
    +                resultdef:=right.resultdef;
    +              else
    +                InternalError(2019070201);
    +            end;
    +          end
             else
               CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
           end;
    @@ -4367,11 +4385,80 @@
           end;
     
     
    +    function tisnode.do_variable_enum_check: tnode;
    +      var
    +        oldleft : tnode;
    +        ProcName : string;
    +        intsize : tdef;
    +      begin
    +        if left.resultdef.typ<>orddef then
    +          begin
    +            { Wrap the left node in a new type conversion }
    +            oldleft:=left;
    +            left:=ctypeconvnode.create_internal(oldleft,s32inttype);
    +            left.fileinfo:=oldleft.fileinfo;
    +            typecheckpass(left);
    +          end;
    +
    +        { If the left node's domain is within the right node's domain, the
    +          result is always True (enums are expanded to LongInt) }
    +
    +        if (torddef(left.resultdef).low>=lower) and (torddef(left.resultdef).high<=upper) then
    +          Result:=cordconstnode.create(1,resultdef,false)
    +        else
    +          begin
    +            { Make the valid domain as small as possible (this prevents
    +              "Int64 is QWord" from returning incorrect results for negative
    +              inputs. }
    +            lower:=max(torddef(left.resultdef).low, lower);
    +            upper:=min(torddef(left.resultdef).high, upper);
    +
    +            if upper<lower then
    +              InternalError(2019070721);
    +
    +            if (lower<torddef(sizesinttype).low) or (upper>torddef(sizesinttype).high) or
    +              (torddef(left.resultdef).low<torddef(sizesinttype).low) or
    +              (torddef(left.resultdef).high>torddef(sizesinttype).high) then
    +              begin
    +                { The ordinal type exceeds the CPU word size, so we have to use
    +                  a slower function }
    +                if (upper>qword(High(int64))) or (torddef(left.resultdef).high>qword(High(int64))) then
    +                  begin
    +                    if (lower<0) then
    +                      { Impossible range }
    +                      InternalError(2019070720);
    +
    +                    ProcName:='fpc_do_is_qword';
    +                    intsize:=u64inttype;
    +                  end
    +                else
    +                  begin
    +                    ProcName:='fpc_do_is_int64';
    +                    intsize:=s64inttype;
    +                  end;
    +              end
    +            else
    +              begin
    +                ProcName:='fpc_do_is_enum';
    +                intsize:=sizesinttype;
    +              end;
    +
    +            Result:=ccallnode.createinternres(ProcName,
    +              ccallparanode.create(cordconstnode.create(upper, intsize, false),
    +                ccallparanode.create(cordconstnode.create(lower, intsize, false),
    +                  ccallparanode.create(left, nil))),
    +              resultdef);
    +
    +          end;
    +      end;
    +
    +
         function tisnode.pass_1 : tnode;
           var
             procname: string;
             statement : tstatementnode;
             tempnode : ttempcreatenode;
    +        v,res : Tconstexprint;
           begin
             result:=nil;
             { Passing a class type to an "is" expression cannot result in a class
    @@ -4417,6 +4504,41 @@
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef);
               end
    +        else if (right.resultdef.typ in [orddef, enumdef]) then
    +          begin
    +            { For a right node of type enumdef or orddef, store the lower and upper
    +              bounds into the lower and upper properties }
    +            if right.resultdef.typ=enumdef then
    +              begin
    +                lower:=tenumdef(right.resultdef).min;
    +                upper:=tenumdef(right.resultdef).max;
    +              end
    +            else
    +              { Must be an orddef due to the if-statement earlier }
    +              begin
    +                lower:=torddef(right.resultdef).low;
    +                upper:=torddef(right.resultdef).high;
    +              end;
    +
    +            if left.nodetype=ordconstn then
    +              begin
    +                v:=Tordconstnode(left).value;
    +                if (v<lower) or (v>upper) then
    +                  res:=0 { false }
    +                else
    +                  res:=1; { true }
    +
    +                result:=cordconstnode.create(res, resultdef, false);
    +              end
    +            else
    +              begin
    +                if right.nodetype=typen then
    +                  TTypeNode(right).allowed:=True;
    +
    +                Result:=do_variable_enum_check;
    +              end;
    +
    +          end
             else
               begin
                 if is_class(left.resultdef) then
    @@ -4429,20 +4551,26 @@
                     procname := 'fpc_intf_is_class'
                   else
                     procname := 'fpc_intf_is';
    -            result := ctypeconvnode.create_internal(ccallnode.createintern(procname,
    +            result:=ctypeconvnode.create_internal(ccallnode.createintern(procname,
                    ccallparanode.create(right,ccallparanode.create(left,nil))),resultdef);
               end;
    -        left := nil;
    -        right := nil;
    -        //firstpass(call);
    -        if codegenerror then
    -          exit;
    +
    +        { Result may be nil on some platform-specific implementations of
    +          do_variable_enum_check }
    +        if Assigned(Result) then
    +          begin
    +            left:=nil;
    +            right:=nil;
    +          end;
           end;
     
    -    { dummy pass_2, it will never be called, but we need one since }
    -    { you can't instantiate an abstract class                      }
    +    { dummy pass_2, it will never be called on platform-agnostic implementations,
    +      but we need one since you can't instantiate an abstract class }
         procedure tisnode.pass_generate_code;
           begin
    +        { It should still never be called though - if this internal error is
    +          triggered, then Result was nil after pass_1 was called. }
    +        InternalError(2019070501);
           end;
     
     
    @@ -4495,6 +4623,9 @@
         function tasnode.pass_1 : tnode;
           var
             procname: string;
    +        leftconv : tnode;
    +        lower, upper, v : Tconstexprint;
    +        intsize : tdef;
           begin
             result:=nil;
             { Passing a class type to an "as" expression cannot result in a class
    @@ -4513,6 +4644,78 @@
                   call := ccallnode.createinternres('fpc_do_as',
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef)
    +            else if (right.resultdef.typ in [orddef, enumdef]) then
    +              begin
    +                if right.resultdef.typ=enumdef then
    +                  begin
    +                    lower:=tenumdef(right.resultdef).min;
    +                    upper:=tenumdef(right.resultdef).max;
    +                  end
    +                else
    +                  { Must be an orddef due to the if-statement earlier }
    +                  begin
    +                    lower:=torddef(right.resultdef).low;
    +                    upper:=torddef(right.resultdef).high;
    +                  end;
    +
    +                if left.nodetype=ordconstn then
    +                  begin
    +                    v:=Tordconstnode(left).value;
    +                    if (v<lower) or (v>upper) then
    +                      Message(parser_e_range_check_error);
    +                    call:=ctypeconvnode.create_internal(left, resultdef);
    +                  end
    +                else
    +                  begin
    +                    if left.resultdef.typ<>orddef then
    +                      leftconv:=ctypeconvnode.create_internal(left, s32inttype)
    +                    else
    +                      leftconv:=left;
    +                  end;
    +
    +                { Make the valid domain as small as possible (this prevents
    +                  "Int64 as QWord" from returning incorrect results for negative
    +                  inputs. }
    +                lower:=max(torddef(left.resultdef).low, lower);
    +                upper:=min(torddef(left.resultdef).high, upper);
    +
    +                if upper<lower then
    +                  InternalError(2019070731);
    +
    +                if (lower<torddef(sizesinttype).low) or (upper>torddef(sizesinttype).high) or
    +                  (torddef(left.resultdef).low<torddef(sizesinttype).low) or
    +                  (torddef(left.resultdef).high>torddef(sizesinttype).high) then
    +                  begin
    +                    { The ordinal type exceeds the CPU word size, so we have to use
    +                      a slower function }
    +
    +                    if (upper>QWord(High(Int64))) then
    +                      begin
    +                        if (lower<0) then
    +                          { Impossible range }
    +                          InternalError(2019070730);
    +
    +                        ProcName:='fpc_do_as_qword';
    +                        intsize:=u64inttype;
    +                      end
    +                    else
    +                      begin
    +                        ProcName:='fpc_do_as_int64';
    +                        intsize:=s64inttype;
    +                      end;
    +                  end
    +                else
    +                  begin
    +                    ProcName:='fpc_do_as_enum';
    +                    intsize:=sizesinttype;
    +                  end;
    +
    +                call:=ccallnode.createinternres(ProcName,
    +                  ccallparanode.create(cordconstnode.create(upper, intsize, false),
    +                    ccallparanode.create(cordconstnode.create(lower, intsize, false),
    +                      ccallparanode.create(leftconv, nil))),
    +                  resultdef);
    +              end
                 else
                   begin
                     if is_class(left.resultdef) then
    Index: rtl/inc/compproc.inc
    ===================================================================
    --- rtl/inc/compproc.inc	(revision 42345)
    +++ rtl/inc/compproc.inc	(working copy)
    @@ -795,6 +795,13 @@
     procedure fpc_AbstractErrorIntern;compilerproc;
     procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
     
    +function fpc_do_as_enum(const value, minvalue, maxvalue: SizeInt): SizeInt; compilerproc; inline;
    +function fpc_do_as_int64(const value, minvalue, maxvalue: Int64): Int64; compilerproc; inline;
    +function fpc_do_as_qword(const value, minvalue, maxvalue: QWord): QWord; compilerproc; inline;
    +function fpc_do_is_enum(const value, minvalue, maxvalue: SizeInt): Boolean; compilerproc; inline;
    +function fpc_do_is_int64(const value, minvalue, maxvalue: Int64): Boolean; compilerproc; inline;
    +function fpc_do_is_qword(const value, minvalue, maxvalue: QWord): Boolean; compilerproc; inline;
    +
     {$ifdef FPC_HAS_FEATURE_FILEIO}
     Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
     Procedure fpc_rewrite_typed(var f : TypedFile;Size : Longint); compilerproc;
    Index: rtl/inc/system.inc
    ===================================================================
    --- rtl/inc/system.inc	(revision 42345)
    +++ rtl/inc/system.inc	(working copy)
    @@ -1550,6 +1550,59 @@
     
     
     {*****************************************************************************
    +                       (I as TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_as_enum(const value, minvalue, maxvalue: SizeInt): SizeInt; compilerproc; inline;
    +begin
    +  if (value>=minvalue) and (value<=maxvalue) then
    +    result:=value
    +  else
    +    handleerroraddrframeInd(219,get_pc_addr,get_frame);
    +end;
    +
    +
    +function fpc_do_as_int64(const value, minvalue, maxvalue: Int64): Int64; compilerproc; inline;
    +begin
    +  if (value>=minvalue) and (value<=maxvalue) then
    +    result:=value
    +  else
    +    handleerroraddrframeInd(219,get_pc_addr,get_frame);
    +end;
    +
    +
    +function fpc_do_as_qword(const value, minvalue, maxvalue: QWord): QWord; compilerproc; inline;
    +begin
    +  if (value>=minvalue) and (value<=maxvalue) then
    +    result:=value
    +  else
    +    handleerroraddrframeInd(219,get_pc_addr,get_frame);
    +end;
    +
    +
    +{*****************************************************************************
    +                       (I is TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_is_enum(const value, minvalue, maxvalue: SizeInt): Boolean; compilerproc; inline;
    +begin
    +  result:=(value>=minvalue) and (value<=maxvalue);
    +end;
    +
    +
    +function fpc_do_is_int64(const value, minvalue, maxvalue: Int64): Boolean; compilerproc; inline;
    +begin
    +  result:=(value>=minvalue) and (value<=maxvalue);
    +end;
    +
    +
    +function fpc_do_is_qword(const value, minvalue, maxvalue: QWord): Boolean; compilerproc; inline;
    +begin
    +  result:=(value>=minvalue) and (value<=maxvalue);
    +end;
    +
    +
    +{*****************************************************************************
                            SetJmp/LongJmp support.
     *****************************************************************************}
     
    
    AS-IS-enum-11.patch (15,930 bytes)
  • AS-IS-enum-11-strict.patch (16,847 bytes)
    Index: compiler/msg/errore.msg
    ===================================================================
    --- compiler/msg/errore.msg	(revision 42348)
    +++ compiler/msg/errore.msg	(working copy)
    @@ -1681,7 +1681,7 @@
     type_e_strict_var_string_violation=04016_E_String types have to match exactly in $V+ mode
     % When compiling in \var{\{\$V+\}} mode, the string you pass as a parameter
     % should be of the exact same type as the declared parameter of the procedure.
    -type_e_succ_and_pred_enums_with_assign_not_possible=04017_E_Succ or Pred on enums with assignments not possible
    +type_e_succ_and_pred_enums_with_assign_not_possible=04017_E_Succ or Pred on non-contiguous enumerations is not possible
     % If you declare an enumeration type which has C-like assignments
     % in it, such as in the following:
     % \begin{verbatim}
    @@ -1769,7 +1769,7 @@
     type_e_typecast_wrong_size_for_assignment=04037_E_Typecast has different size ($1 -> $2) in assignment
     % Type casting to a type with a different size is not allowed when the variable is
     % used in an assignment.
    -type_e_array_index_enums_with_assign_not_possible=04038_E_Enums with assignments cannot be used as array index
    +type_e_array_index_enums_with_assign_not_possible=04038_E_Non-contiguous enumerations cannot be used as an array index
     % When you declared an enumeration type which has C-like
     % assignments, such as in the following:
     % \begin{verbatim}
    Index: compiler/ncnv.pas
    ===================================================================
    --- compiler/ncnv.pas	(revision 42348)
    +++ compiler/ncnv.pas	(working copy)
    @@ -27,7 +27,7 @@
     
         uses
            node,
    -       symtype,
    +       symtype,constexp,
            defutil,defcmp,
            nld
            ;
    @@ -291,6 +291,10 @@
            tasnodeclass = class of tasnode;
     
            tisnode = class(tasisnode)
    +       protected
    +         lower, upper : tconstexprint;
    +         function do_variable_enum_check: tnode; virtual;
    +       public
               constructor create(l,r : tnode);virtual;
               constructor create_internal(l,r : tnode);virtual;
               function pass_1 : tnode;override;
    @@ -317,7 +321,7 @@
     implementation
     
        uses
    -      globtype,systems,constexp,compinnr,
    +      globtype,systems,compinnr,
           cutils,verbose,globals,widestr,
           symconst,symdef,symsym,symcpu,symtable,
           ncon,ncal,nset,nadd,nmem,nmat,nbas,nutils,ninl,
    @@ -2922,7 +2926,7 @@
                     val.svalue:=swapendian(int64(val.svalue))
                   else
                     val.uvalue:=swapendian(qword(val.uvalue));
    -	  else
    +          else
                 internalerror(2014111201);
             end;
           end;
    @@ -4344,6 +4348,20 @@
                       end;
                   end;
               end
    +        else if (right.resultdef.typ in [orddef, enumdef]) then
    +          begin
    +            { left must be an ordinal }
    +            if not is_ordinal(left.resultdef) then
    +              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
    +            case nodetype of
    +              isn:
    +                resultdef:=pasbool8type;
    +              asn:
    +                resultdef:=right.resultdef;
    +              else
    +                InternalError(2019070201);
    +            end;
    +          end
             else
               CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
           end;
    @@ -4367,11 +4385,93 @@
           end;
     
     
    +    function tisnode.do_variable_enum_check: tnode;
    +      var
    +        oldleft : tnode;
    +        procname : string;
    +        intsize : tdef;
    +        leftlower, leftupper : tconstexprint;
    +      begin
    +        if left.resultdef.typ=enumdef then
    +          begin
    +            leftlower:=tenumdef(left.resultdef).min;
    +            leftupper:=tenumdef(left.resultdef).max;
    +          end
    +        else if left.resultdef.typ=orddef then
    +          begin
    +            leftlower:=torddef(left.resultdef).low;
    +            leftupper:=torddef(left.resultdef).high;
    +          end
    +        else
    +          begin
    +            { Attempt to typecast }
    +            oldleft:=left;
    +            left:=ctypeconvnode.create_internal(oldleft,s32inttype);
    +            left.fileinfo:=oldleft.fileinfo;
    +            firstpass(left);
    +            leftlower:=torddef(left.resultdef).low;
    +            leftupper:=torddef(left.resultdef).high;
    +          end;
    +
    +        { If the left node's domain is within the right node's domain, the
    +          result is always True (enums are expanded to LongInt) }
    +
    +        if (leftlower>=lower) and (leftupper<=upper) then
    +          Result:=cordconstnode.create(1,resultdef,false)
    +        else
    +          begin
    +            { Make the valid domain as small as possible (this prevents
    +              "Int64 is QWord" from returning incorrect results for negative
    +              inputs. }
    +            lower:=max(leftlower,lower);
    +            upper:=min(leftupper,upper);
    +
    +            if upper<lower then
    +              InternalError(2019070721);
    +
    +            if (lower<torddef(sizesinttype).low) or (upper>torddef(sizesinttype).high) or
    +              (leftlower<torddef(sizesinttype).low) or
    +              (leftupper>torddef(sizesinttype).high) then
    +              begin
    +                { The ordinal type exceeds the CPU word size, so we have to use
    +                  a slower function }
    +                if (upper>qword(High(int64))) or (torddef(left.resultdef).high>qword(High(int64))) then
    +                  begin
    +                    if (lower<0) then
    +                      { Impossible range }
    +                      InternalError(2019070720);
    +
    +                    procname:='fpc_do_is_qword';
    +                    intsize:=u64inttype;
    +                  end
    +                else
    +                  begin
    +                    procname:='fpc_do_is_int64';
    +                    intsize:=s64inttype;
    +                  end;
    +              end
    +            else
    +              begin
    +                procname:='fpc_do_is_enum';
    +                intsize:=sizesinttype;
    +              end;
    +
    +            Result:=ccallnode.createinternres(procname,
    +              ccallparanode.create(cordconstnode.create(upper, intsize, false),
    +                ccallparanode.create(cordconstnode.create(lower, intsize, false),
    +                  ccallparanode.create(left, nil))),
    +              resultdef);
    +
    +          end;
    +      end;
    +
    +
         function tisnode.pass_1 : tnode;
           var
             procname: string;
             statement : tstatementnode;
             tempnode : ttempcreatenode;
    +        v,res : tconstexprint;
           begin
             result:=nil;
             { Passing a class type to an "is" expression cannot result in a class
    @@ -4417,6 +4517,41 @@
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef);
               end
    +        else if (right.resultdef.typ in [orddef, enumdef]) then
    +          begin
    +            { For a right node of type enumdef or orddef, store the lower and upper
    +              bounds into the lower and upper properties }
    +            if right.resultdef.typ=enumdef then
    +              begin
    +                lower:=tenumdef(right.resultdef).min;
    +                upper:=tenumdef(right.resultdef).max;
    +              end
    +            else
    +              { Must be an orddef due to the if-statement earlier }
    +              begin
    +                lower:=torddef(right.resultdef).low;
    +                upper:=torddef(right.resultdef).high;
    +              end;
    +
    +            if left.nodetype=ordconstn then
    +              begin
    +                v:=Tordconstnode(left).value;
    +                if (v<lower) or (v>upper) then
    +                  res:=0 { false }
    +                else
    +                  res:=1; { true }
    +
    +                result:=cordconstnode.create(res, resultdef, false);
    +              end
    +            else
    +              begin
    +                if right.nodetype=typen then
    +                  TTypeNode(right).allowed:=True;
    +
    +                Result:=do_variable_enum_check;
    +              end;
    +
    +          end
             else
               begin
                 if is_class(left.resultdef) then
    @@ -4429,20 +4564,26 @@
                     procname := 'fpc_intf_is_class'
                   else
                     procname := 'fpc_intf_is';
    -            result := ctypeconvnode.create_internal(ccallnode.createintern(procname,
    +            result:=ctypeconvnode.create_internal(ccallnode.createintern(procname,
                    ccallparanode.create(right,ccallparanode.create(left,nil))),resultdef);
               end;
    -        left := nil;
    -        right := nil;
    -        //firstpass(call);
    -        if codegenerror then
    -          exit;
    +
    +        { Result may be nil on some platform-specific implementations of
    +          do_variable_enum_check }
    +        if Assigned(Result) then
    +          begin
    +            left:=nil;
    +            right:=nil;
    +          end;
           end;
     
    -    { dummy pass_2, it will never be called, but we need one since }
    -    { you can't instantiate an abstract class                      }
    +    { dummy pass_2, it will never be called on platform-agnostic implementations,
    +      but we need one since you can't instantiate an abstract class }
         procedure tisnode.pass_generate_code;
           begin
    +        { It should still never be called though - if this internal error is
    +          triggered, then Result was nil after pass_1 was called. }
    +        InternalError(2019070501);
           end;
     
     
    @@ -4495,6 +4636,9 @@
         function tasnode.pass_1 : tnode;
           var
             procname: string;
    +        leftlower, leftupper, rightlower, rightupper, v : tconstexprint;
    +        intsize : tdef;
    +        oldleft : tnode;
           begin
             result:=nil;
             { Passing a class type to an "as" expression cannot result in a class
    @@ -4513,6 +4657,90 @@
                   call := ccallnode.createinternres('fpc_do_as',
                     ccallparanode.create(left,ccallparanode.create(right,nil)),
                     resultdef)
    +            else if (right.resultdef.typ in [orddef, enumdef]) then
    +              begin
    +                if right.resultdef.typ=enumdef then
    +                  begin
    +                    rightlower:=tenumdef(right.resultdef).min;
    +                    rightupper:=tenumdef(right.resultdef).max;
    +                  end
    +                else
    +                  { Must be an orddef due to the if-statement earlier }
    +                  begin
    +                    rightlower:=torddef(right.resultdef).low;
    +                    rightupper:=torddef(right.resultdef).high;
    +                  end;
    +
    +                if left.nodetype=ordconstn then
    +                  begin
    +                    v:=Tordconstnode(left).value;
    +                    if (v<rightlower) or (v>rightupper) then
    +                      Message(parser_e_range_check_error);
    +                    call:=ctypeconvnode.create_internal(left,resultdef);
    +                  end;
    +
    +                { Make the valid domain as small as possible (this prevents
    +                  "Int64 as QWord" from returning incorrect results for negative
    +                  inputs. }
    +
    +                if left.resultdef.typ=enumdef then
    +                  begin
    +                    leftlower:=tenumdef(left.resultdef).min;
    +                    leftupper:=tenumdef(left.resultdef).max;
    +                  end
    +                else if left.resultdef.typ=orddef then
    +                  begin
    +                    leftlower:=torddef(left.resultdef).low;
    +                    leftupper:=torddef(left.resultdef).high;
    +                  end
    +                else
    +                  begin
    +                    { Attempt to typecast }
    +                    oldleft:=left;
    +                    left:=ctypeconvnode.create_internal(oldleft,s32inttype);
    +                    left.fileinfo:=oldleft.fileinfo;
    +                    firstpass(left);
    +                    leftlower:=torddef(left.resultdef).low;
    +                    leftupper:=torddef(left.resultdef).high;
    +                  end;
    +
    +                if rightupper<rightlower then
    +                  InternalError(2019070731);
    +
    +                if (rightlower<torddef(sizesinttype).low) or (rightupper>torddef(sizesinttype).high) or
    +                  (leftlower<torddef(sizesinttype).low) or
    +                  (leftupper>torddef(sizesinttype).high) then
    +                  begin
    +                    { The ordinal type exceeds the CPU word size, so we have to use
    +                      a slower function }
    +
    +                    if (rightupper>qword(High(int64))) then
    +                      begin
    +                        if (rightlower<0) then
    +                          { Impossible range }
    +                          InternalError(2019070730);
    +
    +                        procname:='fpc_do_as_qword';
    +                        intsize:=u64inttype;
    +                      end
    +                    else
    +                      begin
    +                        procname:='fpc_do_as_int64';
    +                        intsize:=s64inttype;
    +                      end;
    +                  end
    +                else
    +                  begin
    +                    procname:='fpc_do_as_enum';
    +                    intsize:=sizesinttype;
    +                  end;
    +
    +                call := ccallnode.createinternres(procname,
    +                  ccallparanode.create(cordconstnode.create(rightupper, intsize, false),
    +                    ccallparanode.create(cordconstnode.create(rightlower, intsize, false),
    +                      ccallparanode.create(left, nil))),
    +                  resultdef);
    +              end
                 else
                   begin
                     if is_class(left.resultdef) then
    Index: rtl/inc/compproc.inc
    ===================================================================
    --- rtl/inc/compproc.inc	(revision 42348)
    +++ rtl/inc/compproc.inc	(working copy)
    @@ -795,6 +795,13 @@
     procedure fpc_AbstractErrorIntern;compilerproc;
     procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
     
    +function fpc_do_as_enum(const value, minvalue, maxvalue: SizeInt): SizeInt; compilerproc; inline;
    +function fpc_do_as_int64(const value, minvalue, maxvalue: Int64): Int64; compilerproc; inline;
    +function fpc_do_as_qword(const value, minvalue, maxvalue: QWord): QWord; compilerproc; inline;
    +function fpc_do_is_enum(const value, minvalue, maxvalue: SizeInt): Boolean; compilerproc; inline;
    +function fpc_do_is_int64(const value, minvalue, maxvalue: Int64): Boolean; compilerproc; inline;
    +function fpc_do_is_qword(const value, minvalue, maxvalue: QWord): Boolean; compilerproc; inline;
    +
     {$ifdef FPC_HAS_FEATURE_FILEIO}
     Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
     Procedure fpc_rewrite_typed(var f : TypedFile;Size : Longint); compilerproc;
    Index: rtl/inc/system.inc
    ===================================================================
    --- rtl/inc/system.inc	(revision 42348)
    +++ rtl/inc/system.inc	(working copy)
    @@ -1550,6 +1550,59 @@
     
     
     {*****************************************************************************
    +                       (I as TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_as_enum(const value, minvalue, maxvalue: SizeInt): SizeInt; compilerproc; inline;
    +begin
    +  if (value>=minvalue) and (value<=maxvalue) then
    +    result:=value
    +  else
    +    handleerroraddrframeInd(219,get_pc_addr,get_frame);
    +end;
    +
    +
    +function fpc_do_as_int64(const value, minvalue, maxvalue: Int64): Int64; compilerproc; inline;
    +begin
    +  if (value>=minvalue) and (value<=maxvalue) then
    +    result:=value
    +  else
    +    handleerroraddrframeInd(219,get_pc_addr,get_frame);
    +end;
    +
    +
    +function fpc_do_as_qword(const value, minvalue, maxvalue: QWord): QWord; compilerproc; inline;
    +begin
    +  if (value>=minvalue) and (value<=maxvalue) then
    +    result:=value
    +  else
    +    handleerroraddrframeInd(219,get_pc_addr,get_frame);
    +end;
    +
    +
    +{*****************************************************************************
    +                       (I is TMyEnum) support.
    +*****************************************************************************}
    +
    +function fpc_do_is_enum(const value, minvalue, maxvalue: SizeInt): Boolean; compilerproc; inline;
    +begin
    +  result := (value>=minvalue) and (value<=maxvalue);
    +end;
    +
    +
    +function fpc_do_is_int64(const value, minvalue, maxvalue: Int64): Boolean; compilerproc; inline;
    +begin
    +  result := (value>=minvalue) and (value<=maxvalue);
    +end;
    +
    +
    +function fpc_do_is_qword(const value, minvalue, maxvalue: QWord): Boolean; compilerproc; inline;
    +begin
    +  result := (value>=minvalue) and (value<=maxvalue);
    +end;
    +
    +
    +{*****************************************************************************
                            SetJmp/LongJmp support.
     *****************************************************************************}
     
    

Activities

Ondrej Pokorny

2018-04-13 12:52

developer  

AS-enum-01.patch (3,068 bytes)
Index: compiler/ncnv.pas
===================================================================
--- compiler/ncnv.pas	(revision 38690)
+++ compiler/ncnv.pas	(working copy)
@@ -4281,6 +4281,18 @@
                   end;
               end;
           end
+        else if (right.resultdef.typ=enumdef) then
+          begin
+            { left must be an ordinal }
+            if not is_ordinal(left.resultdef) then
+              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
+            case nodetype of
+              isn:
+                resultdef:=pasbool8type;
+              asn:
+                resultdef:=right.resultdef;
+            end;
+          end
         else
           CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
       end;
@@ -4450,6 +4462,15 @@
               call := ccallnode.createinternres('fpc_do_as',
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef)
+            else if (right.resultdef.typ=enumdef) then
+            begin
+              Writeln(tenumdef(right.resultdef).min, ':', tenumdef(right.resultdef).max);
+              call := ccallnode.createinternres('fpc_do_as_enum',
+                ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
+                  ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
+                    ccallparanode.create(left, nil))),
+                resultdef)
+            end
             else
               begin
                 if is_class(left.resultdef) then
Index: rtl/inc/compproc.inc
===================================================================
--- rtl/inc/compproc.inc	(revision 38690)
+++ rtl/inc/compproc.inc	(working copy)
@@ -798,6 +798,7 @@
 
 procedure fpc_AbstractErrorIntern;compilerproc;
 procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
+function fpc_do_as_enum(value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
 
 {$ifdef FPC_HAS_FEATURE_FILEIO}
 Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
Index: rtl/inc/system.inc
===================================================================
--- rtl/inc/system.inc	(revision 38690)
+++ rtl/inc/system.inc	(working copy)
@@ -1528,6 +1528,19 @@
 
 
 {*****************************************************************************
+                       (I as TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_as_enum(value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
+begin
+  if (value>=minvalue) and (value<=maxvalue) then
+    result:=value
+  else
+    handleerroraddrframeInd(219,get_pc_addr,get_frame);
+end;
+
+
+{*****************************************************************************
                        SetJmp/LongJmp support.
 *****************************************************************************}
 
AS-enum-01.patch (3,068 bytes)

Ondrej Pokorny

2018-04-13 12:53

developer  

ValidEnumAS.lpr (1,567 bytes)

Ondrej Pokorny

2018-04-15 14:07

developer  

AS-IS-enum-02.patch (6,628 bytes)
Index: compiler/ncnv.pas
===================================================================
--- compiler/ncnv.pas	(revision 38690)
+++ compiler/ncnv.pas	(working copy)
@@ -4281,6 +4281,18 @@
                   end;
               end;
           end
+        else if (right.resultdef.typ=enumdef) then
+          begin
+            { left must be an ordinal }
+            if not is_ordinal(left.resultdef) then
+              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
+            case nodetype of
+              isn:
+                resultdef:=pasbool8type;
+              asn:
+                resultdef:=right.resultdef;
+            end;
+          end
         else
           CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
       end;
@@ -4309,6 +4321,8 @@
         procname: string;
         statement : tstatementnode;
         tempnode : ttempcreatenode;
+        v,res: Tconstexprint;
+        leftconv: tnode;
       begin
         result:=nil;
         { Passing a class type to an "is" expression cannot result in a class
@@ -4354,6 +4368,35 @@
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef);
           end
+        else if (right.resultdef.typ=enumdef) then
+          begin
+            if left.nodetype=ordconstn then
+              begin
+                v:=Tordconstnode(left).value;
+                res.signed:=false;
+                res.overflow:=false;
+                if v.signed and ((v.svalue<tenumdef(right.resultdef).min) or (v.svalue>tenumdef(right.resultdef).max)) then
+                  res.uvalue:=0 { false }
+                else
+                if not v.signed and ((v.uvalue<tenumdef(right.resultdef).min) or (v.uvalue>tenumdef(right.resultdef).max)) then
+                  res.uvalue:=0 { false }
+                else
+                  res.uvalue:=1; { true }
+                result := cordconstnode.create(res, resultdef, false);
+              end
+            else
+              begin
+                if left.resultdef.typ<>orddef then
+                  leftconv := ctypeconvnode.create_internal(left, s32inttype)
+                else
+                  leftconv := left;
+                result := ccallnode.createinternres('fpc_do_is_enum',
+                  ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
+                    ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
+                      ccallparanode.create(leftconv, nil))),
+                  resultdef);
+              end;
+          end
         else
           begin
             if is_class(left.resultdef) then
@@ -4432,6 +4475,8 @@
     function tasnode.pass_1 : tnode;
       var
         procname: string;
+        leftconv: tnode;
+        v: Tconstexprint;
       begin
         result:=nil;
         { Passing a class type to an "as" expression cannot result in a class
@@ -4450,6 +4495,31 @@
               call := ccallnode.createinternres('fpc_do_as',
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef)
+            else if (right.resultdef.typ=enumdef) then
+              begin
+                if left.nodetype=ordconstn then
+                  begin
+                    v:=Tordconstnode(left).value;
+                    if v.signed and ((v.svalue<tenumdef(right.resultdef).min) or (v.svalue>tenumdef(right.resultdef).max)) then
+                      Message(parser_e_range_check_error)
+                    else
+                    if not v.signed and ((v.uvalue<tenumdef(right.resultdef).min) or (v.uvalue>tenumdef(right.resultdef).max)) then
+                      Message(parser_e_range_check_error);
+                    call := ctypeconvnode.create_internal(left, resultdef);
+                  end
+                else
+                  begin
+                    if left.resultdef.typ<>orddef then
+                      leftconv := ctypeconvnode.create_internal(left, s32inttype)
+                    else
+                      leftconv := left;
+                    call := ccallnode.createinternres('fpc_do_as_enum',
+                      ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
+                        ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
+                          ccallparanode.create(leftconv, nil))),
+                      resultdef)
+                  end;
+              end
             else
               begin
                 if is_class(left.resultdef) then
Index: rtl/inc/compproc.inc
===================================================================
--- rtl/inc/compproc.inc	(revision 38690)
+++ rtl/inc/compproc.inc	(working copy)
@@ -798,6 +798,8 @@
 
 procedure fpc_AbstractErrorIntern;compilerproc;
 procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
+function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
+function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
 
 {$ifdef FPC_HAS_FEATURE_FILEIO}
 Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
Index: rtl/inc/system.inc
===================================================================
--- rtl/inc/system.inc	(revision 38690)
+++ rtl/inc/system.inc	(working copy)
@@ -1528,6 +1528,29 @@
 
 
 {*****************************************************************************
+                       (I as TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
+begin
+  if (value>=minvalue) and (value<=maxvalue) then
+    result:=value
+  else
+    handleerroraddrframeInd(219,get_pc_addr,get_frame);
+end;
+
+
+{*****************************************************************************
+                       (I is TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
+begin
+  result := (value>=minvalue) and (value<=maxvalue);
+end;
+
+
+{*****************************************************************************
                        SetJmp/LongJmp support.
 *****************************************************************************}
 
AS-IS-enum-02.patch (6,628 bytes)

Ondrej Pokorny

2018-04-15 14:08

developer  

ValidEnumIS.lpr (945 bytes)

Ondrej Pokorny

2018-04-15 14:08

developer  

ValidEnumAS-2.lpr (2,258 bytes)

Ondrej Pokorny

2018-04-15 14:11

developer   ~0107796

A new patch AS-IS-enum-02.patch included:

1.) I added support for the IS operator.
2.) I added support of any ordinal type (int/enum) on the left side of the operator:
var
  E: TMyEnum;
begin
  E := E as TMyEnum; // check if E is valid value
  if E is TMyEnum then // check if E is valid value

3.) I added support for compile-time constant evaluation.

4.) Updated test case projects for both AS and IS operators.

Thaddy de Koning

2018-04-16 12:52

reporter   ~0107808

Last edited: 2018-04-16 12:59

View 5 revisions

The patch for "is" is incorrect and fails on value assigned enumerations:
That's because "is" only checks lower and upper bounds.
I have included code that may be of help to fix this. That code propery tests membership.
program checkrange;
{$mode objfpc}{$modeswitch typehelpers}{$M+}
type
  TProgrammerType = (tpDelphi =100, tpVisualC=104, tpVB=110, tpJava=255) ;
  TProgrammerSet = set of TProgrammerType;

  function Test(const a:TprogrammerType):Boolean;
  var
    b:TprogrammerSet =[tpDelphi, tpVisualC, tpVB, tpJava];
  begin
    Result := a in b;
  end;
var
  i:integer;
begin
  // works
  for i := 100 to 110 do
    writeln(i:4,test(i as TprogrammerType):8);
  // fails
  for i := 100 to 110 do if i is TprogrammerType then
    writeln(i:4,i as TprogrammerType:15);
end.

Output:
 100 TRUE
 101 FALSE
 102 FALSE
 103 FALSE
 104 TRUE
 105 FALSE
 106 FALSE
 107 FALSE
 108 FALSE
 109 FALSE
 110 TRUE
 100tpDelphi
An unhandled exception occurred at $00010344:
EInOutError: Unknown Run-Time error : 107
  $00010344

 101

Thaddy de Koning

2018-04-16 13:08

reporter   ~0107809

Last edited: 2018-04-16 13:09

View 2 revisions

I used
Free Pascal Compiler version 3.1.1-r38778+isaspatch [2018/04/16] for arm
Copyright (c) 1993-2018 by Florian Klaempfl and others

I don't know if it is easy for the compiler to use a set containing all members on any enumaration, but may be it is a suggestion to correct it.
I like the feature.

Thaddy de Koning

2018-04-16 13:22

reporter   ~0107810

Last edited: 2018-04-16 13:31

View 6 revisions

Note the patch for "as" is also incorrect for the same reason.
Out of bounds values (- and + range) throw correct 219 exception, but "as" accepts values that are not of the enumeration.
So both is and as are incorrect and need more work.

e.g in my example code "Test(101) as TprogrammerType" should fail with 219 because it is not a member of the enumeration.
219 is "invalid typecast" ofcourse

Crude:
My own dumb function should acutally do this:
 function Test(const a:TprogrammerType):Boolean;
  var
    b:TprogrammerSet =[tpDelphi, tpVisualC, tpVB, tpJava];
  begin
    Result := a in b;
    If Result := false then runerror(219);
  end;

Ondrej Pokorny

2018-04-16 13:35

developer   ~0107811

Thaddy, if you had taken a look into the test case projects, you would have seen that they contain tests for enums with assigned values.

The behavior you describe as incorrect is, on the contrary, correct and desired.

Please take a look into Delphi documentation:
http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Simple_Types_(Delphi)#Enumerated_Types_with_Explicitly_Assigned_Ordinality
Delphi 7 docs: http://docs.embarcadero.com/products/rad_studio/cbuilder6/EN/CB6_ObjPascalLangGuide_EN.pdf see page 5-7 and 5-8

Citation begin:

type Size = (Small = 5, Medium = 10, Large = Small + Medium);

An enumerated type is, in effect, a subrange whose lowest and highest values correspond to the lowest and highest ordinalities of the constants in the declaration. In the previous example, the Size type has 11 possible values whose ordinalities range from 5 to 15. (Hence the type array[Size] of Char represents an array of 11 characters.) Only three of these values have names, but the others are accessible through typecasts and through routines such as Pred, Succ, Inc, and Dec.

Citation end.

Thaddy de Koning

2018-04-16 13:36

reporter   ~0107812

I hope this helps, but for now I am reverting the patch.

Thaddy de Koning

2018-04-16 13:40

reporter   ~0107813

Last edited: 2018-04-16 13:47

View 3 revisions

No the test case uses an assigned value as the high value. Your tests run, because you were testing not enough options. As I proved to you: non-members should error 219 even if they are in the low-high range, because enums must only be ascending (not even that) and not consecutive.
See my example code. The patch is incomplete, very sorry.

AND you did not look at my code:
 TProgrammerType = (tpDelphi =100, tpVisualC=104, tpVB=110, tpJava=255) ;

Is correct but fails with your patches..... Now what... As should fail on 101,102,103,99,256,254 etc. and Is should return false for these values, which it doesn't. So back to the drawing board.

Thaddy de Koning

2018-04-16 14:05

reporter   ~0107814

Last edited: 2018-04-16 14:16

View 3 revisions

If you think otherwise be my guest, but this patch is useless if non-members can be used. I strongly advise against applying it now. You should fix it, not complain to testers.

Even this is legal, btw and issues just a note, but don't worry about that because the compiler sees Low() as 10.
  TProgrammerType = (tpDelphi =100, tpVisualC=10, tpVB=110, tpJava=255) ;

Thaddy de Koning

2018-04-16 14:18

reporter   ~0107815

Maybe you overused exceptions in your testcode. Better to write real tests for it. Specifically for IS.

Ondrej Pokorny

2018-04-16 14:19

developer   ~0107816

Thaddy, you obviously cannot read. DID YOU READ MY POST? According to the Delphi documentation I linked, all values 100..255 are valid, but only 100, 104, 110 and 255 have names.
IS has to return true for all values 100..255 (what it does now) and AS should succeed on the same range (what it does now).

As always: please do not pollute my issue reports. First read the mailing list, where we already discussed a lot about this feature. You could have spared your and my time. If your questions are not answered in the mailing list, ask your questions there.

+++
About differences between objfpc and delphi modes, take the for-in loop: for E in TProgrammerType do

1.) The objfpc mode doesn't allow this (it allows it only for simple enums).
2.) The delphi mode allows this and all values between 100..255 are looped through.

So the only thing I can do is to disable this syntax for the OBJFPC mode and enums with assigned values if the desire is present.

Ondrej Pokorny

2018-04-16 14:31

developer   ~0107818

> About differences between objfpc and delphi modes, take the for-in loop: for E in TProgrammerType do

Sorry, I have to correct myself. I mixed up the for-in loop with array declaration:

A: array[TProgrammerType] of Integer;
1.) The objfpc mode doesn't allow this (it allows it only for simple enums).
2.) The delphi mode allows this and the array index uses all values between 100..255.

Thaddy de Koning

2018-04-16 16:03

reporter   ~0107819

Last edited: 2018-04-16 17:03

View 2 revisions

Then that's a Delphi mistake. If you want to use IS, it *must* be of the enumeration. And other IS should fail. I feel the same goes for AS, but there U can see a point (efficiency). Ask on the mailing list. I am right. What delphi does is an implementation shortcoming if they implement IS and AS that way. Make s especially IS completely useless and not typesafe. And IS is about type safety.

Consider this, set syntax is now completely broken and unreliable, because you can add invisible members to sets without knowing:
program checkEnumAndSets;
{$mode objfpc}{$modeswitch typehelpers}{$M+}
type
  TProgrammerType = (tpDelphi =100, tpVisualC=10, tpVB=110, tpClang =9, tpJava=255) ;
var
  i:integer;
  s:Set of TprogrammerType;
begin
  s:=[];
  i := 110;
  writeln(i,' Is valid enum:', i is TProgrammerType, ' Oh, well, let''s include it in the set then...:');
  writeln('Trying to include i');
  Include(s,i as TProgrammerType);
  writeln('Is it in the set:',i as TprogrammerType in s, ' Which "seems to work..Let''s see:' );

  i := 101;
  writeln(i,' Is valid enum:', i is TProgrammerType, ' Oh, well, let''s include it in the set then...:');
  writeln('Trying to include i');
  Include(s,i as TProgrammerType);
  writeln('Is it in the set:',i as TprogrammerType in s, ' Do we really want that?' );
  writeln('Because this will now fail: ',TProgrammerType(i));
end.

Basically: either implement it as I explained or do not implement it at all. There is no expected type safety here and it should be type safe.

Ondrej Pokorny

2018-04-16 16:51

developer  

AS-IS-enum-03.patch (95,365 bytes)
Index: compiler/msg/errore.msg
===================================================================
--- compiler/msg/errore.msg	(revision 38690)
+++ compiler/msg/errore.msg	(working copy)
@@ -2012,6 +2012,7 @@
 % require specialisation for methods or nested subroutines.
 type_e_seg_procvardef_wrong_memory_model=04124_E_Procedure variables in that memory model do not store segment information
 type_w_empty_constant_range_set=04125_W_The first value of a set constructur range is greater then the second value, so the range describes an empty set.
+type_e_as_is_enums_with_assign_not_possible=04126_E_as or is cannot be used on enums with assignments
 % If a set is constructed like this: \var{s:=[9..7];]}, then an empty set is generated. As this is something normally not desired, the compiler warns about it.
 % \end{description}
 #
Index: compiler/msgidx.inc
===================================================================
--- compiler/msgidx.inc	(revision 38690)
+++ compiler/msgidx.inc	(working copy)
@@ -572,6 +572,7 @@
   type_e_function_reference_kind=04123;
   type_e_seg_procvardef_wrong_memory_model=04124;
   type_w_empty_constant_range_set=04125;
+  type_e_as_is_enums_with_assign_not_possible=04126;
   sym_e_id_not_found=05000;
   sym_f_internal_error_in_symtablestack=05001;
   sym_e_duplicate_id=05002;
@@ -1099,9 +1100,9 @@
   option_info=11024;
   option_help_pages=11025;
 
-  MsgTxtSize = 81837;
+  MsgTxtSize = 81895;
 
   MsgIdxMax : array[1..20] of longint=(
-    27,106,347,126,96,59,142,34,221,67,
+    27,106,347,127,96,59,142,34,221,67,
     61,20,30,1,1,1,1,1,1,1
   );
Index: compiler/msgtxt.inc
===================================================================
--- compiler/msgtxt.inc	(revision 38690)
+++ compiler/msgtxt.inc	(working copy)
@@ -1,8 +1,8 @@
 const msgtxt_codepage=20127;
 {$ifdef Delphi}
-const msgtxt : array[0..000340] of string[240]=(
+const msgtxt : array[0..000341] of string[240]=(
 {$else Delphi}
-const msgtxt : array[0..000340,1..240] of char=(
+const msgtxt : array[0..000341,1..240] of char=(
 {$endif Delphi}
   '01000_T_Compiler: $1'#000+
   '01001_D_Compiler OS: $1'#000+
@@ -723,412 +723,412 @@
   'information'#000+
   '04125_W_The first value o','f a set constructur range is greater then t'+
   'he second value, so the range describes an empty set.'#000+
+  '04126_E_as or is cannot be used on enums with assignments'#000+
   '05000_E_Identifier not found "$1"'#000+
   '05001_F_Internal Error in SymTableStack()'#000+
-  '05002_E_Duplicate identifier "$1"'#000+
-  '05003_H_Identifier already define','d in $1 at line $2'#000+
+  '05002_E_D','uplicate identifier "$1"'#000+
+  '05003_H_Identifier already defined in $1 at line $2'#000+
   '05004_E_Unknown identifier "$1"'#000+
   '05005_E_Forward declaration not solved "$1"'#000+
   '05007_E_Error in type definition'#000+
   '05009_E_Forward type not resolved "$1"'#000+
-  '05010_E_Only static variables can be used in static methods or outside'+
-  ' me','thods'#000+
+  '05010_E_Only st','atic variables can be used in static methods or outsi'+
+  'de methods'#000+
   '05012_E_Record or object or class type expected'#000+
   '05013_E_Instances of classes or objects with an abstract method are no'+
   't allowed'#000+
   '05014_W_Label not defined "$1"'#000+
-  '05015_E_Label used but not defined "$1"'#000+
+  '05015_E_Label use','d but not defined "$1"'#000+
   '05016_E_Illegal label declaration'#000+
-  '0','5017_E_GOTO and LABEL are not supported (use switch -Sg)'#000+
+  '05017_E_GOTO and LABEL are not supported (use switch -Sg)'#000+
   '05018_E_Label not found'#000+
   '05019_E_identifier isn'#039't a label'#000+
   '05020_E_label already defined'#000+
-  '05021_E_illegal type declaration of set elements'#000+
-  '05022_E_Forward class definition not resolved "','$1"'#000+
+  '05021_E_illegal type declaration of se','t elements'#000+
+  '05022_E_Forward class definition not resolved "$1"'#000+
   '05023_H_Unit "$1" not used in $2'#000+
   '05024_H_Parameter "$1" not used'#000+
   '05025_N_Local variable "$1" not used'#000+
   '05026_H_Value parameter "$1" is assigned but never used'#000+
-  '05027_N_Local variable "$1" is assigned but never used'#000+
-  '05028_H_Local $1 "$2" i','s not used'#000+
+  '05027_N_Local variab','le "$1" is assigned but never used'#000+
+  '05028_H_Local $1 "$2" is not used'#000+
   '05029_N_Private field "$1.$2" is never used'#000+
   '05030_N_Private field "$1.$2" is assigned but never used'#000+
   '05031_N_Private method "$1.$2" never used'#000+
   '05032_E_Set type expected'#000+
-  '05033_W_Function result does not seem to be set'#000+
-  '05034_W_Type',' "$1" is not aligned correctly in current record for C'#000+
+  '05','033_W_Function result does not seem to be set'#000+
+  '05034_W_Type "$1" is not aligned correctly in current record for C'#000+
   '05035_E_Unknown record field identifier "$1"'#000+
   '05036_W_Local variable "$1" does not seem to be initialized'#000+
-  '05037_W_Variable "$1" does not seem to be initialized'#000+
-  '05038_E_identifier idents ','no member "$1"'#000+
+  '05037_W_Variable "$1" ','does not seem to be initialized'#000+
+  '05038_E_identifier idents no member "$1"'#000+
   '05039_H_Found declaration: $1'#000+
   '05040_E_Data element too large'#000+
   '05042_E_No matching implementation for interface method "$1" found'#000+
   '05043_W_Symbol "$1" is deprecated'#000+
-  '05044_W_Symbol "$1" is not portable'#000+
-  '05055_W_Symbol "$1" is not ','implemented'#000+
+  '05044','_W_Symbol "$1" is not portable'#000+
+  '05055_W_Symbol "$1" is not implemented'#000+
   '05056_E_Can'#039't create unique type from this type'#000+
   '05057_H_Local variable "$1" does not seem to be initialized'#000+
   '05058_H_Variable "$1" does not seem to be initialized'#000+
-  '05059_W_Function result variable does not seem to be initialized'#000+
-  '0','5060_H_Function result variable does not seem to be initialized'#000+
+  '05059_W_','Function result variable does not seem to be initialized'#000+
+  '05060_H_Function result variable does not seem to be initialized'#000+
   '05061_W_Variable "$1" read but nowhere assigned'#000+
   '05062_H_Found abstract method: $1'#000+
-  '05063_W_Symbol "$1" is experimental'#000+
-  '05064_W_Forward declaration "$1" not resolved, assumed ext','ernal'#000+
+  '05063_W_Symbol "$1" is experimental'#000,
+  '05064_W_Forward declaration "$1" not resolved, assumed external'#000+
   '05065_W_Symbol "$1" is belongs to a library'#000+
   '05066_W_Symbol "$1" is deprecated: "$2"'#000+
   '05067_E_Cannot find an enumerator for the type "$1"'#000+
-  '05068_E_Cannot find a "MoveNext" method in enumerator "$1"'#000+
-  '05069_E_Cannot find a "Current" propert','y in enumerator "$1"'#000+
+  '05068_E_Cannot find a "MoveNext" method ','in enumerator "$1"'#000+
+  '05069_E_Cannot find a "Current" property in enumerator "$1"'#000+
   '05070_E_Mismatch between number of declared parameters and number of c'+
   'olons in message string.'#000+
   '05071_N_Private type "$1.$2" never used'#000+
-  '05072_N_Private const "$1.$2" never used'#000+
-  '05073_N_Private property "$1.$2" never used',#000+
+  '05072_N_Private const "$1.','$2" never used'#000+
+  '05073_N_Private property "$1.$2" never used'#000+
   '05074_W_Unit "$1" is deprecated'#000+
   '05075_W_Unit "$1" is deprecated: "$2"'#000+
   '05076_W_Unit "$1" is not portable'#000+
   '05077_W_Unit "$1" is belongs to a library'#000+
-  '05078_W_Unit "$1" is not implemented'#000+
+  '05078_W_Unit "$1" is not implemente','d'#000+
   '05079_W_Unit "$1" is experimental'#000+
-  '05080_E_No full defini','tion of the formally declared class "$1" is in'+
-  ' scope. Add the unit containing its full definition to the uses clause'+
-  '.'#000+
-  '05081_E_Gotos into initialization or finalization blocks of units are '+
-  'not allowed'#000+
-  '05082_E_Invalid external name "$1" for f','ormal class "$2"'#000+
+  '05080_E_No full definition of the formally declared class "$1" is in s'+
+  'cope. Add the unit containing its full definition to the uses clause.'#000+
+  '05081_E_Gotos into initialization or finalization blocks of unit','s ar'+
+  'e not allowed'#000+
+  '05082_E_Invalid external name "$1" for formal class "$2"'#000+
   '05083_E_Complete class definition with external name "$1" here'#000+
   '05084_W_Possible library conflict: symbol "$1" from library "$2" also '+
   'found in library "$3"'#000+
-  '05085_E_Cannot add implicit constructor '#039'Create'#039' because ident'+
-  'ifier ','already used by "$1"'#000+
+  '05085_E_Ca','nnot add implicit constructor '#039'Create'#039' because ide'+
+  'ntifier already used by "$1"'#000+
   '05086_E_Cannot generate default constructor for class, because parent '+
   'has no parameterless constructor'#000+
   '05087_D_Adding helper for $1'#000+
-  '05088_E_Found declaration: $1'#000+
-  '05089_W_Local variable "$1" of a managed type does not se','em to be in'+
-  'itialized'#000+
+  '05088_E_Found declaration: $1',#000+
+  '05089_W_Local variable "$1" of a managed type does not seem to be init'+
+  'ialized'#000+
   '05090_W_Variable "$1" of a managed type does not seem to be initialize'+
   'd'#000+
   '05091_H_Local variable "$1" of a managed type does not seem to be init'+
   'ialized'#000+
-  '05092_H_Variable "$1" of a managed type does not seem to be initializ',
-  'ed'#000+
+  '05092_H_Var','iable "$1" of a managed type does not seem to be initiali'+
+  'zed'#000+
   '05093_W_function result variable of a managed type does not seem to be'+
   ' initialized'#000+
   '05094_H_Function result variable of a managed type does not seem to be'+
   ' initialized'#000+
-  '05095_W_Duplicate identifier "$1"'#000+
-  '06009_E_Parameter list size exceeds 6','5535 bytes'#000+
+  '05095_W_Dupli','cate identifier "$1"'#000+
+  '06009_E_Parameter list size exceeds 65535 bytes'#000+
   '06012_E_File types must be var parameters'#000+
   '06013_E_The use of a far pointer isn'#039't allowed there'#000+
   '06015_E_EXPORT declared functions cannot be called'#000+
-  '06016_W_Possible illegal call of constructor or destructor'#000+
-  '06017_N_Inefficient code',#000+
+  '06016_W_Possible illegal ','call of constructor or destructor'#000+
+  '06017_N_Inefficient code'#000+
   '06018_W_unreachable code'#000+
   '06020_E_Abstract methods cannot be called directly'#000+
   '06027_DL_Register $1 weight $2 $3'#000+
   '06029_DL_Stack frame is omitted'#000+
-  '06031_E_Object or class methods cannot be inline.'#000+
+  '06031_E_Object or class methods cannot ','be inline.'#000+
   '06032_E_Procvar calls cannot be inline.'#000+
-  '06033_E','_No code for inline procedure stored'#000+
+  '06033_E_No code for inline procedure stored'#000+
   '06035_E_Element zero of an ansi/wide- or longstring cannot be accessed'+
   ', use (set)length instead'#000+
-  '06037_E_Constructors or destructors cannot be called inside a '#039'wit'+
-  'h'#039' clause'#000+
-  '06038_E_Cannot call message han','dler methods directly'#000+
+  '06037_E_Constructors or destructors cannot be cal','led inside a '#039'w'+
+  'ith'#039' clause'#000+
+  '06038_E_Cannot call message handler methods directly'#000+
   '06039_E_Jump in or outside of an exception block'#000+
   '06040_E_Control flow statements are not allowed in a finally block'#000+
-  '06041_W_Parameters size exceeds limit for certain cpu'#039's'#000+
-  '06042_W_Local variable size exceed limit for c','ertain cpu'#039's'#000+
+  '06041_W_Parameters size exceeds limit for ce','rtain cpu'#039's'#000+
+  '06042_W_Local variable size exceed limit for certain cpu'#039's'#000+
   '06043_E_Local variables size exceeds supported limit'#000+
   '06044_E_BREAK not allowed'#000+
   '06045_E_CONTINUE not allowed'#000+
-  '06046_F_Unknown compilerproc "$1". Check if you use the correct run ti'+
-  'me library.'#000+
-  '06047_F_Cannot find system type "$1".',' Check if you use the correct r'+
-  'un time library.'#000+
+  '06046_F_Unknown compilerproc "$1". Check if you use the corre','ct run '+
+  'time library.'#000+
+  '06047_F_Cannot find system type "$1". Check if you use the correct run'+
+  ' time library.'#000+
   '06048_H_Inherited call to abstract method ignored'#000+
   '06049_E_Goto label "$1" not defined or optimized away'#000+
-  '06050_F_Cannot find type "$1" in unit "$2". Check if you use the corre'+
-  'ct run time librar','y.'#000+
+  '06050_F_Cannot find type "$1" ','in unit "$2". Check if you use the cor'+
+  'rect run time library.'#000+
   '06051_E_Interprocedural gotos are allowed only to outer subroutines'#000+
   '06052_E_Label must be defined in the same scope as it is declared'#000+
-  '06053_E_Leaving procedures containing explicit or implicit exceptions '+
-  'frames using goto is not allowed'#000,
+  '06053_E_Leaving procedures containing explici','t or implicit exception'+
+  's frames using goto is not allowed'#000+
   '06054_E_In ISO mode, the mod operator is defined only for positive quo'+
   'tient'#000+
   '06055_DL_Auto inlining: $1'#000+
   '06056_E_The function used, is not supported by the selected instructio'+
-  'n set: $1'#000+
-  '06057_F_Maximum number of units ($1) reached for the curr','ent target'#000+
+  'n set: $1',#000+
+  '06057_F_Maximum number of units ($1) reached for the current target'#000+
   '06058_N_Call to subroutine "$1" marked as inline is not inlined'#000+
   '07000_DL_Starting $1 styled assembler parsing'#000+
   '07001_DL_Finished $1 styled assembler parsing'#000+
-  '07002_E_Non-label pattern contains @'#000+
-  '07004_E_Error building record offset',#000+
+  '07002_E_Non-lab','el pattern contains @'#000+
+  '07004_E_Error building record offset'#000+
   '07005_E_OFFSET used without identifier'#000+
   '07006_E_TYPE used without identifier'#000+
   '07007_E_Cannot use local variable or parameters here'#000+
   '07008_E_need to use OFFSET here'#000+
-  '07009_E_need to use $ here'#000+
+  '07009_E_need to use ','$ here'#000+
   '07010_E_Cannot use multiple relocatable symbols'#000+
-  '070','11_E_Relocatable symbol can only be added'#000+
+  '07011_E_Relocatable symbol can only be added'#000+
   '07012_E_Invalid constant expression'#000+
   '07013_E_Relocatable symbol is not allowed'#000+
   '07014_E_Invalid reference syntax'#000+
-  '07015_E_You cannot reach $1 from that code'#000+
-  '07016_E_Local symbols/labels are not allowed',' as references'#000+
+  '07015_E_You cannot reach $1 f','rom that code'#000+
+  '07016_E_Local symbols/labels are not allowed as references'#000+
   '07017_E_Invalid base and index register usage'#000+
   '07018_W_Possible error in object field handling'#000+
   '07019_E_Wrong scale factor specified'#000+
-  '07020_E_Multiple index register usage'#000+
+  '07020_E_Multiple index register usag','e'#000+
   '07021_E_Invalid operand type'#000+
-  '07022_E_Invalid string as o','pcode operand: $1'#000+
+  '07022_E_Invalid string as opcode operand: $1'#000+
   '07023_W_@CODE and @DATA not supported'#000+
   '07024_E_Null label references are not allowed'#000+
   '07025_E_Divide by zero in asm evaluator'#000+
   '07026_E_Illegal expression'#000+
-  '07027_E_escape sequence ignored: $1'#000+
+  '07027_E_escap','e sequence ignored: $1'#000+
   '07028_E_Invalid symbol reference'#000+
-  '07','029_W_Fwait can cause emulation problems with emu387'#000+
+  '07029_W_Fwait can cause emulation problems with emu387'#000+
   '07030_W_$1 without operand translated into $1P'#000+
   '07031_W_ENTER instruction is not supported by Linux kernel'#000+
-  '07032_W_Calling an overload function in assembler'#000+
-  '07033_E_Unsupported symbol type',' for operand'#000+
+  '07032_W_Calling an over','load function in assembler'#000+
+  '07033_E_Unsupported symbol type for operand'#000+
   '07034_E_Constant value out of bounds'#000+
   '07035_E_Error converting decimal $1'#000+
   '07036_E_Error converting octal $1'#000+
   '07037_E_Error converting binary $1'#000+
-  '07038_E_Error converting hexadecimal $1'#000+
+  '07038_E_Error converting he','xadecimal $1'#000+
   '07039_H_$1 translated to $2'#000+
-  '07040_W_$1 is ass','ociated to an overloaded function'#000+
+  '07040_W_$1 is associated to an overloaded function'#000+
   '07041_E_Cannot use SELF outside a method'#000+
   '07042_E_Cannot use OLDEBP outside a nested procedure'#000+
-  '07043_W_Procedures cannot return any value in asm code'#000+
+  '07043_W_Procedures cannot return any value in asm code',#000+
   '07044_E_SEG not supported'#000+
-  '07045_E_Size suffix and destina','tion or source size do not match'#000+
+  '07045_E_Size suffix and destination or source size do not match'#000+
   '07046_W_Size suffix and destination or source size do not match'#000+
   '07047_E_Assembler syntax error'#000+
   '07048_E_Invalid combination of opcode and operands'#000+
-  '07049_E_Assembler syntax error in operand'#000+
-  '07050_E_Assembler s','yntax error in constant'#000+
+  '070','49_E_Assembler syntax error in operand'#000+
+  '07050_E_Assembler syntax error in constant'#000+
   '07051_E_Invalid String expression'#000+
   '07052_W_constant with symbol $1 for address which is not on a pointer'#000+
   '07053_E_Unrecognized opcode $1'#000+
-  '07054_E_Invalid or missing opcode'#000+
-  '07055_E_Invalid combination of prefix and opcod','e: $1'#000+
+  '07054_E_Invalid or miss','ing opcode'#000+
+  '07055_E_Invalid combination of prefix and opcode: $1'#000+
   '07056_E_Invalid combination of override and opcode: $1'#000+
   '07057_E_Too many operands on line'#000+
   '07058_W_NEAR ignored'#000+
   '07059_W_FAR ignored'#000+
   '07060_E_Duplicate local symbol $1'#000+
-  '07061_E_Undefined local symbol $1'#000+
-  '07062_E_Unknown label identifier $1'#000,
+  '07061_E_Unde','fined local symbol $1'#000+
+  '07062_E_Unknown label identifier $1'#000+
   '07063_E_Invalid register name'#000+
   '07064_E_Invalid floating point register name'#000+
   '07066_W_Modulo not supported'#000+
   '07067_E_Invalid floating point constant $1'#000+
-  '07068_E_Invalid floating point expression'#000+
+  '07068_E_Invalid floating point expr','ession'#000+
   '07069_E_Wrong symbol type'#000+
-  '07070_E_Cannot index a lo','cal var or parameter with a register'#000+
+  '07070_E_Cannot index a local var or parameter with a register'#000+
   '07071_E_Invalid segment override expression'#000+
   '07072_W_Identifier $1 supposed external'#000+
   '07073_E_Strings not allowed as constants'#000+
-  '07074_E_No type of variable specified'#000+
-  '07075_E_assembler code not returned to t','ext section'#000+
+  '07074_E_No type of v','ariable specified'#000+
+  '07075_E_assembler code not returned to text section'#000+
   '07076_E_Not a directive or local symbol $1'#000+
   '07077_E_Using a defined name as a local label'#000+
   '07078_E_Dollar token is used without an identifier'#000+
-  '07079_W_32bit constant created for address'#000+
-  '07080_N_.align is target specific, use .balig','n or .p2align'#000+
+  '07079_W_32bit constant created',' for address'#000+
+  '07080_N_.align is target specific, use .balign or .p2align'#000+
   '07081_E_Cannot directly access fields of pointer-based parameters'#000+
   '07082_E_Can'#039't access fields of objects/classes directly'#000+
-  '07083_E_No size specified and unable to determine the size of the oper'+
-  'ands'#000+
-  '07084_E_Cannot use RESULT in ','this function'#000+
+  '07083_E_No size specified and unable to determ','ine the size of the op'+
+  'erands'#000+
+  '07084_E_Cannot use RESULT in this function'#000+
   '07086_W_"$1" without operand translated into "$1 %st,%st(1)"'#000+
   '07087_W_"$1 %st(n)" translated into "$1 %st,%st(n)"'#000+
   '07088_W_"$1 %st(n)" translated into "$1 %st(n),%st"'#000+
-  '07089_E_Char < not allowed here'#000+
-  '07090_E_Char > not allowed he','re'#000+
+  '070','89_E_Char < not allowed here'#000+
+  '07090_E_Char > not allowed here'#000+
   '07093_W_ALIGN not supported'#000+
   '07094_E_Inc and Dec cannot be together'#000+
   '07095_E_Invalid register list for MOVEM or FMOVEM'#000+
   '07096_E_Reglist invalid for opcode'#000+
-  '07097_E_Higher cpu mode required ($1)'#000+
-  '07098_W_No size specified and unable to determi','ne the size of the op'+
-  'erands, using DWORD as default'#000+
+  '07097_E_Higher cpu mode req','uired ($1)'#000+
+  '07098_W_No size specified and unable to determine the size of the oper'+
+  'ands, using DWORD as default'#000+
   '07099_E_Syntax error while trying to parse a shifter operand'#000+
   '07100_E_Address of packed component is not at a byte boundary'#000+
-  '07101_W_No size specified and unable to determine the size of the',' op'+
+  '07101_W','_No size specified and unable to determine the size of the op'+
   'erands, using BYTE as default'#000+
   '07102_W_Use of +offset(%ebp) for parameters invalid here'#000+
   '07103_W_Use of +offset(%ebp) is not compatible with regcall convention'+
   #000+
-  '07104_W_Use of -offset(%ebp) is not recommended for local variable acc'+
-  'ess'#000+
-  '07105','_W_Use of -offset(%esp), access may cause a crash or value may '+
-  'be lost'#000+
+  '07104_W_Use of -offse','t(%ebp) is not recommended for local variable a'+
+  'ccess'#000+
+  '07105_W_Use of -offset(%esp), access may cause a crash or value may be'+
+  ' lost'#000+
   '07106_E_VMTOffset must be used in combination with a virtual method, a'+
   'nd "$1" is not virtual'#000+
-  '07107_E_Generating PIC, but reference is not PIC-safe'#000+
-  '07108_E_All registers ','in a register set must be of the same kind and'+
-  ' width'#000+
+  '07107_E_Generating',' PIC, but reference is not PIC-safe'#000+
+  '07108_E_All registers in a register set must be of the same kind and w'+
+  'idth'#000+
   '07109_E_A register set cannot be empty'#000+
   '07110_W_@GOTPCREL is useless and potentially dangerous for local symbo'+
   'ls'#000+
-  '07111_W_Constant with general purpose segment register'#000+
-  '07112_E_Invalid offs','et value for $1'#000+
+  '07111_W_Constant ','with general purpose segment register'#000+
+  '07112_E_Invalid offset value for $1'#000+
   '07113_E_Invalid register for $1'#000+
   '07114_E_SEH directives are allowed only in pure assembler procedures'#000+
   '07115_E_Directive "$1" is not supported for the current target'#000+
-  '07116_E_This function'#039's result location cannot be encoded di','rect'+
+  '07','116_E_This function'#039's result location cannot be encoded direct'+
   'ly in a single operand when "nostackframe" is used'#000+
   '07117_E_GOTPCREL references in Intel assembler syntax cannot contain a'+
   ' base or index register, and their offset must 0.'#000+
-  '07118_E_The current target does not support GOTPCREL relocations'#000,
+  '07118_E','_The current target does not support GOTPCREL relocations'#000+
   '07119_W_Exported/global symbols should be accessed via the GOT'#000+
   '07120_W_Check size of memory operand "$1"'#000+
   '07121_W_Check size of memory operand "$1: memory-operand-size is $2 bi'+
-  'ts, but expected [$3 bits]"'#000+
-  '07122_W_Check size of memory operand ','"$1: memory-operand-size is $2 '+
-  'bits, but expected [$3 bits + $4 byte offset]"'#000+
+  'ts, but',' expected [$3 bits]"'#000+
+  '07122_W_Check size of memory operand "$1: memory-operand-size is $2 bi'+
+  'ts, but expected [$3 bits + $4 byte offset]"'#000+
   '07123_W_Check "$1: offset of memory operand is negative "$2 byte"'#000+
-  '07124_W_Check "$1: size of memory operand is empty, but es exists diff'+
-  'erent definitions of the m','emory size =>> map to $2 (smallest option)'+
+  '07124_W_Check "$1: size of memory oper','and is empty, but es exists di'+
+  'fferent definitions of the memory size =>> map to $2 (smallest option)'+
   '"'#000+
   '07125_E_Invalid register used in memory reference expression: "$1"'#000+
   '07126_E_SEG used without identifier'#000+
-  '07127_E_@CODE and @DATA can only be used with the SEG operator'#000+
-  '07128_E_Not enough space (16 b','its required) for the segment constant'+
-  ' of symbol $1'#000+
+  '07127_E_@CODE and @DATA can only be',' used with the SEG operator'#000+
+  '07128_E_Not enough space (16 bits required) for the segment constant o'+
+  'f symbol $1'#000+
   '07129_E_Invalid value of .code directive constant'#000+
   '07130_W_No size specified and unable to determine the size of the cons'+
-  'tant, using BYTE as default'#000+
-  '07131_W_No size specified and unable to ','determine the size of the co'+
-  'nstant, using WORD as default'#000+
+  'tant, usin','g BYTE as default'#000+
+  '07131_W_No size specified and unable to determine the size of the cons'+
+  'tant, using WORD as default'#000+
   '07132_E_Cannot override ES segment'#000+
   '07133_W_Reference is not valid here (expected "$1")'#000+
   '07134_E_Address sizes do not match'#000+
-  '07135_E_Instruction "POP CS" is not valid for the current ta','rget'#000+
+  '07','135_E_Instruction "POP CS" is not valid for the current target'#000+
   '07136_W_Instruction "POP CS" is not portable (it only works on 8086 an'+
   'd 8088 CPUs)'#000+
   '07137_E_Label $1 can only be declared public before it'#039's defined'#000+
-  '07138_E_Local label $1 cannot be declared public'#000+
-  '07139_E_Cannot use multiple segment ov','errides'#000+
+  '07138_E_Local label $1 cannot',' be declared public'#000+
+  '07139_E_Cannot use multiple segment overrides'#000+
   '07140_W_Multiple segment overrides (only the last one will take effect'+
   ')'#000+
   '07141_W_Segment base $1 will be generated, but is ignored by the CPU i'+
   'n 64-bit mode'#000+
-  '08000_F_Too many assembler files'#000+
-  '08001_F_Selected assembler output not suppo','rted'#000+
+  '08000_F_Too many a','ssembler files'#000+
+  '08001_F_Selected assembler output not supported'#000+
   '08002_F_Comp not supported'#000+
   '08003_F_Direct not support for binary writers'#000+
   '08004_E_Allocating of data is only allowed in bss section'#000+
   '08005_F_No binary writer selected'#000+
-  '08006_E_Asm: Opcode $1 not in table'#000+
-  '08007_E_Asm: $1 invalid combinatio','n of opcode and operands'#000+
+  '08006_E_Asm:',' Opcode $1 not in table'#000+
+  '08007_E_Asm: $1 invalid combination of opcode and operands'#000+
   '08008_E_Asm: 16 Bit references not supported'#000+
   '08009_E_Asm: Invalid effective address'#000+
   '08010_E_Asm: Immediate or reference expected'#000+
-  '08011_E_Asm: $1 value exceeds bounds $2'#000+
+  '08011_E_Asm: $1 value exceed','s bounds $2'#000+
   '08012_E_Asm: Short jump is out of range $1'#000+
-  '080','13_E_Asm: Undefined label $1'#000+
+  '08013_E_Asm: Undefined label $1'#000+
   '08014_E_Asm: Comp type not supported for this target'#000+
   '08015_E_Asm: Extended type not supported for this target'#000+
   '08016_E_Asm: Duplicate label $1'#000+
-  '08017_E_Asm: Redefined label $1'#000+
+  '08017_E_Asm',': Redefined label $1'#000+
   '08018_E_Asm: First defined here'#000+
-  '08019','_E_Asm: Invalid register $1'#000+
+  '08019_E_Asm: Invalid register $1'#000+
   '08020_E_Asm: 16 or 32 Bit references not supported'#000+
   '08021_E_Asm: 64 Bit operands not supported'#000+
-  '08022_E_Asm: AH,BH,CH or DH cannot be used in an instruction requiring'+
-  ' REX prefix'#000+
-  '08023_E_Missing .seh_endprologue dir','ective'#000+
+  '08022_E_Asm: AH,BH,CH or DH cannot be used in an instruction',' requiri'+
+  'ng REX prefix'#000+
+  '08023_E_Missing .seh_endprologue directive'#000+
   '08024_E_Function prologue exceeds 255 bytes'#000+
   '08025_E_.seh_handlerdata directive without preceding .seh_handler'#000+
   '08026_F_Relocation count for section $1 exceeds 65535'#000+
-  '08027_N_Change of bind type of symbol $1 from $2 to $3 after use'#000+
-  '0802','8_H_Change of bind type of symbol $1 from $2 to $3 after use'#000+
+  '08027_N_Cha','nge of bind type of symbol $1 from $2 to $3 after use'#000+
+  '08028_H_Change of bind type of symbol $1 from $2 to $3 after use'#000+
   '08029_E_Asm: 32 Bit references not supported'#000+
   '08030_F_Code segment too large'#000+
   '08031_F_Data segment too large'#000+
-  '08032_E_Instruction not supported by the selected instruction set'#000+
-  '08033_','E_Asm: conditional branch destination is out of range'#000+
+  '08032_E_Instru','ction not supported by the selected instruction set'#000+
+  '08033_E_Asm: conditional branch destination is out of range'#000+
   '09000_W_Source operating system redefined'#000+
   '09001_I_Assembling (pipe) $1'#000+
   '09002_E_Can'#039't create assembler file: $1'#000+
-  '09003_E_Can'#039't create object file: $1 (error code: $2)'#000+
-  '09004_E_Can'#039't create ','archive file: $1'#000+
+  '09003_E_Can'#039't cre','ate object file: $1 (error code: $2)'#000+
+  '09004_E_Can'#039't create archive file: $1'#000+
   '09005_E_Assembler $1 not found, switching to external assembling'#000+
   '09006_T_Using assembler: $1'#000+
   '09007_E_Error while assembling exitcode $1'#000+
-  '09008_E_Can'#039't call the assembler, error $1 switching to external a'+
-  'ssembling'#000+
-  '09009_I_Ass','embling $1'#000+
+  '09008_E_Can'#039't call the assemb','ler, error $1 switching to external'+
+  ' assembling'#000+
+  '09009_I_Assembling $1'#000+
   '09010_I_Assembling with smartlinking $1'#000+
   '09011_W_Object $1 not found, Linking may fail !'#000+
   '09012_W_Library $1 not found, Linking may fail !'#000+
   '09013_E_Error while linking'#000+
-  '09014_E_Can'#039't call the linker, switching to external linking'#000+
-  '090','15_I_Linking $1'#000+
+  '09014_','E_Can'#039't call the linker, switching to external linking'#000+
+  '09015_I_Linking $1'#000+
   '09016_E_Util $1 not found, switching to external linking'#000+
   '09017_T_Using util $1'#000+
   '09018_E_Creation of Executables not supported'#000+
-  '09019_E_Creation of Dynamic/Shared Libraries not supported'#000+
-  '09035_E_Creation of Static Libraries not',' supported'#000+
+  '09019_E_Creation of Dynamic/Shared Librar','ies not supported'#000+
+  '09035_E_Creation of Static Libraries not supported'#000+
   '09020_I_Closing script $1'#000+
   '09021_E_resource compiler "$1" not found, switching to external mode'#000+
   '09022_I_Compiling resource $1'#000+
-  '09023_T_unit $1 cannot be statically linked, switching to smart linkin'+
-  'g'#000+
-  '09024_T_unit $1 cannot be smart ','linked, switching to static linking'#000+
+  '09023_T_unit $1 cannot be statically linked, s','witching to smart link'+
+  'ing'#000+
+  '09024_T_unit $1 cannot be smart linked, switching to static linking'#000+
   '09025_T_unit $1 cannot be shared linked, switching to static linking'#000+
   '09026_E_unit $1 cannot be smart or static linked'#000+
-  '09027_E_unit $1 cannot be shared or static linked'#000+
-  '09028_D_Calling resource compiler "$','1" with "$2" as command line'#000+
+  '09027_E_unit $1 cannot be sh','ared or static linked'#000+
+  '09028_D_Calling resource compiler "$1" with "$2" as command line'#000+
   '09029_E_Error while compiling resources'#000+
   '09030_E_Can'#039't call the resource compiler "$1", switching to extern'+
   'al mode'#000+
   '09031_E_Can'#039't open resource file "$1"'#000+
-  '09032_E_Can'#039't write resource file "$1"'#000+
-  '09033_N_File "$1" no','t found for backquoted cat command'#000+
+  '0','9032_E_Can'#039't write resource file "$1"'#000+
+  '09033_N_File "$1" not found for backquoted cat command'#000+
   '09034_W_"$1" not found, this will probably cause a linking failure'#000+
   '09128_F_Can'#039't post process executable $1'#000+
   '09129_F_Can'#039't open executable $1'#000+
-  '09130_X_Size of Code: $1 bytes'#000+
-  '09131_X_Size of initialized data:',' $1 bytes'#000+
+  '09130_','X_Size of Code: $1 bytes'#000+
+  '09131_X_Size of initialized data: $1 bytes'#000+
   '09132_X_Size of uninitialized data: $1 bytes'#000+
   '09133_X_Stack space reserved: $1 bytes'#000+
   '09134_X_Stack space committed: $1 bytes'#000+
-  '09200_F_Executable image size is too big for $1 target.'#000+
-  '09201_W_Object file "$1" contains 32-bit absolute ','relocation to symb'+
-  'ol "$2".'#000+
+  '09200_F_Executable image size is too big for $1 ','target.'#000+
+  '09201_W_Object file "$1" contains 32-bit absolute relocation to symbol'+
+  ' "$2".'#000+
   '09202_E_Program segment too large (exceeds 64k by $1 bytes)'#000+
   '09203_E_Code segment "$1" too large (exceeds 64k by $2 bytes)'#000+
-  '09204_E_Data segment "$1" too large (exceeds 64k by $2 bytes)'#000+
-  '09205_E_Segment "$1" too larg','e (exceeds 64k by $2 bytes)'#000+
+  '09204_E_Data segment "$1" too lar','ge (exceeds 64k by $2 bytes)'#000+
+  '09205_E_Segment "$1" too large (exceeds 64k by $2 bytes)'#000+
   '09206_E_Group "$1" too large (exceeds 64k by $2 bytes)'#000+
   '09207_E_Cannot create a .COM file, because the program contains segmen'+
   't relocations'#000+
-  '09208_W_Program "$1" uses experimental CheckPointer option'#000+
-  '09209_E_Multip','le defined symbol "$1"'#000+
+  '09208_W_Program',' "$1" uses experimental CheckPointer option'#000+
+  '09209_E_Multiple defined symbol "$1"'#000+
   '09210_E_COMDAT selection mode $1 not supported (section: "$1")'#000+
   '09211_E_Associative section expected for COMDAT section "$1"'#000+
-  '09212_E_COMDAT section selection mode doesn'#039't match for section "$'+
-  '1" and symbol "$2"'#000+
-  '09213_E_','Associative COMDAT section for section "$1" not found'#000+
+  '09212_E_COMDAT section selection mo','de doesn'#039't match for section '+
+  '"$1" and symbol "$2"'#000+
+  '09213_E_Associative COMDAT section for section "$1" not found'#000+
   '09214_D_Discarding duplicate symbol "$1" due to COMDAT selection mode'#000+
-  '09215_D_Discarding duplicate symbol "$1" with same size due to COMDAT '+
-  'selection mode'#000+
-  '09216_D_Discarding duplicate sy','mbol "$1" with same content due to CO'+
-  'MDAT selection mode'#000+
+  '09215_D_Discarding duplicate symbol "$1" with same size du','e to COMDA'+
+  'T selection mode'#000+
+  '09216_D_Discarding duplicate symbol "$1" with same content due to COMD'+
+  'AT selection mode'#000+
   '09217_D_Replacing duplicate symbol "$1" with smaller size due to COMDA'+
   'T selection mode'#000+
-  '09218_E_Size of duplicate COMDAT symbol "$1" differs'#000+
-  '09219_E_Content of duplicate COMDAT symbol ','"$1" differs'#000+
+  '09218_E_Size of duplicate COMDAT symbo','l "$1" differs'#000+
+  '09219_E_Content of duplicate COMDAT symbol "$1" differs'#000+
   '09220_E_COMDAT selection mode for symbol "$1" differs'#000+
   '10000_T_Unitsearch: $1'#000+
   '10001_T_PPU Loading $1'#000+
@@ -1135,192 +1135,191 @@
   '10002_U_PPU Name: $1'#000+
   '10003_U_PPU Flags: $1'#000+
   '10004_U_PPU Crc: $1'#000+
-  '10005_U_PPU Time: $1'#000+
+  '10005_','U_PPU Time: $1'#000+
   '10006_U_PPU File too short'#000+
-  '10007_U_PPU Inva','lid Header (no PPU at the begin)'#000+
+  '10007_U_PPU Invalid Header (no PPU at the begin)'#000+
   '10008_U_PPU Invalid Version $1'#000+
   '10009_U_PPU is compiled for another processor'#000+
   '10010_U_PPU is compiled for another target'#000+
   '10011_U_PPU Source: $1'#000+
-  '10012_U_Writing $1'#000+
+  '10012_','U_Writing $1'#000+
   '10013_F_Can'#039't Write PPU-File'#000+
-  '10014_F_Error re','ading PPU-File'#000+
+  '10014_F_Error reading PPU-File'#000+
   '10015_F_unexpected end of PPU-File'#000+
   '10016_F_Invalid PPU-File entry: $1'#000+
   '10017_F_PPU Dbx count problem'#000+
   '10018_E_Illegal unit name: $1 (expecting $2)'#000+
-  '10019_F_Too much units'#000+
+  '10019_F_Too much units',#000+
   '10020_F_Circular unit reference between $1 and $2'#000+
-  '10021_F','_Can'#039't compile unit $1, no sources available'#000+
+  '10021_F_Can'#039't compile unit $1, no sources available'#000+
   '10022_F_Can'#039't find unit $1 used by $2'#000+
   '10023_W_Unit $1 was not found but $2 exists'#000+
   '10024_F_Unit $1 searched but $2 found'#000+
-  '10025_W_Compiling the system unit requires the -Us switch'#000+
-  '10026_F_There wer','e $1 errors compiling module, stopping'#000+
+  '10025_W_Compiling',' the system unit requires the -Us switch'#000+
+  '10026_F_There were $1 errors compiling module, stopping'#000+
   '10027_U_Load from $1 ($2) unit $3'#000+
   '10028_U_Recompiling $1, checksum changed for $2'#000+
   '10029_U_Recompiling $1, source found only'#000+
-  '10030_U_Recompiling unit, static lib is older than ppufile'#000+
-  '10031_U_Recompilin','g unit, shared lib is older than ppufile'#000+
+  '10030_U_Recompiling',' unit, static lib is older than ppufile'#000+
+  '10031_U_Recompiling unit, shared lib is older than ppufile'#000+
   '10032_U_Recompiling unit, obj and asm are older than ppufile'#000+
   '10033_U_Recompiling unit, obj is older than asm'#000+
-  '10034_U_Parsing interface of $1'#000+
+  '10034_U_Parsing interface of $1'#000,
   '10035_U_Parsing implementation of $1'#000+
-  '10036_U_Second load f','or unit $1'#000+
+  '10036_U_Second load for unit $1'#000+
   '10037_U_PPU Check file $1 time $2'#000+
   '10040_W_Can'#039't recompile unit $1, but found modified include files'#000+
   '10041_U_File $1 is newer than the one used for creating PPU file $2'#000+
-  '10042_U_Trying to use a unit which was compiled with a differ','ent FPU'+
+  '100','42_U_Trying to use a unit which was compiled with a different FPU'+
   ' mode'#000+
   '10043_U_Loading interface units from $1'#000+
   '10044_U_Loading implementation units from $1'#000+
   '10045_U_Interface CRC changed for unit $1'#000+
-  '10046_U_Implementation CRC changed for unit $1'#000+
+  '10046_U_Implementation CRC changed for uni','t $1'#000+
   '10047_U_Finished compiling unit $1'#000+
-  '10048_U_Adding dep','endency: $1 depends on $2'#000+
+  '10048_U_Adding dependency: $1 depends on $2'#000+
   '10049_U_No reload, is caller: $1'#000+
   '10050_U_No reload, already in second compile: $1'#000+
   '10051_U_Flag for reload: $1'#000+
   '10052_U_Forced reloading'#000+
-  '10053_U_Previous state of $1: $2'#000+
-  '10054_U_Already compiling $1, setting second c','ompile'#000+
+  '10053_U_Previous stat','e of $1: $2'#000+
+  '10054_U_Already compiling $1, setting second compile'#000+
   '10055_U_Loading unit $1'#000+
   '10056_U_Finished loading unit $1'#000+
   '10057_U_Registering new unit $1'#000+
   '10058_U_Re-resolving unit $1'#000+
-  '10059_U_Skipping re-resolving unit $1, still loading used units'#000+
+  '10059_U_Skipping re-resolving unit $1, still loading used',' units'#000+
   '10060_U_Unloading resource unit $1 (not needed)'#000+
-  '100','61_E_Unit $1 was compiled using a different whole program optimiz'+
-  'ation feedback input ($2, $3); recompile it without wpo or use the sam'+
-  'e wpo feedback input file for this compilation invocation'#000+
-  '10062_U_Indirect interface (objects/classes) CR','C changed for unit $1'+
-  #000+
+  '10061_E_Unit $1 was compiled using a different whole program optimizat'+
+  'ion feedback input ($2, $3); recompile it without wpo or use the same '+
+  'wpo feedback input file for this compilation ','invocation'#000+
+  '10062_U_Indirect interface (objects/classes) CRC changed for unit $1'#000+
   '10063_U_PPU is compiled for another i8086 memory model'#000+
   '10064_U_Loading unit $1 from package $2'#000+
-  '10065_F_Internal type "$1" was not found. Check if you use the correct'+
-  ' run time library.'#000+
-  '10066_F_Internal type "$1" does no','t look as expected. Check if you u'+
-  'se the correct run time library.'#000+
+  '10065_F_Internal type "$1" was not found. Check if you use the co','rre'+
+  'ct run time library.'#000+
+  '10066_F_Internal type "$1" does not look as expected. Check if you use'+
+  ' the correct run time library.'#000+
   '11000_O_$1 [options] <inputfile> [options]'#000+
   '11001_W_Only one source file supported, changing source file to compil'+
-  'e from "$1" into "$2"'#000+
-  '11002_W_DEF file can be created only f','or OS/2'#000+
+  'e ','from "$1" into "$2"'#000+
+  '11002_W_DEF file can be created only for OS/2'#000+
   '11003_E_nested response files are not supported'#000+
   '11004_F_No source file name in command line'#000+
   '11005_N_No option inside $1 config file'#000+
   '11006_E_Illegal parameter: $1'#000+
-  '11007_H_-? writes help pages'#000+
+  '11007_H_-? w','rites help pages'#000+
   '11008_F_Too many config files nested'#000+
-  '1100','9_F_Unable to open file $1'#000+
+  '11009_F_Unable to open file $1'#000+
   '11010_D_Reading further options from $1'#000+
   '11011_W_Target is already set to: $1'#000+
   '11012_W_Shared libs not supported on DOS platform, reverting to static'+
   #000+
-  '11013_F_In options file $1 at line $2 too many #IF(N)DEFs encount','ere'+
+  '11013_F','_In options file $1 at line $2 too many #IF(N)DEFs encountere'+
   'd'#000+
   '11014_F_In options file $1 at line $2 unexpected #ENDIFs encountered'#000+
   '11015_F_Open conditional at the end of the options file'#000+
-  '11016_W_Debug information generation is not supported by this executab'+
-  'le'#000+
+  '11016_W_Debug information generation is not supporte','d by this execut'+
+  'able'#000+
   '11017_H_Try recompiling with -dGDB'#000+
-  '11','018_W_You are using the obsolete switch $1'#000+
+  '11018_W_You are using the obsolete switch $1'#000+
   '11019_W_You are using the obsolete switch $1, please use $2'#000+
   '11020_N_Switching assembler to default source writing assembler'#000+
-  '11021_W_Assembler output selected "$1" is not compatible with "$2"'#000+
-  '11022_','W_"$1" assembler use forced'#000+
+  '11021_W_Assembl','er output selected "$1" is not compatible with "$2"'#000+
+  '11022_W_"$1" assembler use forced'#000+
   '11026_T_Reading options from file $1'#000+
   '11027_T_Reading options from environment $1'#000+
   '11028_D_Handling option "$1"'#000+
   '11029_O_*** press enter ***'#000+
-  '11030_H_Start of reading config file $1'#000+
-  '11031_H_End of reading config file',' $1'#000+
+  '11030_H_Start of',' reading config file $1'#000+
+  '11031_H_End of reading config file $1'#000+
   '11032_D_interpreting option "$1"'#000+
   '11036_D_interpreting firstpass option "$1"'#000+
   '11033_D_interpreting file option "$1"'#000+
   '11034_D_Reading config file "$1"'#000+
-  '11035_D_found source file name "$1"'#000+
+  '11035_D_found source file name ','"$1"'#000+
   '11039_E_Unknown codepage "$1"'#000+
-  '11040_F_Config file $1 ','is a directory'#000+
+  '11040_F_Config file $1 is a directory'#000+
   '11041_W_Assembler output selected "$1" cannot generate debug info, deb'+
   'ugging disabled'#000+
   '11042_W_Use of ppc386.cfg is deprecated, please use fpc.cfg instead'#000+
-  '11043_F_In options file $1 at line $2 #ELSE directive without #IF(N)DE'+
-  'F',' found'#000+
+  '11043_F_In op','tions file $1 at line $2 #ELSE directive without #IF(N)'+
+  'DEF found'#000+
   '11044_F_Option "$1" is not, or not yet, supported on the current targe'+
   't platform'#000+
   '11045_F_The feature "$1" is not, or not yet, supported on the selected'+
   ' target platform'#000+
-  '11046_N_DWARF debug information cannot be used with smart linking',' on'+
+  '11046_N','_DWARF debug information cannot be used with smart linking on'+
   ' this target, switching to static linking'#000+
   '11047_W_Option "$1" is ignored for the current target platform.'#000+
   '11048_W_Disabling external debug information because it is unsupported'+
-  ' for the selected target/debug format combination.'#000+
-  '11049_N_DW','ARF debug information cannot be used with smart linking wi'+
-  'th external assembler, disabling static library creation.'#000+
-  '11050_E_Invalid value for MACOSX_DEPLOYMENT_TARGET environment variabl'+
-  'e: $1'#000+
-  '11051_E_Invalid value for IPHONEOS_DEPLOYMENT_TA','RGET environment var'+
-  'iable: $1'#000+
+  ' fo','r the selected target/debug format combination.'#000+
+  '11049_N_DWARF debug information cannot be used with smart linking with'+
+  ' external assembler, disabling static library creation.'#000+
+  '11050_E_Invalid value for MACOSX_DEPLOYMENT_TARGET environment var','ia'+
+  'ble: $1'#000+
+  '11051_E_Invalid value for IPHONEOS_DEPLOYMENT_TARGET environment varia'+
+  'ble: $1'#000+
   '11052_E_You must use a FPU type of VFPV2, VFPV3 or VFPV3_D16 when usin'+
   'g the EABIHF ABI target'#000+
-  '11053_W_The selected debug format is not supported on the current targ'+
-  'et, not changing the current setting'#000+
-  '11054_E_a','rgument to "$1" is missing'#000+
+  '11053_W_The selected debug format is not supported on the ','current ta'+
+  'rget, not changing the current setting'#000+
+  '11054_E_argument to "$1" is missing'#000+
   '11055_E_malformed parameter: $1'#000+
   '11056_W_Smart linking requires external linker'#000+
   '11057_E_Creating .COM files is not supported in the current memory mod'+
-  'el. Only the tiny memory model supports making .COM files.'#000+
-  '11058','_W_Experimental CheckPointer option not enabled because it is i'+
-  'ncomptatible with -Ur option.'#000+
+  'el. On','ly the tiny memory model supports making .COM files.'#000+
+  '11058_W_Experimental CheckPointer option not enabled because it is inc'+
+  'omptatible with -Ur option.'#000+
   '11059_E_Unsupported target architecture -P$1, invoke the "fpc" compile'+
   'r driver instead.'#000+
-  '11060_E_Feature switches are only supported while compiling',' the syst'+
+  '1','1060_E_Feature switches are only supported while compiling the syst'+
   'em unit.'#000+
   '12000_F_Cannot open whole program optimization feedback file "$1"'#000+
   '12001_D_Processing whole program optimization information in wpo feedb'+
   'ack file "$1"'#000+
-  '12002_D_Finished processing the whole program optimization information'+
-  ' i','n wpo feedback file "$1"'#000+
+  '12002_D_Finish','ed processing the whole program optimization informati'+
+  'on in wpo feedback file "$1"'#000+
   '12003_E_Expected section header, but got "$2" at line $1 of wpo feedba'+
   'ck file'#000+
   '12004_W_No handler registered for whole program optimization section "'+
-  '$2" at line $1 of wpo feedback file, ignoring'#000+
-  '12005_D_Found whole p','rogram optimization section "$1" with informati'+
-  'on about "$2"'#000+
+  '$2" at li','ne $1 of wpo feedback file, ignoring'#000+
+  '12005_D_Found whole program optimization section "$1" with information'+
+  ' about "$2"'#000+
   '12006_F_The selected whole program optimizations require a previously '+
   'generated feedback file (use -Fw to specify)'#000+
-  '12007_E_No collected information necessary to perform "$1" whole',' pro'+
+  '12007_','E_No collected information necessary to perform "$1" whole pro'+
   'gram optimization found'#000+
   '12008_F_Specify a whole program optimization feedback file to store th'+
   'e generated info in (using -FW)'#000+
-  '12009_E_Not generating any whole program optimization information, yet'+
-  ' a feedback file was specified (using -F','W)'#000+
+  '12009_E_Not generating any whole program optimizatio','n information, y'+
+  'et a feedback file was specified (using -FW)'#000+
   '12010_E_Not performing any whole program optimizations, yet an input f'+
   'eedback file was specified (using -Fw)'#000+
-  '12011_D_Skipping whole program optimization section "$1", because not '+
+  '12011_D_Skipping whole program optimization section "$1", because not ',
   'needed by the requested optimizations'#000+
-  '12012_W_Overriding p','reviously read information for "$1" from feedbac'+
-  'k input file using information in section "$2"'#000+
+  '12012_W_Overriding previously read information for "$1" from feedback '+
+  'input file using information in section "$2"'#000+
   '12013_E_Cannot extract symbol liveness information from program when s'+
-  'tripping symbols, use -Xs-'#000+
-  '12014_E_Cannot extract symbol liveness informati','on from program when'+
-  ' when not linking'#000+
+  'tripping symbols,',' use -Xs-'#000+
+  '12014_E_Cannot extract symbol liveness information from program when w'+
+  'hen not linking'#000+
   '12015_F_Cannot find "$1" or "$2" to extract symbol liveness informatio'+
   'n from linked program'#000+
-  '12016_E_Error during reading symbol liveness information produced by "'+
-  '$1"'#000+
-  '12017_F_Error executing "$1" (exitco','de: $2) to extract symbol inform'+
-  'ation from linked program'#000+
+  '12016_E_Error during reading symbol liveness informa','tion produced by'+
+  ' "$1"'#000+
+  '12017_F_Error executing "$1" (exitcode: $2) to extract symbol informat'+
+  'ion from linked program'#000+
   '12018_E_Collection of symbol liveness information can only help when u'+
   'sing smart linking, use -CX -XX'#000+
-  '12019_E_Cannot create specified whole program optimisation feedback fi'+
-  'le "$1"'#000+
-  '13','001_F_Can'#039't find package $1'#000+
+  '12019_E_Cannot create ','specified whole program optimisation feedback '+
+  'file "$1"'#000+
+  '13001_F_Can'#039't find package $1'#000+
   '13002_U_PCP file for package $1 found'#000+
   '13003_E_Duplicate package $1'#000+
   '13004_E_Unit $1 can not be part of a package'#000+
-  '13005_N_Unit $1 is implicitely imported into package $2'#000+
-  '13006_F_Failed to create PCP file $2 for pac','kage $1'#000+
+  '13005_N_Unit $1 is implicitely imported in','to package $2'#000+
+  '13006_F_Failed to create PCP file $2 for package $1'#000+
   '13007_F_Failed to read PCP file for package $1'#000+
   '13008_T_PCP loading $1'#000+
   '13009_U_PCP Name: $1'#000+
@@ -1327,28 +1326,28 @@
   '13010_U_PCP Flags: $1'#000+
   '13011_U_PCP Crc: $1'#000+
   '13012_U_PCP Time: $1'#000+
-  '13013_U_PCP File too short'#000+
+  '13013_U_PCP File too',' short'#000+
   '13014_U_PCP Invalid Header (no PCP at the begin)'#000+
-  '13','015_U_PCP Invalid Version $1'#000+
+  '13015_U_PCP Invalid Version $1'#000+
   '13016_U_PCP is compiled for another processor'#000+
   '13017_U_PCP is compiled for another target'#000+
   '13018_U_Writing $1'#000+
   '13019_F_Can'#039't Write PCP-File'#000+
-  '13020_F_Error reading PCP-File'#000+
+  '13020_F_Error re','ading PCP-File'#000+
   '13021_F_unexpected end of PCP-File'#000+
-  '13022_F_','Invalid PCP-File entry: $1'#000+
+  '13022_F_Invalid PCP-File entry: $1'#000+
   '13023_U_Trying to use a unit which was compiled with a different FPU m'+
   'ode'#000+
   '13024_T_Packagesearch: $1'#000+
   '13025_U_Required package $1'#000+
   '13026_U_Contained unit $1'#000+
-  '13027_E_Unit $1 is already contained in package $2'#000+
-  '13028_W_','Unit $1 is imported from indirectly required package $2'#000+
+  '1','3027_E_Unit $1 is already contained in package $2'#000+
+  '13028_W_Unit $1 is imported from indirectly required package $2'#000+
   '13029_U_PPL filename $1'#000+
   '11023_Free Pascal Compiler version $FPCFULLVERSION [$FPCDATE] for $FPC'+
   'CPU'#010+
-  'Copyright (c) 1993-2018 by Florian Klaempfl and others'#000+
-  '11024_Free Pascal Compiler vers','ion $FPCVERSION'#010+
+  'Copyright (c) 1993-2018 by F','lorian Klaempfl and others'#000+
+  '11024_Free Pascal Compiler version $FPCVERSION'#010+
   #010+
   'Compiler date      : $FPCDATE'#010+
   'Compiler CPU target: $FPCCPU'#010+
@@ -1357,10 +1356,10 @@
   'ment):'#010+
   '  $OSTARGETS'#010+
   #010+
-  'Supported CPU instruction sets:'#010+
+  'Supported CPU instruct','ion sets:'#010+
   '  $INSTRUCTIONSETS'#010+
   #010+
-  'Supported FPU instruction se','ts:'#010+
+  'Supported FPU instruction sets:'#010+
   '  $FPUINSTRUCTIONSETS'#010+
   #010+
   'Supported inline assembler modes:'#010+
@@ -1372,153 +1371,153 @@
   'Supported ABI targets:'#010+
   '  $ABITARGETS'#010+
   #010+
-  'Supported Optimizations:'#010+
+  'Supported Optimi','zations:'#010+
   '  $OPTIMIZATIONS'#010+
   #010+
-  'Supported Whole Program Optimiz','ations:'#010+
+  'Supported Whole Program Optimizations:'#010+
   '  All'#010+
   '  $WPOPTIMIZATIONS'#010+
   #010+
   'Supported Microcontroller types:$\n  $CONTROLLERTYPES$\n'#010+
   'This program comes under the GNU General Public Licence'#010+
-  'For more information read COPYING.v2'#010+
+  'For more information read COPYING.v','2'#010+
   #010+
   'Please report bugs in our bug tracker on:'#010+
-  '             ','    http://bugs.freepascal.org'#010+
+  '                 http://bugs.freepascal.org'#010+
   #010+
   'More information may be found on our WWW pages (including directions'#010+
   'for mailing lists useful for asking questions or discussing potential'#010+
-  'new features, etc.):'#010+
+  'new feature','s, etc.):'#010+
   '                 http://www.freepascal.org'#000+
-  '11025','_F*0*_Only options valid for the default or selected platform a'+
-  're listed.'#010+
+  '11025_F*0*_Only options valid for the default or selected platform are'+
+  ' listed.'#010+
   '**0*_Put + after a boolean switch option to enable it, - to disable it'+
   '.'#010+
-  '**1@<x>_Read compiler options from <x> in addition to the default fpc.'+
-  'cfg'#010+
-  '**1a_The compiler do','es not delete the generated assembler file'#010+
+  '**1@<x>_Read compiler options from <','x> in addition to the default fp'+
+  'c.cfg'#010+
+  '**1a_The compiler does not delete the generated assembler file'#010+
   '**2a5_Don'#039't generate Big Obj COFF files for GNU Binutils older tha'+
   'n 2.25 (Windows, NativeNT)'#010+
-  '**2al_List sourcecode lines in assembler file'#010+
-  '**2an_List node info in assembler file (-dEXTDEBUG compile','r)'#010+
+  '**2al_List sourcecode lines in assembler file'#010,
+  '**2an_List node info in assembler file (-dEXTDEBUG compiler)'#010+
   '**2ao_Add an extra option to external assembler call (ignored for inte'+
   'rnal)'#010+
   '*L2ap_Use pipes instead of creating temporary assembler files'#010+
-  '**2ar_List register allocation/release info in assembler file'#010+
-  '**2at_List temp allocation/release in','fo in assembler file'#010+
+  '**2ar_List register allocation/release in','fo in assembler file'#010+
+  '**2at_List temp allocation/release info in assembler file'#010+
   '**1A<x>_Output format:'#010+
   '**2Adefault_Use default assembler'#010+
   '3*2Aas_Assemble using GNU AS'#010+
   '3*2Amacho_Mach-O (Darwin, Intel 32 bit) using internal writer'#010+
-  '8*2Anasm_Assemble using Nasm'#010+
+  '8*2Anasm_Asse','mble using Nasm'#010+
   '8*2Anasmobj_Assemble using Nasm'#010+
-  '3*2Anasm_A','ssemble using Nasm'#010+
+  '3*2Anasm_Assemble using Nasm'#010+
   '3*2Anasmcoff_COFF (Go32v2) file using Nasm'#010+
   '3*2Anasmelf_ELF32 (Linux) file using Nasm'#010+
   '3*2Anasmwin32_Win32 object file using Nasm'#010+
-  '3*2Anasmwdosx_Win32/WDOSX object file using Nasm'#010+
-  '3*2Anasmdarwin_macho32 object file using Nas','m (experimental)'#010+
+  '3*2Anasmwdosx_Win32/WDOSX object fi','le using Nasm'#010+
+  '3*2Anasmdarwin_macho32 object file using Nasm (experimental)'#010+
   '3*2Awasm_Obj file using Wasm (Watcom)'#010+
   '3*2Anasmobj_Obj file using Nasm'#010+
   '3*2Amasm_Obj file using Masm (Microsoft)'#010+
   '3*2Atasm_Obj file using Tasm (Borland)'#010+
-  '3*2Aelf_ELF (Linux) using internal writer'#010+
-  '3*2Acoff_COFF (Go32v2) using in','ternal writer'#010+
+  '3*2Aelf_ELF (Li','nux) using internal writer'#010+
+  '3*2Acoff_COFF (Go32v2) using internal writer'#010+
   '3*2Apecoff_PE-COFF (Win32) using internal writer'#010+
   '3*2Ayasm_Assemble using Yasm (experimental)'#010+
   '4*2Aas_Assemble using GNU AS'#010+
   '4*2Agas_Assemble using GNU GAS'#010+
-  '4*2Agas-darwin_Assemble darwin Mach-O64 using GNU GAS'#010+
-  '4*2Amasm_Win64 obje','ct file using ml64 (Microsoft)'#010+
+  '4*2Agas-darwin_','Assemble darwin Mach-O64 using GNU GAS'#010+
+  '4*2Amasm_Win64 object file using ml64 (Microsoft)'#010+
   '4*2Apecoff_PE-COFF (Win64) using internal writer'#010+
   '4*2Aelf_ELF (Linux-64bit) using internal writer'#010+
   '4*2Ayasm_Assemble using Yasm (experimental)'#010+
-  '4*2Anasm_Assemble using Nasm (experimental)'#010+
-  '4*2Anasmwin64_Assemble W','in64 object file using Nasm (experimental)'#010+
+  '4*2Anasm_A','ssemble using Nasm (experimental)'#010+
+  '4*2Anasmwin64_Assemble Win64 object file using Nasm (experimental)'#010+
   '4*2Anasmelf_Assemble Linux-64bit object file using Nasm (experimental)'+
   #010+
-  '4*2Anasmdarwin_Assemble darwin macho64 object file using Nasm (experim'+
-  'ental)'#010+
+  '4*2Anasmdarwin_Assemble darwin macho64 object file using Nasm (exper','i'+
+  'mental)'#010+
   '6*2Aas_Unix o-file using GNU AS'#010+
-  '6*2Agas_GNU Motor','ola assembler'#010+
+  '6*2Agas_GNU Motorola assembler'#010+
   '6*2Amit_MIT Syntax (old GAS)'#010+
   '6*2Amot_Standard Motorola assembler'#010+
   'A*2Aas_Assemble using GNU AS'#010+
   'P*2Aas_Assemble using GNU AS'#010+
   'S*2Aas_Assemble using GNU AS'#010+
-  '**1b_Generate browser info'#010+
+  '**1b_Generate br','owser info'#010+
   '**2bl_Generate local symbol info'#010+
-  '**1B_Build all',' modules'#010+
+  '**1B_Build all modules'#010+
   '**1C<x>_Code generation options:'#010+
   '**2C3_Turn on ieee error checking for constants'#010+
   '**2Ca<x>_Select ABI; see fpc -i or fpc -ia for possible values'#010+
-  '**2Cb_Generate code for a big-endian variant of the target architectur'+
-  'e'#010+
-  '**2Cc<x>_Set de','fault calling convention to <x>'#010+
+  '**2Cb_Generate code for a big','-endian variant of the target architect'+
+  'ure'#010+
+  '**2Cc<x>_Set default calling convention to <x>'#010+
   '**2CD_Create also dynamic library (not supported)'#010+
   '**2Ce_Compilation with emulated floating point opcodes'#010+
-  '**2Cf<x>_Select fpu instruction set to use; see fpc -i or fpc -if for '+
-  'possible values'#010+
-  '**2CF<x>_Minimal ','floating point constant precision (default, 32, 64)'+
-  #010+
+  '**2Cf<x>_Select fpu instruction set to use; s','ee fpc -i or fpc -if fo'+
+  'r possible values'#010+
+  '**2CF<x>_Minimal floating point constant precision (default, 32, 64)'#010+
   '**2Cg_Generate PIC code'#010+
   '**2Ch<n>[,m]_<n> bytes min heap size (between 1023 and 67107840) and o'+
   'ptionally [m] max heap size'#010+
-  '**2Ci_IO-checking'#010+
-  'A*2CI<x>_Select instruction set on ARM: ARM or T','HUMB'#010+
+  '**2Ci_IO','-checking'#010+
+  'A*2CI<x>_Select instruction set on ARM: ARM or THUMB'#010+
   '**2Cn_Omit linking stage'#010+
   'P*2CN_Generate nil-pointer checks (AIX-only)'#010+
   '**2Co_Check overflow of integer operations'#010+
   '**2CO_Check for possible overflow of integer operations'#010+
-  '**2Cp<x>_Select instruction set; see fpc -i or fpc -ic for possibl','e '+
+  '**2Cp<x>','_Select instruction set; see fpc -i or fpc -ic for possible '+
   'values'#010+
   '**2CP<x>=<y>_ packing settings'#010+
   '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or DEFAULT or NORMAL, 2, 4 '+
   'and 8'#010+
-  '**3CPPACKENUM=<y>_ <y> enum packing: 0, 1, 2 and 4 or DEFAULT or NORMA'+
-  'L'#010+
-  '**3CPPACKRECORD=<y>_ <y> record packing: 0 or DEFAUL','T or NORMAL, 1, '+
-  '2, 4, 8, 16 and 32'#010+
+  '**3CPPACKENUM=<y>_ <y> enum packing: 0, 1, 2 and 4 or DEFAULT or N','OR'+
+  'MAL'#010+
+  '**3CPPACKRECORD=<y>_ <y> record packing: 0 or DEFAULT or NORMAL, 1, 2,'+
+  ' 4, 8, 16 and 32'#010+
   '**2Cr_Range checking'#010+
   '**2CR_Verify object method call validity'#010+
   '**2Cs<n>_Set stack checking size to <n>'#010+
-  '**2Ct_Stack checking (for testing only, see manual)'#010+
+  '**2Ct_Stack checking (for testing only, see m','anual)'#010+
   '8*2CT<x>_Target-specific code generation options'#010+
-  '3*','2CT<x>_Target-specific code generation options'#010+
+  '3*2CT<x>_Target-specific code generation options'#010+
   '4*2CT<x>_Target-specific code generation options'#010+
   'p*2CT<x>_Target-specific code generation options'#010+
-  'P*2CT<x>_Target-specific code generation options'#010+
-  'J*2CT<x>_Target-specific code generation optio','ns'#010+
+  'P*2CT<x>_Target-specific code generat','ion options'#010+
+  'J*2CT<x>_Target-specific code generation options'#010+
   'A*2CT<x>_Target-specific code generation options'#010+
   'p*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
   ' (AIX)'#010+
-  'P*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
-  ' (AIX)'#010+
-  'J*3CTautogetterprefix=X_  Automati','cally create getters for propertie'+
-  's with prefix X (empty string disables)'#010+
+  'P*3CTsmalltoc_ Generate smaller TOCs at the expense o','f execution spe'+
+  'ed (AIX)'#010+
+  'J*3CTautogetterprefix=X_  Automatically create getters for properties '+
+  'with prefix X (empty string disables)'#010+
   'J*3CTautosetterprefix=X_  Automatically create setters for properties '+
-  'with prefix X (empty string disables)'#010+
-  '8*3CTcld_                 Emit a CLD instruction before us','ing the x8'+
-  '6 string instructions'#010+
+  'with prefix X (empty string disables)'#010,
+  '8*3CTcld_                 Emit a CLD instruction before using the x86 '+
+  'string instructions'#010+
   '3*3CTcld_                 Emit a CLD instruction before using the x86 '+
   'string instructions'#010+
-  '4*3CTcld_                 Emit a CLD instruction before using the x86 '+
-  'string instructions'#010+
-  '8*3CTfarprocspushoddbp_     ','  Increment BP before pushing it in the '+
-  'prologue of far functions'#010+
+  '4*3CTcld_                 Emit a CLD instruction before usin','g the x8'+
+  '6 string instructions'#010+
+  '8*3CTfarprocspushoddbp_       Increment BP before pushing it in the pr'+
+  'ologue of far functions'#010+
   'J*3CTcompactintarrayinit_ Generate smaller (but potentially slower) co'+
   'de for initializing integer array constants'#010+
-  'J*3CTenumfieldinit_       Initialize enumeration fields in c','onstruct'+
+  'J*','3CTenumfieldinit_       Initialize enumeration fields in construct'+
   'ors to enumtype(0), after calling inherited constructors'#010+
   'J*3CTinitlocals_          Initialize local variables that trigger a JV'+
-  'M bytecode verification error if used uninitialized (slows down code)'#010+
-  'J*3CTlowercaseprocstart_  Lowercase',' the first character of procedure'+
-  '/function/method names'#010+
+  'M bytecode verification error if used uninitial','ized (slows down code'+
+  ')'#010+
+  'J*3CTlowercaseprocstart_  Lowercase the first character of procedure/f'+
+  'unction/method names'#010+
   'A*3CTthumbinterworking_ Generate Thumb interworking-safe code if possi'+
   'ble'#010+
   'J*2Cv_Var/out parameter copy-out checking'#010+
-  '**2CX_Create also smartlinked library'#010+
-  '**1d<x>_Defines the symbol <x>',#010+
+  '**2CX_Crea','te also smartlinked library'#010+
+  '**1d<x>_Defines the symbol <x>'#010+
   '**1D_Generate a DEF file'#010+
   '**2Dd<x>_Set description to <x>'#010+
   '**2Dv<x>_Set DLL version to <x>'#010+
@@ -1526,148 +1525,148 @@
   '**1e<x>_Set path to executable'#010+
   '**1E_Same as -Cn'#010+
   '**1fPIC_Same as -Cg'#010+
-  '**1F<x>_Set file names and paths:'#010+
-  '**2Fa<x>[,y]_(for a program',') load units <x> and [y] before uses is p'+
-  'arsed'#010+
+  '**1','F<x>_Set file names and paths:'#010+
+  '**2Fa<x>[,y]_(for a program) load units <x> and [y] before uses is par'+
+  'sed'#010+
   '**2Fc<x>_Set input codepage to <x>'#010+
   '**2FC<x>_Set RC compiler binary name to <x>'#010+
   '**2Fd_Disable the compiler'#039's internal directory cache'#010+
-  '**2FD<x>_Set the directory where to search for compiler util','ities'#010+
+  '**','2FD<x>_Set the directory where to search for compiler utilities'#010+
   '**2Fe<x>_Redirect error output to <x>'#010+
   '**2Ff<x>_Add <x> to framework path (Darwin only)'#010+
   '**2FE<x>_Set exe/unit output path to <x>'#010+
   '**2Fi<x>_Add <x> to include path'#010+
-  '**2Fl<x>_Add <x> to library path'#010+
+  '**2Fl<x>_Add <x','> to library path'#010+
   '**2FL<x>_Use <x> as dynamic linker'#010+
-  '**2Fm','<x>_Load unicode conversion table from <x>.txt in the compiler '+
-  'dir'#010+
+  '**2Fm<x>_Load unicode conversion table from <x>.txt in the compiler di'+
+  'r'#010+
   '**2FM<x>_Set the directory where to search for unicode binary files'#010+
   '**2Fo<x>_Add <x> to object path'#010+
-  '**2Fr<x>_Load error message file <x>'#010+
-  '**2FR<x>_Set resource (.res) linker ','to <x>'#010+
+  '**2Fr<x>_Load e','rror message file <x>'#010+
+  '**2FR<x>_Set resource (.res) linker to <x>'#010+
   '**2Fu<x>_Add <x> to unit path'#010+
   '**2FU<x>_Set unit output path to <x>, overrides -FE'#010+
   '**2FW<x>_Store generated whole-program optimization feedback in <x>'#010+
-  '**2Fw<x>_Load previously stored whole-program optimization feedback fr'+
-  'om <x>'#010+
-  '*g1g_G','enerate debug information (default format for target)'#010+
+  '**2Fw<x>_Load previously ','stored whole-program optimization feedback '+
+  'from <x>'#010+
+  '*g1g_Generate debug information (default format for target)'#010+
   '*g2gc_Generate checks for pointers (experimental, only available on so'+
   'me targets, might generate false positive)'#010+
-  '*g2gh_Use heaptrace unit (for memory leak/corruption debugging)'#010+
-  '*g2gl_Use',' line info unit (show more info with backtraces)'#010+
+  '*g2gh_Use heapt','race unit (for memory leak/corruption debugging)'#010+
+  '*g2gl_Use line info unit (show more info with backtraces)'#010+
   '*g2go<x>_Set debug information options'#010+
   '*g3godwarfsets_ Enable DWARF '#039'set'#039' type debug information (bre'+
   'aks gdb < 6.5)'#010+
-  '*g3gostabsabsincludes_ Store absolute/full include file paths in Stabs'+
-  #010+
-  '*g3g','odwarfmethodclassprefix_ Prefix method names in DWARF with class'+
-  ' name'#010+
+  '*g3gostabsabsincl','udes_ Store absolute/full include file paths in Sta'+
+  'bs'#010+
+  '*g3godwarfmethodclassprefix_ Prefix method names in DWARF with class n'+
+  'ame'#010+
   '*g3godwarfcpp_ Simulate C++ debug information in DWARF'#010+
   '*g2gp_Preserve case in stabs symbol names'#010+
-  '*g2gs_Generate Stabs debug information'#010+
-  '*g2gt_Trash local variables (to de','tect uninitialized uses; multiple '+
-  #039't'#039' changes the trashing value)'#010+
+  '*g2gs_Generate ','Stabs debug information'#010+
+  '*g2gt_Trash local variables (to detect uninitialized uses; multiple '#039+
+  't'#039' changes the trashing value)'#010+
   '*g2gv_Generates programs traceable with Valgrind'#010+
   '*g2gw_Generate DWARFv2 debug information (same as -gw2)'#010+
-  '*g2gw2_Generate DWARFv2 debug information'#010+
-  '*g2gw3_Generate DWARFv3 deb','ug information'#010+
+  '*g2gw2_Gene','rate DWARFv2 debug information'#010+
+  '*g2gw3_Generate DWARFv3 debug information'#010+
   '*g2gw4_Generate DWARFv4 debug information (experimental)'#010+
   '**1i_Information'#010+
   '**2iD_Return compiler date'#010+
   '**2iSO_Return compiler OS'#010+
   '**2iSP_Return compiler host processor'#010+
-  '**2iTO_Return target OS'#010+
+  '**','2iTO_Return target OS'#010+
   '**2iTP_Return target processor'#010+
-  '**2iV','_Return short compiler version'#010+
+  '**2iV_Return short compiler version'#010+
   '**2iW_Return full compiler version'#010+
   '**2ia_Return list of supported ABI targets'#010+
   '**2ic_Return list of supported CPU instruction sets'#010+
-  '**2if_Return list of supported FPU instruction sets'#010+
-  '**2ii_Return list of suppor','ted inline assembler modes'#010+
+  '**2if_Return list of ','supported FPU instruction sets'#010+
+  '**2ii_Return list of supported inline assembler modes'#010+
   '**2io_Return list of supported optimizations'#010+
   '**2ir_Return list of recognized compiler and RTL features'#010+
   '**2it_Return list of supported targets'#010+
-  '**2iu_Return list of supported microcontroller types'#010+
-  '**2iw_Return list ','of supported whole program optimizations'#010+
+  '**2iu_Return ','list of supported microcontroller types'#010+
+  '**2iw_Return list of supported whole program optimizations'#010+
   '**1I<x>_Add <x> to include path'#010+
   '**1k<x>_Pass <x> to the linker'#010+
   '**1l_Write logo'#010+
   '**1M<x>_Set language mode to <x>'#010+
-  '**2Mfpc_Free Pascal dialect (default)'#010+
+  '**2Mfpc_Free Pascal dialect (','default)'#010+
   '**2Mobjfpc_FPC mode with Object Pascal support'#010+
-  '**','2Mdelphi_Delphi 7 compatibility mode'#010+
+  '**2Mdelphi_Delphi 7 compatibility mode'#010+
   '**2Mtp_TP/BP 7.0 compatibility mode'#010+
   '**2Mmacpas_Macintosh Pascal dialects compatibility mode'#010+
   '**2Miso_ISO 7185 mode'#010+
-  '**2Mextendedpascal_ISO 10206 mode'#010+
-  '**2Mdelphiunicode_Delphi 2009 and later compatibility m','ode'#010+
+  '**2Mextendedpascal_ISO 10206 mo','de'#010+
+  '**2Mdelphiunicode_Delphi 2009 and later compatibility mode'#010+
   '**1n_Do not read the default config files'#010+
   '**1o<x>_Change the name of the executable produced to <x>'#010+
   '**1O<x>_Optimizations:'#010+
   '**2O-_Disable optimizations'#010+
-  '**2O1_Level 1 optimizations (quick and debugger friendly)'#010+
-  '**2O2_Level 2 optimizations',' (-O1 + quick optimizations)'#010+
+  '**2O1_Level 1 optimizations',' (quick and debugger friendly)'#010+
+  '**2O2_Level 2 optimizations (-O1 + quick optimizations)'#010+
   '**2O3_Level 3 optimizations (-O2 + slow optimizations)'#010+
   '**2O4_Level 4 optimizations (-O3 + optimizations which might have unex'+
   'pected side effects)'#010+
-  '**2Oa<x>=<y>_Set alignment'#010+
-  '**2Oo[NO]<x>_Enable or disable optimiz','ations; see fpc -i or fpc -io '+
-  'for possible values'#010+
+  '**2Oa<x','>=<y>_Set alignment'#010+
+  '**2Oo[NO]<x>_Enable or disable optimizations; see fpc -i or fpc -io fo'+
+  'r possible values'#010+
   '**2Op<x>_Set target cpu for optimizing; see fpc -i or fpc -ic for poss'+
   'ible values'#010+
-  '**2OW<x>_Generate whole-program optimization feedback for optimization'+
-  ' <x>; see fpc -i or fpc -iw for possib','le values'#010+
+  '**2OW<x>_Generate whole-program optimization feedb','ack for optimizati'+
+  'on <x>; see fpc -i or fpc -iw for possible values'#010+
   '**2Ow<x>_Perform whole-program optimization <x>; see fpc -i or fpc -iw'+
   ' for possible values'#010+
   '**2Os_Optimize for size rather than speed'#010+
-  '**1pg_Generate profile code for gprof (defines FPC_PROFILE)'#010+
-  'F*1P<x>_Target CPU / compiler related',' options:'#010+
+  '**1pg_Generate profile code for gprof (','defines FPC_PROFILE)'#010+
+  'F*1P<x>_Target CPU / compiler related options:'#010+
   'F*2PB_Show default compiler binary'#010+
   'F*2PP_Show default target cpu'#010+
   'F*2P<x>_Set target CPU (aarch64,arm,avr,i386,i8086,jvm,m68k,mips,mipse'+
   'l,powerpc,powerpc64,sparc,x86_64)'#010+
-  '**1R<x>_Assembler reading style:'#010+
-  '**2Rdefault_Use default asse','mbler for target'#010+
+  '**1','R<x>_Assembler reading style:'#010+
+  '**2Rdefault_Use default assembler for target'#010+
   '3*2Ratt_Read AT&T style assembler'#010+
   '3*2Rintel_Read Intel style assembler'#010+
   '4*2Ratt_Read AT&T style assembler'#010+
   '4*2Rintel_Read Intel style assembler'#010+
-  '8*2Ratt_Read AT&T style assembler'#010+
+  '8*2Ratt_Read AT&T style',' assembler'#010+
   '8*2Rintel_Read Intel style assembler'#010+
-  '6*2RMOT_Re','ad Motorola style assembler'#010+
+  '6*2RMOT_Read Motorola style assembler'#010+
   '**1S<x>_Syntax options:'#010+
   '**2S2_Same as -Mobjfpc'#010+
   '**2Sc_Support operators like C (*=,+=,/= and -=)'#010+
   '**2Sa_Turn on assertions'#010+
   '**2Sd_Same as -Mdelphi'#010+
-  '**2Se<x>_Error options. <x> is a combination of the following:'#010+
-  '**3*_','<n> : Compiler halts after the <n> errors (default is 1)'#010+
+  '**2Se<x>_E','rror options. <x> is a combination of the following:'#010+
+  '**3*_<n> : Compiler halts after the <n> errors (default is 1)'#010+
   '**3*_w : Compiler also halts after warnings'#010+
   '**3*_n : Compiler also halts after notes'#010+
-  '**3*_h : Compiler also halts after hints'#010+
-  '**2Sf_Enable certain features in compiler and RTL; see fp','c -i or fpc'+
-  ' -ir for possible values)'#010+
+  '**3*_h : Compiler also halts after hints',#010+
+  '**2Sf_Enable certain features in compiler and RTL; see fpc -i or fpc -'+
+  'ir for possible values)'#010+
   '**2Sg_Enable LABEL and GOTO (default in -Mtp and -Mdelphi)'#010+
   '**2Sh_Use reference counted strings (ansistring by default) instead of'+
   ' shortstrings'#010+
-  '**2Si_Turn on inlining of procedures/functions declared as "','inline"'#010+
+  '**','2Si_Turn on inlining of procedures/functions declared as "inline"'#010+
   '**2Sj_Allows typed constants to be writeable (default in all modes)'#010+
   '**2Sk_Load fpcylix unit'#010+
   '**2SI<x>_Set interface style to <x>'#010+
   '**3SIcom_COM compatible interface (default)'#010+
-  '**3SIcorba_CORBA compatible interface'#010+
-  '**2Sm_Support macros l','ike C (global)'#010+
+  '**','3SIcorba_CORBA compatible interface'#010+
+  '**2Sm_Support macros like C (global)'#010+
   '**2So_Same as -Mtp'#010+
   '**2Sr_Transparent file names in ISO mode'#010+
   '**2Ss_Constructor name must be init (destructor must be done)'#010+
-  '**2Sv_Support vector processing (use CPU vector extensions if availabl'+
-  'e)'#010+
-  '**2Sx_Enable exception keyword','s (default in Delphi/ObjFPC modes)'#010+
+  '**2Sv_Support vector processing (use CPU vect','or extensions if availa'+
+  'ble)'#010+
+  '**2Sx_Enable exception keywords (default in Delphi/ObjFPC modes)'#010+
   '**2Sy_@<pointer> returns a typed pointer, same as $T+'#010+
   '**1s_Do not call assembler and linker'#010+
   '**2sh_Generate script to link on host'#010+
-  '**2st_Generate script to link on target'#010+
-  '**2sr_Skip register allocation phas','e (use with -alr)'#010+
+  '**2st_Generate sc','ript to link on target'#010+
+  '**2sr_Skip register allocation phase (use with -alr)'#010+
   '**1T<x>_Target operating system:'#010+
   '3*2Tandroid_Android'#010+
   '3*2Taros_AROS'#010+
@@ -1674,25 +1673,25 @@
   '3*2Tbeos_BeOS'#010+
   '3*2Tdarwin_Darwin/Mac OS X'#010+
   '3*2Tembedded_Embedded'#010+
-  '3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+
+  '3*2Temx_OS/2 via EMX (including EM','X/RSX extender)'#010+
   '3*2Tfreebsd_FreeBSD'#010+
-  '3*2Tgo32v2_Version 2 o','f DJ Delorie DOS extender'#010+
+  '3*2Tgo32v2_Version 2 of DJ Delorie DOS extender'#010+
   '3*2Thaiku_Haiku'#010+
   '3*2Tiphonesim_iPhoneSimulator from iOS SDK 3.2+ (older versions: -Tdar'+
   'win)'#010+
   '3*2Tlinux_Linux'#010+
   '3*2Tnativent_Native NT API (experimental)'#010+
-  '3*2Tnetbsd_NetBSD'#010+
+  '3*2Tnet','bsd_NetBSD'#010+
   '3*2Tnetware_Novell Netware Module (clib)'#010+
-  '3*2Tne','twlibc_Novell Netware Module (libc)'#010+
+  '3*2Tnetwlibc_Novell Netware Module (libc)'#010+
   '3*2Topenbsd_OpenBSD'#010+
   '3*2Tos2_OS/2 / eComStation'#010+
   '3*2Tsymbian_Symbian OS'#010+
   '3*2Tsolaris_Solaris'#010+
   '3*2Twatcom_Watcom compatible DOS extender'#010+
-  '3*2Twdosx_WDOSX DOS extender'#010+
+  '3*2Twdosx_WDOS','X DOS extender'#010+
   '3*2Twin32_Windows 32 Bit'#010+
-  '3*2Twince_Windows ','CE'#010+
+  '3*2Twince_Windows CE'#010+
   '4*2Taros_AROS'#010+
   '4*2Tdarwin_Darwin/Mac OS X'#010+
   '4*2Tdragonfly_DragonFly BSD'#010+
@@ -1701,9 +1700,9 @@
   '4*2Tiphonesim_iPhoneSimulator'#010+
   '4*2Tlinux_Linux'#010+
   '4*2Tnetbsd_NetBSD'#010+
-  '4*2Topenbsd_OpenBSD'#010+
+  '4*2T','openbsd_OpenBSD'#010+
   '4*2Tsolaris_Solaris'#010+
-  '4*2Twin64_Win64 (64 bi','t Windows systems)'#010+
+  '4*2Twin64_Win64 (64 bit Windows systems)'#010+
   '6*2Tamiga_Commodore Amiga'#010+
   '6*2Tatari_Atari ST/STe/TT'#010+
   '6*2Tembedded_Embedded'#010+
@@ -1711,9 +1710,9 @@
   '6*2Tnetbsd_NetBSD'#010+
   '6*2Tmacos_Mac OS'#010+
   '6*2Tpalmos_PalmOS'#010+
-  '8*2Tembedded_Embedded'#010+
+  '8*2Tembedded_Embedde','d'#010+
   '8*2Tmsdos_MS-DOS (and compatible)'#010+
-  '8*2Twin16_Windows 16 B','it'#010+
+  '8*2Twin16_Windows 16 Bit'#010+
   'A*2Tandroid_Android'#010+
   'A*2Taros_AROS'#010+
   'A*2Tdarwin_Darwin/iPhoneOS/iOS'#010+
@@ -1722,10 +1721,10 @@
   'A*2Tlinux_Linux'#010+
   'A*2Tnds_Nintendo DS'#010+
   'A*2Tnetbsd_NetBSD'#010+
-  'A*2Tpalmos_PalmOS'#010+
+  'A*2Tpalmos_Pa','lmOS'#010+
   'A*2Tsymbian_Symbian'#010+
   'A*2Twince_Windows CE'#010+
-  'a*2Tdarwin_D','arwin/iOS'#010+
+  'a*2Tdarwin_Darwin/iOS'#010+
   'a*2Tlinux_Linux'#010+
   'J*2Tandroid_Android'#010+
   'J*2Tjava_Java'#010+
@@ -1735,10 +1734,10 @@
   'M*2Tembedded_Embedded'#010+
   'M*2Tlinux_Linux'#010+
   'P*2Taix_AIX'#010+
-  'P*2Tamiga_AmigaOS'#010+
+  'P*2Tamiga_Amig','aOS'#010+
   'P*2Tdarwin_Darwin/Mac OS X'#010+
   'P*2Tembedded_Embedded'#010+
-  'P*2Tl','inux_Linux'#010+
+  'P*2Tlinux_Linux'#010+
   'P*2Tmacos_Mac OS (classic)'#010+
   'P*2Tmorphos_MorphOS'#010+
   'P*2Tnetbsd_NetBSD'#010+
@@ -1748,148 +1747,147 @@
   'p*2Tembedded_Embedded'#010+
   'p*2Tlinux_Linux'#010+
   'S*2Tlinux_Linux'#010+
-  'S*2Tsolaris_Solaris'#010+
+  'S','*2Tsolaris_Solaris'#010+
   's*2Tlinux_Linux'#010+
   'V*2Tembedded_Embedded'#010+
-  '*','*1u<x>_Undefines the symbol <x>'#010+
+  '**1u<x>_Undefines the symbol <x>'#010+
   '**1U_Unit options:'#010+
   '**2Un_Do not check where the unit name matches the file name'#010+
   '**2Ur_Generate release unit files (never automatically recompiled)'#010+
-  '**2Us_Compile a system unit'#010+
-  '**1v<x>_Be verbose. <x> is a comb','ination of the following letters:'#010+
+  '**2','Us_Compile a system unit'#010+
+  '**1v<x>_Be verbose. <x> is a combination of the following letters:'#010+
   '**2*_e : Show errors (default)       0 : Show nothing (except errors)'#010+
   '**2*_w : Show warnings               u : Show unit info'#010+
-  '**2*_n : Show notes                  t : Show tried/used files'#010+
-  '**2*_h : Show hin','ts                  c : Show conditionals'#010+
+  '**2*_n : Show notes   ','               t : Show tried/used files'#010+
+  '**2*_h : Show hints                  c : Show conditionals'#010+
   '**2*_i : Show general info           d : Show debug info'#010+
   '**2*_l : Show linenumbers            r : Rhide/GCC compatibility mode'#010+
-  '**2*_s : Show time stamps            q : Show message numbers'#010+
-  '**2*_a : ','Show everything             x : Show info about invoked too'+
-  'ls'#010+
+  '**2*_s : Show',' time stamps            q : Show message numbers'#010+
+  '**2*_a : Show everything             x : Show info about invoked tools'+
+  #010+
   '**2*_b : Write file names messages   p : Write tree.log with parse tre'+
   'e'#010+
-  '**2*_    with full path              v : Write fpcdebug.txt with'#010+
-  '**2*_z : Write output to stderr          ','lots of debugging info'#010+
+  '**2*_    with full path              v : Write f','pcdebug.txt with'#010+
+  '**2*_z : Write output to stderr          lots of debugging info'#010+
   '**2*_m<x>,<y> : Do not show messages numbered <x> and <y>'#010+
   'F*1V<x>_Append '#039'-<x>'#039' to the used compiler binary name (e.g. f'+
   'or version)'#010+
-  '**1W<x>_Target-specific options (targets)'#010+
-  '3*2WA_Specify native type application (Wind','ows)'#010+
+  '**1W<x>_Target-specific opt','ions (targets)'#010+
+  '3*2WA_Specify native type application (Windows)'#010+
   '4*2WA_Specify native type application (Windows)'#010+
   'A*2WA_Specify native type application (Windows)'#010+
   '3*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  'P*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  'p*2Wb_Create a bundle instead of a ','library (Darwin)'#010+
+  'P*2Wb_Create a bundle instead',' of a library (Darwin)'#010+
+  'p*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'a*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'A*2Wb_Create a bundle instead of a library (Darwin)'#010+
   '4*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  '3*2WB_Create a relocatable image (Windows, Symbian)'#010+
-  '3*2WB<x>_Set im','age base to <x> (Windows, Symbian)'#010+
+  '3*2WB_Cre','ate a relocatable image (Windows, Symbian)'#010+
+  '3*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
   '4*2WB_Create a relocatable image (Windows)'#010+
   '4*2WB<x>_Set image base to <x> (Windows)'#010+
   'A*2WB_Create a relocatable image (Windows, Symbian)'#010+
-  'A*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
-  '3*2WC_Specify conso','le type application (EMX, OS/2, Windows)'#010+
+  'A*2WB<x>_Se','t image base to <x> (Windows, Symbian)'#010+
+  '3*2WC_Specify console type application (EMX, OS/2, Windows)'#010+
   '4*2WC_Specify console type application (Windows)'#010+
   'A*2WC_Specify console type application (Windows)'#010+
-  'P*2WC_Specify console type application (Classic Mac OS)'#010+
-  '3*2WD_Use DEFFILE to export functions of DLL ','or EXE (Windows)'#010+
+  'P*2WC_Specify console type application (Cla','ssic Mac OS)'#010+
+  '3*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   '4*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   'A*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   '3*2We_Use external resources (Darwin)'#010+
-  '4*2We_Use external resources (Darwin)'#010+
-  'a*2We_Use external reso','urces (Darwin)'#010+
+  '4*2','We_Use external resources (Darwin)'#010+
+  'a*2We_Use external resources (Darwin)'#010+
   'A*2We_Use external resources (Darwin)'#010+
   'P*2We_Use external resources (Darwin)'#010+
   'p*2We_Use external resources (Darwin)'#010+
-  '3*2WF_Specify full-screen type application (EMX, OS/2)'#010+
-  '3*2WG_Specify graphic type application (EMX, OS/2, Windo','ws)'#010+
+  '3*2WF_Specify full-screen type application (EMX, OS/2',')'#010+
+  '3*2WG_Specify graphic type application (EMX, OS/2, Windows)'#010+
   '4*2WG_Specify graphic type application (Windows)'#010+
   'A*2WG_Specify graphic type application (Windows)'#010+
   'P*2WG_Specify graphic type application (Classic Mac OS)'#010+
-  '3*2Wi_Use internal resources (Darwin)'#010+
+  '3*2Wi_Use internal resou','rces (Darwin)'#010+
   '4*2Wi_Use internal resources (Darwin)'#010+
-  'a*2Wi_','Use internal resources (Darwin)'#010+
+  'a*2Wi_Use internal resources (Darwin)'#010+
   'A*2Wi_Use internal resources (Darwin)'#010+
   'P*2Wi_Use internal resources (Darwin)'#010+
   'p*2Wi_Use internal resources (Darwin)'#010+
-  '3*2WI_Turn on/off the usage of import sections (Windows)'#010+
-  '4*2WI_Turn on/off the usage of import',' sections (Windows)'#010+
+  '3*2WI_Turn on/off the usage of impor','t sections (Windows)'#010+
+  '4*2WI_Turn on/off the usage of import sections (Windows)'#010+
   'A*2WI_Turn on/off the usage of import sections (Windows)'#010+
   '8*2Wh_Use huge code for units (ignored for models with CODE in a uniqu'+
   'e segment)'#010+
-  '8*2Wm<x>_Set memory model'#010+
+  '8*2Wm<x>_Set memory mode','l'#010+
   '8*3WmTiny_Tiny memory model'#010+
-  '8*3WmSmall_Small memory mode','l (default)'#010+
+  '8*3WmSmall_Small memory model (default)'#010+
   '8*3WmMedium_Medium memory model'#010+
   '8*3WmCompact_Compact memory model'#010+
   '8*3WmLarge_Large memory model'#010+
   '8*3WmHuge_Huge memory model'#010+
-  '3*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
+  '3*2WM<x>_Minimum Mac OS X deployment version: ','10.4, 10.5.1, ... (Dar'+
+  'win)'#010+
+  '4*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   'n)'#010+
-  '4*2WM<x>_Minimum Mac OS X deplo','yment version: 10.4, 10.5.1, ... (Dar'+
-  'win)'#010+
   'p*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   'n)'#010+
-  'P*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
-  'n)'#010+
-  '3*2WN_Do not generate relocation code, needed for de','bugging (Windows'+
-  ')'#010+
+  'P*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Da','r'+
+  'win)'#010+
+  '3*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
   '4*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
   'A*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
-  'A*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
+  'A*2Wp<x>_Specify the con','troller type; see fpc -i or fpc -iu for poss'+
+  'ible values'#010+
+  'm*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'le values'#010+
-  'm*','2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for poss'+
-  'ible values'#010+
   'V*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'le values'#010+
-  '3*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (iphonesim)'#010+
-  '4*2WP<x>_Mini','mum iOS deployment version: 8.0, 8.0.2, ... (iphonesim)'+
+  '3*2WP<x>_Minimum iOS dep','loyment version: 3.0, 5.0.1, ... (iphonesim)'+
   #010+
+  '4*2WP<x>_Minimum iOS deployment version: 8.0, 8.0.2, ... (iphonesim)'#010+
   'a*2WP<x>_Minimum iOS deployment version: 7.0, 7.1.2, ... (Darwin)'#010+
-  'A*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (Darwin)'#010+
+  'A*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (Da','rwin)'#010+
   '3*2WR_Generate relocation code (Windows)'#010+
-  '4*2WR_Gener','ate relocation code (Windows)'#010+
+  '4*2WR_Generate relocation code (Windows)'#010+
   'A*2WR_Generate relocation code (Windows)'#010+
   '8*2Wt<x>_Set the target executable format'#010+
   '8*3Wtexe_Create a DOS .EXE file (default)'#010+
-  '8*3Wtcom_Create a DOS .COM file (requires tiny memory model)'#010+
-  'P*2WT_Specify MPW tool t','ype application (Classic Mac OS)'#010+
+  '8*3Wtcom_Create a DOS .COM ','file (requires tiny memory model)'#010+
+  'P*2WT_Specify MPW tool type application (Classic Mac OS)'#010+
   '**2WX_Enable executable stack (Linux)'#010+
   '**1X_Executable options:'#010+
   '**2X9_Generate linkerscript for GNU Binutils ld older than version 2.1'+
   '9.1 (Linux)'#010+
-  '**2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, Free','BSD, L'+
+  '**2X','c_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, L'+
   'inux)'#010+
   '**2Xd_Do not search default library path (sometimes required for cross'+
   '-compiling when not using -XR)'#010+
   '**2Xe_Use external linker'#010+
-  '**2Xf_Substitute pthread library name for linking (BSD)'#010+
-  '**2Xg_Create debuginfo in a separate file and',' add a debuglink sectio'+
-  'n to executable'#010+
+  '**2Xf_Substitute pthread library name for l','inking (BSD)'#010+
+  '**2Xg_Create debuginfo in a separate file and add a debuglink section '+
+  'to executable'#010+
   '**2XD_Try to link units dynamically      (defines FPC_LINK_DYNAMIC)'#010+
   '**2Xi_Use internal linker'#010+
   '**2XLA_Define library substitutions for linking'#010+
-  '**2XLO_Define order of library linking'#010+
-  '**2XLD_Exclude defau','lt order of standard libraries'#010+
+  '*','*2XLO_Define order of library linking'#010+
+  '**2XLD_Exclude default order of standard libraries'#010+
   '**2Xm_Generate link map'#010+
   '**2XM<x>_Set the name of the '#039'main'#039' program routine (default i'+
   's '#039'main'#039')'#010+
-  '**2Xn_Use target system native linker instead of GNU ld (Solaris, AIX)'+
-  #010+
-  'F*2Xp<x>_First search for the compiler bin','ary in the directory <x>'#010+
+  '**2Xn_Use target system native linker instead of GNU ld',' (Solaris, AI'+
+  'X)'#010+
+  'F*2Xp<x>_First search for the compiler binary in the directory <x>'#010+
   '**2XP<x>_Prepend the binutils names with the prefix <x>'#010+
   '**2Xr<x>_Set the linker'#039's rlink-path to <x> (needed for cross comp'+
-  'ile, see the ld manual for more information) (BeOS, Linux)'#010+
-  '**2XR<x>_Prepend <x> to all linker',' search paths (BeOS, Darwin, FreeB'+
-  'SD, Linux, Mac OS, Solaris)'#010+
+  'ile, see the ld manual for more inf','ormation) (BeOS, Linux)'#010+
+  '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, FreeBSD'+
+  ', Linux, Mac OS, Solaris)'#010+
   '**2Xs_Strip all symbols from executable'#010+
   '**2XS_Try to link units statically (default, defines FPC_LINK_STATIC)'#010+
-  '**2Xt_Link with static libraries (-static is passed to linker)'#010+
-  '**2Xv','_Generate table for Virtual Entry calls'#010+
+  '**2Xt_Link',' with static libraries (-static is passed to linker)'#010+
+  '**2Xv_Generate table for Virtual Entry calls'#010+
   '**2XV_Use VLink as external linker       (default on Amiga, MorphOS)'#010+
   '**2XX_Try to smartlink units             (defines FPC_LINK_SMART)'#010+
   '**1*_'#010+
-  '**1?_Show this help'#010+
+  '*','*1?_Show this help'#010+
   '**1h_Shows this help without waiting'
 );
Index: compiler/ncnv.pas
===================================================================
--- compiler/ncnv.pas	(revision 38690)
+++ compiler/ncnv.pas	(working copy)
@@ -4281,6 +4281,21 @@
                   end;
               end;
           end
+        else if (right.resultdef.typ=enumdef) then
+          begin
+            if (m_fpc in current_settings.modeswitches) and
+               (tenumdef(right.resultdef).has_jumps) then
+              CGMessage(type_e_as_is_enums_with_assign_not_possible);
+            { left must be an ordinal }
+            if not is_ordinal(left.resultdef) then
+              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
+            case nodetype of
+              isn:
+                resultdef:=pasbool8type;
+              asn:
+                resultdef:=right.resultdef;
+            end;
+          end
         else
           CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
       end;
@@ -4309,6 +4324,8 @@
         procname: string;
         statement : tstatementnode;
         tempnode : ttempcreatenode;
+        v,res: Tconstexprint;
+        leftconv: tnode;
       begin
         result:=nil;
         { Passing a class type to an "is" expression cannot result in a class
@@ -4354,6 +4371,35 @@
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef);
           end
+        else if (right.resultdef.typ=enumdef) then
+          begin
+            if left.nodetype=ordconstn then
+              begin
+                v:=Tordconstnode(left).value;
+                res.signed:=false;
+                res.overflow:=false;
+                if v.signed and ((v.svalue<tenumdef(right.resultdef).min) or (v.svalue>tenumdef(right.resultdef).max)) then
+                  res.uvalue:=0 { false }
+                else
+                if not v.signed and ((v.uvalue<tenumdef(right.resultdef).min) or (v.uvalue>tenumdef(right.resultdef).max)) then
+                  res.uvalue:=0 { false }
+                else
+                  res.uvalue:=1; { true }
+                result := cordconstnode.create(res, resultdef, false);
+              end
+            else
+              begin
+                if left.resultdef.typ<>orddef then
+                  leftconv := ctypeconvnode.create_internal(left, s32inttype)
+                else
+                  leftconv := left;
+                result := ccallnode.createinternres('fpc_do_is_enum',
+                  ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
+                    ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
+                      ccallparanode.create(leftconv, nil))),
+                  resultdef);
+              end;
+          end
         else
           begin
             if is_class(left.resultdef) then
@@ -4432,6 +4478,8 @@
     function tasnode.pass_1 : tnode;
       var
         procname: string;
+        leftconv: tnode;
+        v: Tconstexprint;
       begin
         result:=nil;
         { Passing a class type to an "as" expression cannot result in a class
@@ -4450,6 +4498,31 @@
               call := ccallnode.createinternres('fpc_do_as',
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef)
+            else if (right.resultdef.typ=enumdef) then
+              begin
+                if left.nodetype=ordconstn then
+                  begin
+                    v:=Tordconstnode(left).value;
+                    if v.signed and ((v.svalue<tenumdef(right.resultdef).min) or (v.svalue>tenumdef(right.resultdef).max)) then
+                      Message(parser_e_range_check_error)
+                    else
+                    if not v.signed and ((v.uvalue<tenumdef(right.resultdef).min) or (v.uvalue>tenumdef(right.resultdef).max)) then
+                      Message(parser_e_range_check_error);
+                    call := ctypeconvnode.create_internal(left, resultdef);
+                  end
+                else
+                  begin
+                    if left.resultdef.typ<>orddef then
+                      leftconv := ctypeconvnode.create_internal(left, s32inttype)
+                    else
+                      leftconv := left;
+                    call := ccallnode.createinternres('fpc_do_as_enum',
+                      ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
+                        ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
+                          ccallparanode.create(leftconv, nil))),
+                      resultdef)
+                  end;
+              end
             else
               begin
                 if is_class(left.resultdef) then
Index: rtl/inc/compproc.inc
===================================================================
--- rtl/inc/compproc.inc	(revision 38690)
+++ rtl/inc/compproc.inc	(working copy)
@@ -798,6 +798,8 @@
 
 procedure fpc_AbstractErrorIntern;compilerproc;
 procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
+function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
+function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
 
 {$ifdef FPC_HAS_FEATURE_FILEIO}
 Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
Index: rtl/inc/system.inc
===================================================================
--- rtl/inc/system.inc	(revision 38690)
+++ rtl/inc/system.inc	(working copy)
@@ -1528,6 +1528,29 @@
 
 
 {*****************************************************************************
+                       (I as TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
+begin
+  if (value>=minvalue) and (value<=maxvalue) then
+    result:=value
+  else
+    handleerroraddrframeInd(219,get_pc_addr,get_frame);
+end;
+
+
+{*****************************************************************************
+                       (I is TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
+begin
+  result := (value>=minvalue) and (value<=maxvalue);
+end;
+
+
+{*****************************************************************************
                        SetJmp/LongJmp support.
 *****************************************************************************}
 
AS-IS-enum-03.patch (95,365 bytes)

Ondrej Pokorny

2018-04-16 17:01

developer   ~0107821

Thaddy, once again because you seem you cannot read: discuss your opinions and worries on the mailing list - a place where more people have talked about this feature already, including FPC developers. You will reach more audience there. It is a better medium for discussion than issue reports.

AS-IS-enum-03.patch: I disabled the IS/AS operators on assigned enums for the objfpc mode to match the array[enum] behavior and the docs.

Thaddy de Koning

2018-04-16 17:05

reporter   ~0107822

Last edited: 2018-04-16 18:53

View 2 revisions

Ok will test. And by the way this indeed needs more discussion. See my other example. Maybe better to have IS/AS in ObjFpc mode typesafe.

Note you propose a feature that Delphi does not even have...So do it right.

Thaddy de Koning

2018-04-18 14:58

reporter   ~0107844

Last edited: 2018-04-18 14:59

View 2 revisions

Ok. Next test, unacceptable side effects:
program checkEnumAndSets;
{$mode delphi}{$modeswitch typehelpers}{$M+}
type
  TProgrammerType = (tpDelphi =100, tpVisualC=4, tpVB=255, tpClang=101, tpJava=2) ;

   
  function TypeSafeIS(const a:TprogrammerType):Boolean;
  var
    b:Set of TprogrammerType =[];
    c:TProgrammerType;
  begin
    b:= [tpDelphi, tpVisualC, tpVB, tpClang, tpJava];
    Result := a in b;
  end;


var
  i:integer;
  s:Set of TprogrammerType;
begin
  s:=[];
  i := 4;
  writeln(i,' Is valid enum:', i is TProgrammerType, ' Oh, well, let''s include it in the set then...:');
  writeln('Trying to include i');
  Include(s,i as TProgrammerType);
  writeln('Is it in the set:',i as TprogrammerType in s, ' Which "seems to work..Let''s see:' );
  writeln(' Do we really want that? We screwed up set syntax.' );
  for i := 0 to 4 do
    writeln(i:4,TypeSafeIs(i as TprogrammerType):8);
end.

Ondrej Pokorny

2018-04-18 15:06

developer   ~0107845

Thaddy, again - the 3rd time already.
1.) You obviously cannot read. (You should read the Delphi documentation I linked above.)
2.) You obviously cannot read. (Discuss your worries and problems in the mailing list.)

The behavior of AS/IS in your example code is CORRECT.

Thaddy de Koning

2018-04-19 21:47

reporter   ~0107877

Last edited: 2018-04-19 21:49

View 2 revisions

The only code that is correct is my code. And I did read all of it. ALL.
Which means: Delphi takes a shortcut and does not even have as/is for enums AFAIK.
Your code breaks things.(big time).
You can fix that. Then it is a valuable contribution.
- Don't consider it a range, it is not...
- Just elements..
- Make sure it doesn't break set syntax.

Plz make a solid contribution and *think*. I really like the feature.
Hence I am investing so much time in it. But if it breaks - basic pascal set -code as I demonstrated it is useless.
I am trying to help, not obstruct you.

Ondrej Pokorny

2018-04-19 23:41

developer   ~0107881

1.) If you read the mailing-list part, you would have already started a ML thread with your questions.

2.) If you read the Delphi documentation, you would understand what "TProgrammerType = (tpDelphi =100, tpVisualC=4, tpVB=255, tpClang=101, tpJava=2)" means.

You fail at both points.

In your code in 0033603:0107844 you write "unacceptable side effects" but do not describe what these side effects should be in the code. Do you mean the "for i := 0 to 4 do writeln(i:4,TypeSafeIs(i as TprogrammerType):8);" part? Or what?

You obviously do not understand what "TProgrammerType = (tpDelphi =100, tpVisualC=4, tpVB=255, tpClang=101, tpJava=2)" in Delphi means.
In Delphi it means "TProgrammerType=2..255" with 2, 4, 100, 101 and 255 having a name equivalent but all 2..255 elements are valid.

"i as TprogrammerType" succeeds for all i values between 2 and 255. It fails for all others (..., 0, 1, 256, 257, etc). Therefore the first "writeln(i:4,TypeSafeIs(i as TprogrammerType):8);" raises an exception, which is CORRECT.

What should "i as TprogrammerType" for i=0 (i.e. TprogrammerType(0)) return? tpDelphi? No, come on. TProgrammerType is not an "array[0..4] of Integer = (100, 4, 255, 101, 2)". TprogrammerType(0) is invalid and thus the AS operator raises an exception. The same goes for i=4 - it is the tpVisualC value and not tpJava.

The patch doesn't brake any set syntax. You only don't understand what assigned enums are about.

Here is a sample code to demonstrate why my approach is correct. It shows you why 2..255 are valid elements of TProgrammerType. You can run the code both in Delphi and FPC:

program CheckAssignedEnum;

{$IFDEF FPC}
  {$MODE DELPHI}
{$ELSE}
  {$APPTYPE CONSOLE}
{$ENDIF}

type
  TProgrammerType = (tpDelphi=100, tpVisualC=4, tpVB=255, tpClang=101, tpJava=2);

var
  I, L: Integer;
  A: array[TProgrammerType] of Integer;
begin
  Writeln('Low(A) = ', Ord(Low(A)), ' - lowest valid index of array');
  Writeln('High(A) = ', Ord(High(A)), ' - highest valid index of array');
  Writeln('Low(TProgrammerType) = ', Ord(Low(TProgrammerType)), ' - lowest valid element of TProgrammerType');
  Writeln('High(TProgrammerType) = ', Ord(High(TProgrammerType)), ' - highest valid element of TProgrammerType');

  L := 0;
  for I := Low(Integer) to High(Integer) do
  begin
    {$IFDEF FPC}
    if I is TProgrammerType then // FPC with the new IS syntax
    {$ELSE}
    if (I>=Ord(Low(TProgrammerType))) and (I<=Ord(High(TProgrammerType))) then // Delphi doesn't support the IS syntax
    {$ENDIF}
    begin
      A[TProgrammerType(I)] := L;
      Inc(L);
      Writeln('I = ', I, ', A[I] = ', A[TProgrammerType(I)]);
    end;
  end;
  Writeln('End.');
end.

---
A side note: sets only support elements up to 255, enums support any integer value. If you declare "TProgrammerType = (tpDelphi = 256)" you cannot declare set of TProgrammerType any more.

---
A second note: I appreciate any meaningful feedback. But your feedback is rubbish because 1. you don't understand the background 2. you don't understand Delphi basics and 3. you don't even try to think about my explanations and don't want to understand them. It happened already several times you wrote you nonsense comments in my issue reports about how wrong and incorrect my patches were and yet they have been applied to FPC by FPC developers.

Please do not waste my time. If I explain something to you, think about it and try to understand it. You are just trolling and spamming everywhere.

Thaddy de Koning

2018-04-20 20:27

reporter   ~0107887

Last edited: 2018-04-20 20:33

View 3 revisions

1. I read that.
But any meaningful is/as needs to adhere to *actual* members, not a range. Your patch does not.
It can also break code as I demonstrated. I still think it is a really good feature to pursue, but in its current state I can't see any use for it.

The risk of breaking things as side effect is just too big (like 100%)
I am trying to be constructive. You can not simply allow a part of the range that is not part of the enumeration to pass your IS/AS. That is wrong. You need to test for membership. Like I did. I do not know if that is feasable on the compiler level, but I suspect it is.
Plz do not dismiss my comments: they are valid, tested, and come with example code that proves the patch is wrong. But the feature would be nice. And I will keep testing it...And I encourage you to improve on it..

Ondrej Pokorny

2018-04-20 20:42

developer   ~0107888

> But any meaningful is/as needs to adhere to *actual* members, not a range.

Read again and fully 0033603:0107811:

Please take a look into Delphi documentation:
http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Simple_Types_(Delphi)#Enumerated_Types_with_Explicitly_Assigned_Ordinality [^]
Delphi 7 docs: http://docs.embarcadero.com/products/rad_studio/cbuilder6/EN/CB6_ObjPascalLangGuide_EN.pdf [^] see page 5-7 and 5-8

Citation begin:

type Size = (Small = 5, Medium = 10, Large = Small + Medium);

An enumerated type is, in effect, a subrange whose lowest and highest values correspond to the lowest and highest ordinalities of the constants in the declaration. In the previous example, the Size type has 11 possible values whose ordinalities range from 5 to 15. (Hence the type array[Size] of Char represents an array of 11 characters.) Only three of these values have names, but the others are accessible through typecasts and through routines such as Pred, Succ, Inc, and Dec.

Citation end.

---

The range are *actual* members. Just read the documentation!!!!!!!!!!!!!!!!! (It is the block between "Citation begin" and "Citation end" above.)

+++

> The risk of breaking things as side effect is just too big (like 100%)

My patch CANNOT break any code. The syntax is completely new. It CANNOT break anything.

---

I am still waiting that you exactly describe what you think is wrong with the new IS/AS operator in 0033603:0107819.

Thaddy de Koning

2018-04-20 20:54

reporter   ~0107889

Last edited: 2018-04-20 20:59

View 3 revisions

What is wrong is in my last example:
- your IS allows you to introduce a *new* member with AS in the enumeration that has no name, because it *happens* to be in the range.
- A subsequent and often used construct is to declare a *set of enumeration* and that will fail because it has no name.
You really have to test for *membership*, not just test range. Can't you see that? And the computational expense is negligable if the full set is accessible to the compiler. Meaning: use the set of enum to determine membership.
Also: why does my code generate a 107: unknown error....Your code breaks things as it stands.(and I am seriously testing this, because I like the concept)

Ondrej Pokorny

2018-04-20 21:13

developer   ~0107890

> your IS allows you to introduce a *new* member with AS in the enumeration that has no name, because it *happens* to be in the range

Again: this "*new* member" (as you describe it) is a valid enumeration value because it is in the range. I am telling you this in every single reply. Maybe you have a problem with the English language and don't understand me and the Delphi docs?

> Meaning: use the set of enum to determine membership.

Again: you cannot use set of enum to determine membership for enums with highest value higher than 255. Thus this is not a general solution, even if you wanted it so.

Thaddy de Koning

2018-04-21 13:42

reporter   ~0107893

Last edited: 2018-04-21 13:46

View 3 revisions

Yes, you can. I figured out how to do it. (Probably Jonas, Sven and Florian have the same conclusion)
And don't mix up range with enums.
- IS should test for membership of the enum, not the range, and return true or false.
- AS should only work for membership as declared, not for range....
Did you really test my code? I don't think so....Because the breaks are very obvious.
But again: it is a nice feature and I will keep testing any evolutions.

Thaddy de Koning

2018-04-21 21:09

reporter   ~0107899

But I agree the setof is limited to an enum of 256 elements. That's true.

J. Gareth Moreton

2019-07-02 21:41

reporter   ~0117033

These patches, in principle, have my blessing, since it's a nice compromise for the lack of range checks in case blocks where enumerations are concerned.

Apologies for not noticing this earlier and hence bringing it up AGAIN in the development mailing list.

I'll do some preliminary testing.

Ondrej Pokorny

2019-07-02 22:41

developer   ~0117037

Last edited: 2019-07-02 22:46

View 2 revisions

No need to apologize. On the contrary, I am happy you brought this up.

Btw. I should enable AS/IS back for enums with holes even in objfpc because it corresponds with the CASE warning Jonas introduced recently (the warning is available in objfpc mode as well) and it makes perfect sense. Even if Thaddy doesn't agree.

EDIT: actually there is nothing to do: the AS-IS-enum-02.patch does the thing.

https://lists.freepascal.org/pipermail/fpc-devel/2019-May/040868.html

Citation:
> Yet, it still does not answer my question if the holes belong to the
> valid enumeration values from the FPC point-of-view or not.

As far as range checking and undefined behaviour is concerned, they do.
I.e., you won't get undefined behaviour by assigning any value between
low(enum)..high(enum) to them.

J. Gareth Moreton

2019-07-02 22:53

reporter   ~0117040

Updated the patch to work with the current trunk. Notably, I've added "InternalError(2019070201)" to the case block in "compiler/ncnv.pas" at line 4355, because case blocks now need to have a valid branch for all possible inputs, otherwise a compiler warning is thrown.

J. Gareth Moreton

2019-07-02 23:02

reporter  

AS-IS-enum-04.patch (7,725 bytes)
Index: compiler/msg/errore.msg
===================================================================
--- compiler/msg/errore.msg	(revision 42321)
+++ compiler/msg/errore.msg	(working copy)
@@ -2038,6 +2038,7 @@
 % require specialisation for methods or nested subroutines.
 type_e_seg_procvardef_wrong_memory_model=04124_E_Procedure variables in that memory model do not store segment information
 type_w_empty_constant_range_set=04125_W_The first value of a set constructur range is greater then the second value, so the range describes an empty set.
+type_e_as_is_enums_with_assign_not_possible=04126_E_as or is cannot be used on enums with assignments
 % If a set is constructed like this: \var{s:=[9..7];]}, then an empty set is generated. As this is something normally not desired, the compiler warns about it.
 % \end{description}
 #
Index: compiler/ncnv.pas
===================================================================
--- compiler/ncnv.pas	(revision 42321)
+++ compiler/ncnv.pas	(working copy)
@@ -4344,6 +4344,23 @@
                   end;
               end;
           end
+        else if (right.resultdef.typ=enumdef) then
+          begin
+            if (m_fpc in current_settings.modeswitches) and
+               (tenumdef(right.resultdef).has_jumps) then
+              CGMessage(type_e_as_is_enums_with_assign_not_possible);
+            { left must be an ordinal }
+            if not is_ordinal(left.resultdef) then
+              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
+            case nodetype of
+              isn:
+                resultdef:=pasbool8type;
+              asn:
+                resultdef:=right.resultdef;
+              else
+                InternalError(2019070201);
+            end;
+          end
         else
           CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
       end;
@@ -4372,6 +4389,8 @@
         procname: string;
         statement : tstatementnode;
         tempnode : ttempcreatenode;
+        v,res: Tconstexprint;
+        leftconv: tnode;
       begin
         result:=nil;
         { Passing a class type to an "is" expression cannot result in a class
@@ -4417,6 +4436,35 @@
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef);
           end
+        else if (right.resultdef.typ=enumdef) then
+          begin
+            if left.nodetype=ordconstn then
+              begin
+                v:=Tordconstnode(left).value;
+                res.signed:=false;
+                res.overflow:=false;
+                if v.signed and ((v.svalue<tenumdef(right.resultdef).min) or (v.svalue>tenumdef(right.resultdef).max)) then
+                  res.uvalue:=0 { false }
+                else
+                if not v.signed and ((v.uvalue<tenumdef(right.resultdef).min) or (v.uvalue>tenumdef(right.resultdef).max)) then
+                  res.uvalue:=0 { false }
+                else
+                  res.uvalue:=1; { true }
+                result := cordconstnode.create(res, resultdef, false);
+              end
+            else
+              begin
+                if left.resultdef.typ<>orddef then
+                  leftconv := ctypeconvnode.create_internal(left, s32inttype)
+                else
+                  leftconv := left;
+                result := ccallnode.createinternres('fpc_do_is_enum',
+                  ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
+                    ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
+                      ccallparanode.create(leftconv, nil))),
+                  resultdef);
+              end;
+          end
         else
           begin
             if is_class(left.resultdef) then
@@ -4495,6 +4543,8 @@
     function tasnode.pass_1 : tnode;
       var
         procname: string;
+        leftconv: tnode;
+        v: Tconstexprint;
       begin
         result:=nil;
         { Passing a class type to an "as" expression cannot result in a class
@@ -4513,6 +4563,31 @@
               call := ccallnode.createinternres('fpc_do_as',
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef)
+            else if (right.resultdef.typ=enumdef) then
+              begin
+                if left.nodetype=ordconstn then
+                  begin
+                    v:=Tordconstnode(left).value;
+                    if v.signed and ((v.svalue<tenumdef(right.resultdef).min) or (v.svalue>tenumdef(right.resultdef).max)) then
+                      Message(parser_e_range_check_error)
+                    else
+                    if not v.signed and ((v.uvalue<tenumdef(right.resultdef).min) or (v.uvalue>tenumdef(right.resultdef).max)) then
+                      Message(parser_e_range_check_error);
+                    call := ctypeconvnode.create_internal(left, resultdef);
+                  end
+                else
+                  begin
+                    if left.resultdef.typ<>orddef then
+                      leftconv := ctypeconvnode.create_internal(left, s32inttype)
+                    else
+                      leftconv := left;
+                    call := ccallnode.createinternres('fpc_do_as_enum',
+                      ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
+                        ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
+                          ccallparanode.create(leftconv, nil))),
+                      resultdef)
+                  end;
+              end
             else
               begin
                 if is_class(left.resultdef) then
Index: rtl/inc/compproc.inc
===================================================================
--- rtl/inc/compproc.inc	(revision 42321)
+++ rtl/inc/compproc.inc	(working copy)
@@ -794,6 +794,8 @@
 
 procedure fpc_AbstractErrorIntern;compilerproc;
 procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
+function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
+function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
 
 {$ifdef FPC_HAS_FEATURE_FILEIO}
 Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
Index: rtl/inc/system.inc
===================================================================
--- rtl/inc/system.inc	(revision 42321)
+++ rtl/inc/system.inc	(working copy)
@@ -1550,6 +1550,29 @@
 
 
 {*****************************************************************************
+                       (I as TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
+begin
+  if (value>=minvalue) and (value<=maxvalue) then
+    result:=value
+  else
+    handleerroraddrframeInd(219,get_pc_addr,get_frame);
+end;
+
+
+{*****************************************************************************
+                       (I is TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
+begin
+  result := (value>=minvalue) and (value<=maxvalue);
+end;
+
+
+{*****************************************************************************
                        SetJmp/LongJmp support.
 *****************************************************************************}
 
AS-IS-enum-04.patch (7,725 bytes)

J. Gareth Moreton

2019-07-04 09:02

reporter   ~0117056

So I've started working on the patch - initially to program more optimal code for x86 - and found some issues:

- On lines 30, 34 and 38 of ValidEnumIS.lpr, the error "type identifier not allowed here" is raised.
- On line 24 of ValidEnumIS.lpr, the error "as or is cannot be used on enums with assignments" is raised. This is misleading because the line of code is an assignment, and it turns out the error is because the enumeration has gaps in it due to the explicit value of 2 being given to one of the elements (and hence 1 being skipped). Something like "as or is cannot be used with non-contiguous enumerations" is better.

I can understand banning the use of non-contiguous enumerations because of the complex node constructions required to get it working, but it feels arbitrary and incomplete as a feature, so for the time being, I consider the patch to not be ready for merging into the trunk. I will, however, see if I can make the feature complete - if not, then I'll change the error message to my suggestion.

Ondrej Pokorny

2019-07-04 09:10

developer   ~0117057

Last edited: 2019-07-04 09:11

View 2 revisions

See my note 0033603:0117037 above: I introduced banning of "enumeration with gaps" (with "assignments") in the 03.patch mainly because Thaddy was so annoying. The 02.patch doesn't have this limitation. IMO it's better without the limitation.

Ondrej Pokorny

2019-07-04 10:13

developer   ~0117058

Btw. I don't get any "type identifier not allowed here" errors in ValidEnumIS.lpr. Not on line 30, 34 nor 38 - nowhere. On the contrary, the program compiles and runs as expected. Maybe you didn't build FPC?

+ I removed the "enums with holes" limitation in 05.patch

Ondrej Pokorny

2019-07-04 10:15

developer  

AS-IS-enum-05.patch (6,222 bytes)
Index: compiler/ncnv.pas
===================================================================
--- compiler/ncnv.pas	(revision 42322)
+++ compiler/ncnv.pas	(working copy)
@@ -4344,6 +4344,20 @@
                   end;
               end;
           end
+        else if (right.resultdef.typ=enumdef) then
+          begin
+            { left must be an ordinal }
+            if not is_ordinal(left.resultdef) then
+              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
+            case nodetype of
+              isn:
+                resultdef:=pasbool8type;
+              asn:
+                resultdef:=right.resultdef;
+              else
+                InternalError(2019070201);
+            end;
+          end
         else
           CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
       end;
@@ -4372,6 +4386,8 @@
         procname: string;
         statement : tstatementnode;
         tempnode : ttempcreatenode;
+        v,res: Tconstexprint;
+        leftconv: tnode;
       begin
         result:=nil;
         { Passing a class type to an "is" expression cannot result in a class
@@ -4417,6 +4433,32 @@
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef);
           end
+        else if (right.resultdef.typ=enumdef) then
+          begin
+            if left.nodetype=ordconstn then
+              begin
+                v:=Tordconstnode(left).value;
+                res.signed:=false;
+                res.overflow:=false;
+                if (v<tenumdef(right.resultdef).min) or (v>tenumdef(right.resultdef).max) then
+                  res.uvalue:=0 { false }
+                else
+                  res.uvalue:=1; { true }
+                result := cordconstnode.create(res, resultdef, false);
+              end
+            else
+              begin
+                if left.resultdef.typ<>orddef then
+                  leftconv := ctypeconvnode.create_internal(left, s32inttype)
+                else
+                  leftconv := left;
+                result := ccallnode.createinternres('fpc_do_is_enum',
+                  ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
+                    ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
+                      ccallparanode.create(leftconv, nil))),
+                  resultdef);
+              end;
+          end
         else
           begin
             if is_class(left.resultdef) then
@@ -4495,6 +4537,8 @@
     function tasnode.pass_1 : tnode;
       var
         procname: string;
+        leftconv: tnode;
+        v: Tconstexprint;
       begin
         result:=nil;
         { Passing a class type to an "as" expression cannot result in a class
@@ -4513,6 +4557,28 @@
               call := ccallnode.createinternres('fpc_do_as',
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef)
+            else if (right.resultdef.typ=enumdef) then
+              begin
+                if left.nodetype=ordconstn then
+                  begin
+                    v:=Tordconstnode(left).value;
+                    if (v<tenumdef(right.resultdef).min) or (v>tenumdef(right.resultdef).max) then
+                      Message(parser_e_range_check_error);
+                    call := ctypeconvnode.create_internal(left, resultdef);
+                  end
+                else
+                  begin
+                    if left.resultdef.typ<>orddef then
+                      leftconv := ctypeconvnode.create_internal(left, s32inttype)
+                    else
+                      leftconv := left;
+                    call := ccallnode.createinternres('fpc_do_as_enum',
+                      ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
+                        ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
+                          ccallparanode.create(leftconv, nil))),
+                      resultdef)
+                  end;
+              end
             else
               begin
                 if is_class(left.resultdef) then
Index: rtl/inc/compproc.inc
===================================================================
--- rtl/inc/compproc.inc	(revision 42322)
+++ rtl/inc/compproc.inc	(working copy)
@@ -794,6 +794,8 @@
 
 procedure fpc_AbstractErrorIntern;compilerproc;
 procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
+function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
+function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
 
 {$ifdef FPC_HAS_FEATURE_FILEIO}
 Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
Index: rtl/inc/system.inc
===================================================================
--- rtl/inc/system.inc	(revision 42322)
+++ rtl/inc/system.inc	(working copy)
@@ -1550,6 +1550,29 @@
 
 
 {*****************************************************************************
+                       (I as TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
+begin
+  if (value>=minvalue) and (value<=maxvalue) then
+    result:=value
+  else
+    handleerroraddrframeInd(219,get_pc_addr,get_frame);
+end;
+
+
+{*****************************************************************************
+                       (I is TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
+begin
+  result := (value>=minvalue) and (value<=maxvalue);
+end;
+
+
+{*****************************************************************************
                        SetJmp/LongJmp support.
 *****************************************************************************}
 
AS-IS-enum-05.patch (6,222 bytes)

J. Gareth Moreton

2019-07-05 21:03

reporter   ~0117094

I've merged my addition of code generation that is specific to x86 platforms - if Low(TMyEnum) is zero, then it consists of a single comparison, and a MOV, SUB, CMP combination if Low(TMyEnum) is non-zero. Let me know what you think.

The issue I reported about the "type identifier not allowed here" error only seems to occur if I run the compiler within the debugger, so I'm not sure what's going on there.

AS-IS-enum-06.patch (11,952 bytes)
Index: compiler/msg/errore.msg
===================================================================
--- compiler/msg/errore.msg	(revision 42331)
+++ compiler/msg/errore.msg	(working copy)
@@ -2038,6 +2038,7 @@
 % require specialisation for methods or nested subroutines.
 type_e_seg_procvardef_wrong_memory_model=04124_E_Procedure variables in that memory model do not store segment information
 type_w_empty_constant_range_set=04125_W_The first value of a set constructur range is greater then the second value, so the range describes an empty set.
+type_e_as_is_enums_with_assign_not_possible=04126_E_as or is cannot be used with non-contiguous enumerations
 % If a set is constructed like this: \var{s:=[9..7];]}, then an empty set is generated. As this is something normally not desired, the compiler warns about it.
 % \end{description}
 #
Index: compiler/ncnv.pas
===================================================================
--- compiler/ncnv.pas	(revision 42331)
+++ compiler/ncnv.pas	(working copy)
@@ -4344,6 +4344,20 @@
                   end;
               end;
           end
+        else if (right.resultdef.typ=enumdef) then
+          begin
+            { left must be an ordinal }
+            if not is_ordinal(left.resultdef) then
+              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
+            case nodetype of
+              isn:
+                resultdef:=pasbool8type;
+              asn:
+                resultdef:=right.resultdef;
+              else
+                InternalError(2019070201);
+            end;
+          end
         else
           CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
       end;
@@ -4372,6 +4386,8 @@
         procname: string;
         statement : tstatementnode;
         tempnode : ttempcreatenode;
+        v,res: Tconstexprint;
+        leftconv: tnode;
       begin
         result:=nil;
         { Passing a class type to an "is" expression cannot result in a class
@@ -4417,6 +4433,32 @@
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef);
           end
+        else if (right.resultdef.typ=enumdef) then
+          begin
+            if left.nodetype=ordconstn then
+              begin
+                v:=Tordconstnode(left).value;
+                res.signed:=false;
+                res.overflow:=false;
+                if (v<tenumdef(right.resultdef).min) or (v>tenumdef(right.resultdef).max) then
+                  res.uvalue:=0 { false }
+                else
+                  res.uvalue:=1; { true }
+                result := cordconstnode.create(res, resultdef, false);
+              end
+            else
+              begin
+                if left.resultdef.typ<>orddef then
+                  leftconv := ctypeconvnode.create_internal(left, s32inttype)
+                else
+                  leftconv := left;
+                result := ccallnode.createinternres('fpc_do_is_enum',
+                  ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
+                    ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
+                      ccallparanode.create(leftconv, nil))),
+                  resultdef);
+              end;
+          end
         else
           begin
             if is_class(left.resultdef) then
@@ -4443,6 +4485,8 @@
     { you can't instantiate an abstract class                      }
     procedure tisnode.pass_generate_code;
       begin
+        { It should still never be called though }
+        InternalError(2019070501);
       end;
 
 
@@ -4495,6 +4539,8 @@
     function tasnode.pass_1 : tnode;
       var
         procname: string;
+        leftconv: tnode;
+        v: Tconstexprint;
       begin
         result:=nil;
         { Passing a class type to an "as" expression cannot result in a class
@@ -4513,6 +4559,28 @@
               call := ccallnode.createinternres('fpc_do_as',
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef)
+            else if (right.resultdef.typ=enumdef) then
+              begin
+                if left.nodetype=ordconstn then
+                  begin
+                    v:=Tordconstnode(left).value;
+                    if (v<tenumdef(right.resultdef).min) or (v>tenumdef(right.resultdef).max) then
+                      Message(parser_e_range_check_error);
+                    call := ctypeconvnode.create_internal(left, resultdef);
+                  end
+                else
+                  begin
+                    if left.resultdef.typ<>orddef then
+                      leftconv := ctypeconvnode.create_internal(left, s32inttype)
+                    else
+                      leftconv := left;
+                    call := ccallnode.createinternres('fpc_do_as_enum',
+                      ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).max, sizesinttype, false),
+                        ccallparanode.create(cordconstnode.create(tenumdef(right.resultdef).min, sizesinttype, false),
+                          ccallparanode.create(leftconv, nil))),
+                      resultdef)
+                  end;
+              end
             else
               begin
                 if is_class(left.resultdef) then
Index: compiler/x86/nx86cnv.pas
===================================================================
--- compiler/x86/nx86cnv.pas	(revision 42331)
+++ compiler/x86/nx86cnv.pas	(working copy)
@@ -26,7 +26,7 @@
 interface
 
     uses
-      node,ncgcnv,defutil;
+      node,ncnv,ncgcnv,defutil,constexp;
 
     type
        tx86typeconvnode = class(tcgtypeconvnode)
@@ -54,7 +54,15 @@
          { procedure second_char_to_char;override; }
        end;
 
+       Tx86IsNode = class(TIsNode)
+       protected
+         min_, max_: TConstExprInt;
+       public
+         function pass_1: TNode; override;
+         procedure pass_generate_code; override;
+       end;
 
+
 implementation
 
    uses
@@ -63,7 +71,7 @@
       symconst,symdef,
       cgbase,cga,pass_1,pass_2,
       cpuinfo,
-      ncnv,
+      ncon,
       cpubase,
       cgutils,cgobj,hlcgobj,cgx86,
       tgobj;
@@ -445,6 +453,98 @@
         location_freetemp(current_asmdata.CurrAsmList,left.location);
       end;
 
+
+{*****************************************************************************
+                               TX86ISNODE
+*****************************************************************************}
+
+    function Tx86IsNode.pass_1: TNode;
+      var
+        OldLeft: TNode;
+        v, res: TConstExprInt;
+      begin
+        if (right.resultdef.typ in [orddef, enumdef]) then
+          begin
+            if left.nodetype=ordconstn then
+              begin
+                v := Tordconstnode(left).value;
+                if (v < TEnumDef(right.resultdef).min) or (v > TEnumDef(right.resultdef).max) then
+                  res := 0 { False }
+                else
+                  res := 1; { True }
+                Result := cordconstnode.create(res, resultdef, false);
+              end
+            else
+              begin
+                if left.resultdef.typ<>orddef then
+                  begin
+                    { Wrap the left node in a new type conversion }
+                    OldLeft := Left;
+                    left := ctypeconvnode.create_internal(OldLeft, s32inttype);
+                    left.fileinfo:=OldLeft.fileinfo;
+                    firstpass(left); { This will also do the type check }
+                  end;
+
+                if right.resultdef.typ = enumdef then
+                  with right.resultdef as TEnumDef do
+                    begin
+                      min_ := min;
+                      max_ := max;
+                    end
+                else
+                  { Must be an orddef due to the check at the top }
+                    with right.resultdef as TOrdDef do
+                      begin
+                        min_ := low;
+                        max_ := high;
+                      end;
+
+                { If the left node's domain is within the right node's domain, the
+                  result is always True }
+
+                if (TOrdDef(left.resultdef).low >= min_) and (TOrdDef(left.resultdef).high <= max_) then
+                  Result := cordconstnode.create(1, resultdef, false)
+                else
+                  { Delegate platform-specific work to pass_generate_code }
+                  Result := nil;
+              end;
+          end
+        else
+          { Go to the default "is" handler }
+          Result := inherited;
+      end;
+
+
+    procedure Tx86IsNode.pass_generate_code;
+      var
+        leftsize, rightsize, opcgsize: TCgSize;
+        scratch_reg: TRegister;
+      begin
+        { The right side will never be smaller than the left side by this point }
+        opcgsize := def_cgsize(right.resultdef);
+
+        secondpass(left);
+
+        scratch_reg := hlcg.getintregister(current_asmdata.CurrAsmList, right.resultdef);
+
+        if min_ = 0 then
+          begin
+            { If the lower bound is zero, we can do the range check without a scratch register }
+            emit_const_ref(A_CMP, TCGSize2Opsize[opcgsize], aint(max_), left.location.reference);
+          end
+        else
+          begin
+            cg.a_load_ref_reg(current_asmdata.CurrAsmList, def_cgsize(left.resultdef), opcgsize, left.location.reference, scratch_reg);
+            cg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SUB, opcgsize, aint(min_), scratch_reg);
+            emit_const_reg(A_CMP, TCGSize2Opsize[opcgsize], aint(max_) - aint(min_), scratch_reg);
+          end;
+
+        location_reset(location, LOC_FLAGS, OS_NO);
+        location.resflags := F_BE;
+      end;
+
+
 begin
-  ctypeconvnode:=tx86typeconvnode
+  ctypeconvnode:=tx86typeconvnode;
+  cisnode := Tx86IsNode;
 end.
Index: rtl/inc/compproc.inc
===================================================================
--- rtl/inc/compproc.inc	(revision 42331)
+++ rtl/inc/compproc.inc	(working copy)
@@ -794,6 +794,8 @@
 
 procedure fpc_AbstractErrorIntern;compilerproc;
 procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
+function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
+function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
 
 {$ifdef FPC_HAS_FEATURE_FILEIO}
 Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
Index: rtl/inc/system.inc
===================================================================
--- rtl/inc/system.inc	(revision 42331)
+++ rtl/inc/system.inc	(working copy)
@@ -1550,6 +1550,29 @@
 
 
 {*****************************************************************************
+                       (I as TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_as_enum(const value, minvalue, maxvalue:SizeInt): SizeInt; compilerproc; inline;
+begin
+  if (value>=minvalue) and (value<=maxvalue) then
+    result:=value
+  else
+    handleerroraddrframeInd(219,get_pc_addr,get_frame);
+end;
+
+
+{*****************************************************************************
+                       (I is TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_is_enum(const value, minvalue, maxvalue:SizeInt): Boolean; compilerproc; inline;
+begin
+  result := (value>=minvalue) and (value<=maxvalue);
+end;
+
+
+{*****************************************************************************
                        SetJmp/LongJmp support.
 *****************************************************************************}
 
AS-IS-enum-06.patch (11,952 bytes)

J. Gareth Moreton

2019-07-06 00:10

reporter   ~0117096

Thinkin about it a bit more, especially after Pierre pointed out that Pred() and Succ() also don't work with non-contiguous enumerations, it may be better to continue disallowing them for "as" and "is" because creating a general purpose algorithm to make an efficient set of Boolean operations to cover all the holes is not going to be straightforward. I would argue it's a small price to pay for this sanity check that is a bit unusual for Free Pascal. Plus, generally, a non-standard value for an element is usually present only for an error value, so the workaround would be to remove it and treat it as invalid like the hole before it.

J. Gareth Moreton

2019-07-08 02:35

reporter   ~0117108

Last edited: 2019-07-08 02:54

View 2 revisions

Finished my work on including all ordinal types. Based on Jonas' and Florian's advice, I've removed my x86-specific implementation for the time being on the word that Jonas' changes will produce more optimal assembly language.

One point to note is that the is and as operators cannot be used in this way within generic functions - I've even left a note in the "ValidOrdIs.lpr" test to refactor it once this issue is resolved. However, I have deferred it for now and will open it as a separate issue once everything here is refactored, tested and approved.



ValidOrdIs.lpr (34,873 bytes)

J. Gareth Moreton

2019-07-08 05:19

reporter   ~0117109

Some of the tests will have to be rewritten. I haven't properly tested ValidEnumAS.lpr and ValidEnumAS-2.lpr, and I know that ValidEnumIS.lpr will no longer compile since "is" and "as" can no longer be used with non-contiguous enumerations (I changed references to "enums with assignments" to "non-contiguous enumerations" in the error messages because, honestly, seeing the error for the first time genuinely confused me because it occurred on a line where there was an assignment to a Boolean variable - I feel that "non-contiguous enumerations" is less ambiguous... assuming people know what the word means).

Thaddy de Koning

2019-07-08 10:27

reporter   ~0117111

Still, the real issue can only be solved by the typinfo unit, since that is needed for value assigned enumeration members.
- shows the type
- shows the name only and only if a name is actually assigned.

I already gave an example for how to avoid enum members with assigned values in the range of the enum that do not actually have a name (so should be excluded)

J. Gareth Moreton

2019-07-09 08:20

reporter   ~0117119

Uploaded new patch with some code standards applied as per Sven's guidelines.

J. Gareth Moreton

2019-07-09 21:17

reporter   ~0117129

More reformatting!

Akira1364

2019-07-10 20:30

reporter   ~0117142

Last edited: 2019-07-11 04:55

View 11 revisions

I think this feature would make much more sense with the ability to work on "non-contiguous" enums, which it seems it originally included.

For example, I often, currently, do overload the "in" operator for a similar purpose, and I'd expect "is" at least to give pretty much identical results:

program Example;

{$mode ObjFPC}

type Letters = (
  A = 5,
  B = 25,
  C = 50,
  D = 75,
  E = 100,
  F = 125,
  G = 150,
  H = 175,
  I = 200,
  J = 225,
  K = 250,
  L = 275,
  M = 300
);

operator In(const A: Word; const B: Letters): Boolean; inline;
begin
  Result := (B <= High(Letters)) and (A >= Word(Low(Letters))) and (A <= Word(B));
end;

var Num: Word;

begin
  // Prints everything from 5 to 300, inclusive, of course.
  for Num := Word(Low(Letters)) to Word(High(Letters)) do
    WriteLn(Num);

  // Prints false, since Letters(2) can never be valid.
  WriteLn(2 in A);

  // Prints false, since 25 is not exactly 5.
  WriteLn(25 in A);

  // Prints false, since Letters(200) is valid, but higher than H as as number.
  WriteLn(200 in H);

  // Prints true, since 36 is between A as a number and C as a number, inclusive.
  WriteLn(36 in C);

  // Prints false, since Letters(9000) is invalid.
  WriteLn(24 in Letters(9000));
end.

Enums *are* essentially just fancier ranges regardless of whether you specify numeric values for their members or not. The only difference is that with non-contiguous values, everything between each one is "implied".

J. Gareth Moreton

2019-07-11 07:03

reporter   ~0117162

The thing with enumerations is that, almost everywhere, the compiler assumes that variables of the enumeration type contain valid values. Even Ord is technically undefined if the enumeration is out of bounds. It's caused problems because there's no reliable means to stop a case block from being entered if the enum contains an invalid value and possibly triggering an access violation.

The idea behind "is" and "as" is that they are the sole exception to the rule and will return False and raise an error respectively if the enum is out of bounds. If the value falls within a hole, then it will pass - currently only in Delphi mode though. FPC mode won't allow it.

J. Gareth Moreton

2019-07-11 11:58

reporter   ~0117179

Updated patch so non-contiguous enumerations now work under all modes.

J. Gareth Moreton

2019-07-13 18:23

reporter  

AS-IS-enum-11.patch (15,930 bytes)
Index: compiler/msg/errore.msg
===================================================================
--- compiler/msg/errore.msg	(revision 42345)
+++ compiler/msg/errore.msg	(working copy)
@@ -1681,7 +1681,7 @@
 type_e_strict_var_string_violation=04016_E_String types have to match exactly in $V+ mode
 % When compiling in \var{\{\$V+\}} mode, the string you pass as a parameter
 % should be of the exact same type as the declared parameter of the procedure.
-type_e_succ_and_pred_enums_with_assign_not_possible=04017_E_Succ or Pred on enums with assignments not possible
+type_e_succ_and_pred_enums_with_assign_not_possible=04017_E_Succ or Pred on non-contiguous enumerations is not possible
 % If you declare an enumeration type which has C-like assignments
 % in it, such as in the following:
 % \begin{verbatim}
@@ -1769,7 +1769,7 @@
 type_e_typecast_wrong_size_for_assignment=04037_E_Typecast has different size ($1 -> $2) in assignment
 % Type casting to a type with a different size is not allowed when the variable is
 % used in an assignment.
-type_e_array_index_enums_with_assign_not_possible=04038_E_Enums with assignments cannot be used as array index
+type_e_array_index_enums_with_assign_not_possible=04038_E_Non-contiguous enumerations cannot be used as an array index
 % When you declared an enumeration type which has C-like
 % assignments, such as in the following:
 % \begin{verbatim}
Index: compiler/ncnv.pas
===================================================================
--- compiler/ncnv.pas	(revision 42345)
+++ compiler/ncnv.pas	(working copy)
@@ -27,7 +27,7 @@
 
     uses
        node,
-       symtype,
+       symtype,constexp,
        defutil,defcmp,
        nld
        ;
@@ -291,6 +291,10 @@
        tasnodeclass = class of tasnode;
 
        tisnode = class(tasisnode)
+       protected
+         lower, upper: tconstexprint;
+         function do_variable_enum_check: tnode; virtual;
+       public
           constructor create(l,r : tnode);virtual;
           constructor create_internal(l,r : tnode);virtual;
           function pass_1 : tnode;override;
@@ -317,7 +321,7 @@
 implementation
 
    uses
-      globtype,systems,constexp,compinnr,
+      globtype,systems,compinnr,
       cutils,verbose,globals,widestr,
       symconst,symdef,symsym,symcpu,symtable,
       ncon,ncal,nset,nadd,nmem,nmat,nbas,nutils,ninl,
@@ -2922,7 +2926,7 @@
                 val.svalue:=swapendian(int64(val.svalue))
               else
                 val.uvalue:=swapendian(qword(val.uvalue));
-	  else
+          else
             internalerror(2014111201);
         end;
       end;
@@ -4344,6 +4348,20 @@
                   end;
               end;
           end
+        else if (right.resultdef.typ in [orddef, enumdef]) then
+          begin
+            { left must be an ordinal }
+            if not is_ordinal(left.resultdef) then
+              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
+            case nodetype of
+              isn:
+                resultdef:=pasbool8type;
+              asn:
+                resultdef:=right.resultdef;
+              else
+                InternalError(2019070201);
+            end;
+          end
         else
           CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
       end;
@@ -4367,11 +4385,80 @@
       end;
 
 
+    function tisnode.do_variable_enum_check: tnode;
+      var
+        oldleft : tnode;
+        ProcName : string;
+        intsize : tdef;
+      begin
+        if left.resultdef.typ<>orddef then
+          begin
+            { Wrap the left node in a new type conversion }
+            oldleft:=left;
+            left:=ctypeconvnode.create_internal(oldleft,s32inttype);
+            left.fileinfo:=oldleft.fileinfo;
+            typecheckpass(left);
+          end;
+
+        { If the left node's domain is within the right node's domain, the
+          result is always True (enums are expanded to LongInt) }
+
+        if (torddef(left.resultdef).low>=lower) and (torddef(left.resultdef).high<=upper) then
+          Result:=cordconstnode.create(1,resultdef,false)
+        else
+          begin
+            { Make the valid domain as small as possible (this prevents
+              "Int64 is QWord" from returning incorrect results for negative
+              inputs. }
+            lower:=max(torddef(left.resultdef).low, lower);
+            upper:=min(torddef(left.resultdef).high, upper);
+
+            if upper<lower then
+              InternalError(2019070721);
+
+            if (lower<torddef(sizesinttype).low) or (upper>torddef(sizesinttype).high) or
+              (torddef(left.resultdef).low<torddef(sizesinttype).low) or
+              (torddef(left.resultdef).high>torddef(sizesinttype).high) then
+              begin
+                { The ordinal type exceeds the CPU word size, so we have to use
+                  a slower function }
+                if (upper>qword(High(int64))) or (torddef(left.resultdef).high>qword(High(int64))) then
+                  begin
+                    if (lower<0) then
+                      { Impossible range }
+                      InternalError(2019070720);
+
+                    ProcName:='fpc_do_is_qword';
+                    intsize:=u64inttype;
+                  end
+                else
+                  begin
+                    ProcName:='fpc_do_is_int64';
+                    intsize:=s64inttype;
+                  end;
+              end
+            else
+              begin
+                ProcName:='fpc_do_is_enum';
+                intsize:=sizesinttype;
+              end;
+
+            Result:=ccallnode.createinternres(ProcName,
+              ccallparanode.create(cordconstnode.create(upper, intsize, false),
+                ccallparanode.create(cordconstnode.create(lower, intsize, false),
+                  ccallparanode.create(left, nil))),
+              resultdef);
+
+          end;
+      end;
+
+
     function tisnode.pass_1 : tnode;
       var
         procname: string;
         statement : tstatementnode;
         tempnode : ttempcreatenode;
+        v,res : Tconstexprint;
       begin
         result:=nil;
         { Passing a class type to an "is" expression cannot result in a class
@@ -4417,6 +4504,41 @@
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef);
           end
+        else if (right.resultdef.typ in [orddef, enumdef]) then
+          begin
+            { For a right node of type enumdef or orddef, store the lower and upper
+              bounds into the lower and upper properties }
+            if right.resultdef.typ=enumdef then
+              begin
+                lower:=tenumdef(right.resultdef).min;
+                upper:=tenumdef(right.resultdef).max;
+              end
+            else
+              { Must be an orddef due to the if-statement earlier }
+              begin
+                lower:=torddef(right.resultdef).low;
+                upper:=torddef(right.resultdef).high;
+              end;
+
+            if left.nodetype=ordconstn then
+              begin
+                v:=Tordconstnode(left).value;
+                if (v<lower) or (v>upper) then
+                  res:=0 { false }
+                else
+                  res:=1; { true }
+
+                result:=cordconstnode.create(res, resultdef, false);
+              end
+            else
+              begin
+                if right.nodetype=typen then
+                  TTypeNode(right).allowed:=True;
+
+                Result:=do_variable_enum_check;
+              end;
+
+          end
         else
           begin
             if is_class(left.resultdef) then
@@ -4429,20 +4551,26 @@
                 procname := 'fpc_intf_is_class'
               else
                 procname := 'fpc_intf_is';
-            result := ctypeconvnode.create_internal(ccallnode.createintern(procname,
+            result:=ctypeconvnode.create_internal(ccallnode.createintern(procname,
                ccallparanode.create(right,ccallparanode.create(left,nil))),resultdef);
           end;
-        left := nil;
-        right := nil;
-        //firstpass(call);
-        if codegenerror then
-          exit;
+
+        { Result may be nil on some platform-specific implementations of
+          do_variable_enum_check }
+        if Assigned(Result) then
+          begin
+            left:=nil;
+            right:=nil;
+          end;
       end;
 
-    { dummy pass_2, it will never be called, but we need one since }
-    { you can't instantiate an abstract class                      }
+    { dummy pass_2, it will never be called on platform-agnostic implementations,
+      but we need one since you can't instantiate an abstract class }
     procedure tisnode.pass_generate_code;
       begin
+        { It should still never be called though - if this internal error is
+          triggered, then Result was nil after pass_1 was called. }
+        InternalError(2019070501);
       end;
 
 
@@ -4495,6 +4623,9 @@
     function tasnode.pass_1 : tnode;
       var
         procname: string;
+        leftconv : tnode;
+        lower, upper, v : Tconstexprint;
+        intsize : tdef;
       begin
         result:=nil;
         { Passing a class type to an "as" expression cannot result in a class
@@ -4513,6 +4644,78 @@
               call := ccallnode.createinternres('fpc_do_as',
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef)
+            else if (right.resultdef.typ in [orddef, enumdef]) then
+              begin
+                if right.resultdef.typ=enumdef then
+                  begin
+                    lower:=tenumdef(right.resultdef).min;
+                    upper:=tenumdef(right.resultdef).max;
+                  end
+                else
+                  { Must be an orddef due to the if-statement earlier }
+                  begin
+                    lower:=torddef(right.resultdef).low;
+                    upper:=torddef(right.resultdef).high;
+                  end;
+
+                if left.nodetype=ordconstn then
+                  begin
+                    v:=Tordconstnode(left).value;
+                    if (v<lower) or (v>upper) then
+                      Message(parser_e_range_check_error);
+                    call:=ctypeconvnode.create_internal(left, resultdef);
+                  end
+                else
+                  begin
+                    if left.resultdef.typ<>orddef then
+                      leftconv:=ctypeconvnode.create_internal(left, s32inttype)
+                    else
+                      leftconv:=left;
+                  end;
+
+                { Make the valid domain as small as possible (this prevents
+                  "Int64 as QWord" from returning incorrect results for negative
+                  inputs. }
+                lower:=max(torddef(left.resultdef).low, lower);
+                upper:=min(torddef(left.resultdef).high, upper);
+
+                if upper<lower then
+                  InternalError(2019070731);
+
+                if (lower<torddef(sizesinttype).low) or (upper>torddef(sizesinttype).high) or
+                  (torddef(left.resultdef).low<torddef(sizesinttype).low) or
+                  (torddef(left.resultdef).high>torddef(sizesinttype).high) then
+                  begin
+                    { The ordinal type exceeds the CPU word size, so we have to use
+                      a slower function }
+
+                    if (upper>QWord(High(Int64))) then
+                      begin
+                        if (lower<0) then
+                          { Impossible range }
+                          InternalError(2019070730);
+
+                        ProcName:='fpc_do_as_qword';
+                        intsize:=u64inttype;
+                      end
+                    else
+                      begin
+                        ProcName:='fpc_do_as_int64';
+                        intsize:=s64inttype;
+                      end;
+                  end
+                else
+                  begin
+                    ProcName:='fpc_do_as_enum';
+                    intsize:=sizesinttype;
+                  end;
+
+                call:=ccallnode.createinternres(ProcName,
+                  ccallparanode.create(cordconstnode.create(upper, intsize, false),
+                    ccallparanode.create(cordconstnode.create(lower, intsize, false),
+                      ccallparanode.create(leftconv, nil))),
+                  resultdef);
+              end
             else
               begin
                 if is_class(left.resultdef) then
Index: rtl/inc/compproc.inc
===================================================================
--- rtl/inc/compproc.inc	(revision 42345)
+++ rtl/inc/compproc.inc	(working copy)
@@ -795,6 +795,13 @@
 procedure fpc_AbstractErrorIntern;compilerproc;
 procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
 
+function fpc_do_as_enum(const value, minvalue, maxvalue: SizeInt): SizeInt; compilerproc; inline;
+function fpc_do_as_int64(const value, minvalue, maxvalue: Int64): Int64; compilerproc; inline;
+function fpc_do_as_qword(const value, minvalue, maxvalue: QWord): QWord; compilerproc; inline;
+function fpc_do_is_enum(const value, minvalue, maxvalue: SizeInt): Boolean; compilerproc; inline;
+function fpc_do_is_int64(const value, minvalue, maxvalue: Int64): Boolean; compilerproc; inline;
+function fpc_do_is_qword(const value, minvalue, maxvalue: QWord): Boolean; compilerproc; inline;
+
 {$ifdef FPC_HAS_FEATURE_FILEIO}
 Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
 Procedure fpc_rewrite_typed(var f : TypedFile;Size : Longint); compilerproc;
Index: rtl/inc/system.inc
===================================================================
--- rtl/inc/system.inc	(revision 42345)
+++ rtl/inc/system.inc	(working copy)
@@ -1550,6 +1550,59 @@
 
 
 {*****************************************************************************
+                       (I as TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_as_enum(const value, minvalue, maxvalue: SizeInt): SizeInt; compilerproc; inline;
+begin
+  if (value>=minvalue) and (value<=maxvalue) then
+    result:=value
+  else
+    handleerroraddrframeInd(219,get_pc_addr,get_frame);
+end;
+
+
+function fpc_do_as_int64(const value, minvalue, maxvalue: Int64): Int64; compilerproc; inline;
+begin
+  if (value>=minvalue) and (value<=maxvalue) then
+    result:=value
+  else
+    handleerroraddrframeInd(219,get_pc_addr,get_frame);
+end;
+
+
+function fpc_do_as_qword(const value, minvalue, maxvalue: QWord): QWord; compilerproc; inline;
+begin
+  if (value>=minvalue) and (value<=maxvalue) then
+    result:=value
+  else
+    handleerroraddrframeInd(219,get_pc_addr,get_frame);
+end;
+
+
+{*****************************************************************************
+                       (I is TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_is_enum(const value, minvalue, maxvalue: SizeInt): Boolean; compilerproc; inline;
+begin
+  result:=(value>=minvalue) and (value<=maxvalue);
+end;
+
+
+function fpc_do_is_int64(const value, minvalue, maxvalue: Int64): Boolean; compilerproc; inline;
+begin
+  result:=(value>=minvalue) and (value<=maxvalue);
+end;
+
+
+function fpc_do_is_qword(const value, minvalue, maxvalue: QWord): Boolean; compilerproc; inline;
+begin
+  result:=(value>=minvalue) and (value<=maxvalue);
+end;
+
+
+{*****************************************************************************
                        SetJmp/LongJmp support.
 *****************************************************************************}
 
AS-IS-enum-11.patch (15,930 bytes)
AS-IS-enum-11-strict.patch (16,847 bytes)
Index: compiler/msg/errore.msg
===================================================================
--- compiler/msg/errore.msg	(revision 42348)
+++ compiler/msg/errore.msg	(working copy)
@@ -1681,7 +1681,7 @@
 type_e_strict_var_string_violation=04016_E_String types have to match exactly in $V+ mode
 % When compiling in \var{\{\$V+\}} mode, the string you pass as a parameter
 % should be of the exact same type as the declared parameter of the procedure.
-type_e_succ_and_pred_enums_with_assign_not_possible=04017_E_Succ or Pred on enums with assignments not possible
+type_e_succ_and_pred_enums_with_assign_not_possible=04017_E_Succ or Pred on non-contiguous enumerations is not possible
 % If you declare an enumeration type which has C-like assignments
 % in it, such as in the following:
 % \begin{verbatim}
@@ -1769,7 +1769,7 @@
 type_e_typecast_wrong_size_for_assignment=04037_E_Typecast has different size ($1 -> $2) in assignment
 % Type casting to a type with a different size is not allowed when the variable is
 % used in an assignment.
-type_e_array_index_enums_with_assign_not_possible=04038_E_Enums with assignments cannot be used as array index
+type_e_array_index_enums_with_assign_not_possible=04038_E_Non-contiguous enumerations cannot be used as an array index
 % When you declared an enumeration type which has C-like
 % assignments, such as in the following:
 % \begin{verbatim}
Index: compiler/ncnv.pas
===================================================================
--- compiler/ncnv.pas	(revision 42348)
+++ compiler/ncnv.pas	(working copy)
@@ -27,7 +27,7 @@
 
     uses
        node,
-       symtype,
+       symtype,constexp,
        defutil,defcmp,
        nld
        ;
@@ -291,6 +291,10 @@
        tasnodeclass = class of tasnode;
 
        tisnode = class(tasisnode)
+       protected
+         lower, upper : tconstexprint;
+         function do_variable_enum_check: tnode; virtual;
+       public
           constructor create(l,r : tnode);virtual;
           constructor create_internal(l,r : tnode);virtual;
           function pass_1 : tnode;override;
@@ -317,7 +321,7 @@
 implementation
 
    uses
-      globtype,systems,constexp,compinnr,
+      globtype,systems,compinnr,
       cutils,verbose,globals,widestr,
       symconst,symdef,symsym,symcpu,symtable,
       ncon,ncal,nset,nadd,nmem,nmat,nbas,nutils,ninl,
@@ -2922,7 +2926,7 @@
                 val.svalue:=swapendian(int64(val.svalue))
               else
                 val.uvalue:=swapendian(qword(val.uvalue));
-	  else
+          else
             internalerror(2014111201);
         end;
       end;
@@ -4344,6 +4348,20 @@
                   end;
               end;
           end
+        else if (right.resultdef.typ in [orddef, enumdef]) then
+          begin
+            { left must be an ordinal }
+            if not is_ordinal(left.resultdef) then
+              CGMessage1(type_e_ordinal_expr_expected,left.resultdef.typename);
+            case nodetype of
+              isn:
+                resultdef:=pasbool8type;
+              asn:
+                resultdef:=right.resultdef;
+              else
+                InternalError(2019070201);
+            end;
+          end
         else
           CGMessage1(type_e_class_or_interface_type_expected,right.resultdef.typename);
       end;
@@ -4367,11 +4385,93 @@
       end;
 
 
+    function tisnode.do_variable_enum_check: tnode;
+      var
+        oldleft : tnode;
+        procname : string;
+        intsize : tdef;
+        leftlower, leftupper : tconstexprint;
+      begin
+        if left.resultdef.typ=enumdef then
+          begin
+            leftlower:=tenumdef(left.resultdef).min;
+            leftupper:=tenumdef(left.resultdef).max;
+          end
+        else if left.resultdef.typ=orddef then
+          begin
+            leftlower:=torddef(left.resultdef).low;
+            leftupper:=torddef(left.resultdef).high;
+          end
+        else
+          begin
+            { Attempt to typecast }
+            oldleft:=left;
+            left:=ctypeconvnode.create_internal(oldleft,s32inttype);
+            left.fileinfo:=oldleft.fileinfo;
+            firstpass(left);
+            leftlower:=torddef(left.resultdef).low;
+            leftupper:=torddef(left.resultdef).high;
+          end;
+
+        { If the left node's domain is within the right node's domain, the
+          result is always True (enums are expanded to LongInt) }
+
+        if (leftlower>=lower) and (leftupper<=upper) then
+          Result:=cordconstnode.create(1,resultdef,false)
+        else
+          begin
+            { Make the valid domain as small as possible (this prevents
+              "Int64 is QWord" from returning incorrect results for negative
+              inputs. }
+            lower:=max(leftlower,lower);
+            upper:=min(leftupper,upper);
+
+            if upper<lower then
+              InternalError(2019070721);
+
+            if (lower<torddef(sizesinttype).low) or (upper>torddef(sizesinttype).high) or
+              (leftlower<torddef(sizesinttype).low) or
+              (leftupper>torddef(sizesinttype).high) then
+              begin
+                { The ordinal type exceeds the CPU word size, so we have to use
+                  a slower function }
+                if (upper>qword(High(int64))) or (torddef(left.resultdef).high>qword(High(int64))) then
+                  begin
+                    if (lower<0) then
+                      { Impossible range }
+                      InternalError(2019070720);
+
+                    procname:='fpc_do_is_qword';
+                    intsize:=u64inttype;
+                  end
+                else
+                  begin
+                    procname:='fpc_do_is_int64';
+                    intsize:=s64inttype;
+                  end;
+              end
+            else
+              begin
+                procname:='fpc_do_is_enum';
+                intsize:=sizesinttype;
+              end;
+
+            Result:=ccallnode.createinternres(procname,
+              ccallparanode.create(cordconstnode.create(upper, intsize, false),
+                ccallparanode.create(cordconstnode.create(lower, intsize, false),
+                  ccallparanode.create(left, nil))),
+              resultdef);
+
+          end;
+      end;
+
+
     function tisnode.pass_1 : tnode;
       var
         procname: string;
         statement : tstatementnode;
         tempnode : ttempcreatenode;
+        v,res : tconstexprint;
       begin
         result:=nil;
         { Passing a class type to an "is" expression cannot result in a class
@@ -4417,6 +4517,41 @@
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef);
           end
+        else if (right.resultdef.typ in [orddef, enumdef]) then
+          begin
+            { For a right node of type enumdef or orddef, store the lower and upper
+              bounds into the lower and upper properties }
+            if right.resultdef.typ=enumdef then
+              begin
+                lower:=tenumdef(right.resultdef).min;
+                upper:=tenumdef(right.resultdef).max;
+              end
+            else
+              { Must be an orddef due to the if-statement earlier }
+              begin
+                lower:=torddef(right.resultdef).low;
+                upper:=torddef(right.resultdef).high;
+              end;
+
+            if left.nodetype=ordconstn then
+              begin
+                v:=Tordconstnode(left).value;
+                if (v<lower) or (v>upper) then
+                  res:=0 { false }
+                else
+                  res:=1; { true }
+
+                result:=cordconstnode.create(res, resultdef, false);
+              end
+            else
+              begin
+                if right.nodetype=typen then
+                  TTypeNode(right).allowed:=True;
+
+                Result:=do_variable_enum_check;
+              end;
+
+          end
         else
           begin
             if is_class(left.resultdef) then
@@ -4429,20 +4564,26 @@
                 procname := 'fpc_intf_is_class'
               else
                 procname := 'fpc_intf_is';
-            result := ctypeconvnode.create_internal(ccallnode.createintern(procname,
+            result:=ctypeconvnode.create_internal(ccallnode.createintern(procname,
                ccallparanode.create(right,ccallparanode.create(left,nil))),resultdef);
           end;
-        left := nil;
-        right := nil;
-        //firstpass(call);
-        if codegenerror then
-          exit;
+
+        { Result may be nil on some platform-specific implementations of
+          do_variable_enum_check }
+        if Assigned(Result) then
+          begin
+            left:=nil;
+            right:=nil;
+          end;
       end;
 
-    { dummy pass_2, it will never be called, but we need one since }
-    { you can't instantiate an abstract class                      }
+    { dummy pass_2, it will never be called on platform-agnostic implementations,
+      but we need one since you can't instantiate an abstract class }
     procedure tisnode.pass_generate_code;
       begin
+        { It should still never be called though - if this internal error is
+          triggered, then Result was nil after pass_1 was called. }
+        InternalError(2019070501);
       end;
 
 
@@ -4495,6 +4636,9 @@
     function tasnode.pass_1 : tnode;
       var
         procname: string;
+        leftlower, leftupper, rightlower, rightupper, v : tconstexprint;
+        intsize : tdef;
+        oldleft : tnode;
       begin
         result:=nil;
         { Passing a class type to an "as" expression cannot result in a class
@@ -4513,6 +4657,90 @@
               call := ccallnode.createinternres('fpc_do_as',
                 ccallparanode.create(left,ccallparanode.create(right,nil)),
                 resultdef)
+            else if (right.resultdef.typ in [orddef, enumdef]) then
+              begin
+                if right.resultdef.typ=enumdef then
+                  begin
+                    rightlower:=tenumdef(right.resultdef).min;
+                    rightupper:=tenumdef(right.resultdef).max;
+                  end
+                else
+                  { Must be an orddef due to the if-statement earlier }
+                  begin
+                    rightlower:=torddef(right.resultdef).low;
+                    rightupper:=torddef(right.resultdef).high;
+                  end;
+
+                if left.nodetype=ordconstn then
+                  begin
+                    v:=Tordconstnode(left).value;
+                    if (v<rightlower) or (v>rightupper) then
+                      Message(parser_e_range_check_error);
+                    call:=ctypeconvnode.create_internal(left,resultdef);
+                  end;
+
+                { Make the valid domain as small as possible (this prevents
+                  "Int64 as QWord" from returning incorrect results for negative
+                  inputs. }
+
+                if left.resultdef.typ=enumdef then
+                  begin
+                    leftlower:=tenumdef(left.resultdef).min;
+                    leftupper:=tenumdef(left.resultdef).max;
+                  end
+                else if left.resultdef.typ=orddef then
+                  begin
+                    leftlower:=torddef(left.resultdef).low;
+                    leftupper:=torddef(left.resultdef).high;
+                  end
+                else
+                  begin
+                    { Attempt to typecast }
+                    oldleft:=left;
+                    left:=ctypeconvnode.create_internal(oldleft,s32inttype);
+                    left.fileinfo:=oldleft.fileinfo;
+                    firstpass(left);
+                    leftlower:=torddef(left.resultdef).low;
+                    leftupper:=torddef(left.resultdef).high;
+                  end;
+
+                if rightupper<rightlower then
+                  InternalError(2019070731);
+
+                if (rightlower<torddef(sizesinttype).low) or (rightupper>torddef(sizesinttype).high) or
+                  (leftlower<torddef(sizesinttype).low) or
+                  (leftupper>torddef(sizesinttype).high) then
+                  begin
+                    { The ordinal type exceeds the CPU word size, so we have to use
+                      a slower function }
+
+                    if (rightupper>qword(High(int64))) then
+                      begin
+                        if (rightlower<0) then
+                          { Impossible range }
+                          InternalError(2019070730);
+
+                        procname:='fpc_do_as_qword';
+                        intsize:=u64inttype;
+                      end
+                    else
+                      begin
+                        procname:='fpc_do_as_int64';
+                        intsize:=s64inttype;
+                      end;
+                  end
+                else
+                  begin
+                    procname:='fpc_do_as_enum';
+                    intsize:=sizesinttype;
+                  end;
+
+                call := ccallnode.createinternres(procname,
+                  ccallparanode.create(cordconstnode.create(rightupper, intsize, false),
+                    ccallparanode.create(cordconstnode.create(rightlower, intsize, false),
+                      ccallparanode.create(left, nil))),
+                  resultdef);
+              end
             else
               begin
                 if is_class(left.resultdef) then
Index: rtl/inc/compproc.inc
===================================================================
--- rtl/inc/compproc.inc	(revision 42348)
+++ rtl/inc/compproc.inc	(working copy)
@@ -795,6 +795,13 @@
 procedure fpc_AbstractErrorIntern;compilerproc;
 procedure fpc_assert(Const Msg,FName:Shortstring;LineNo:Longint;ErrorAddr:Pointer); compilerproc;
 
+function fpc_do_as_enum(const value, minvalue, maxvalue: SizeInt): SizeInt; compilerproc; inline;
+function fpc_do_as_int64(const value, minvalue, maxvalue: Int64): Int64; compilerproc; inline;
+function fpc_do_as_qword(const value, minvalue, maxvalue: QWord): QWord; compilerproc; inline;
+function fpc_do_is_enum(const value, minvalue, maxvalue: SizeInt): Boolean; compilerproc; inline;
+function fpc_do_is_int64(const value, minvalue, maxvalue: Int64): Boolean; compilerproc; inline;
+function fpc_do_is_qword(const value, minvalue, maxvalue: QWord): Boolean; compilerproc; inline;
+
 {$ifdef FPC_HAS_FEATURE_FILEIO}
 Procedure fpc_reset_typed(var f : TypedFile;Size : Longint); compilerproc;
 Procedure fpc_rewrite_typed(var f : TypedFile;Size : Longint); compilerproc;
Index: rtl/inc/system.inc
===================================================================
--- rtl/inc/system.inc	(revision 42348)
+++ rtl/inc/system.inc	(working copy)
@@ -1550,6 +1550,59 @@
 
 
 {*****************************************************************************
+                       (I as TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_as_enum(const value, minvalue, maxvalue: SizeInt): SizeInt; compilerproc; inline;
+begin
+  if (value>=minvalue) and (value<=maxvalue) then
+    result:=value
+  else
+    handleerroraddrframeInd(219,get_pc_addr,get_frame);
+end;
+
+
+function fpc_do_as_int64(const value, minvalue, maxvalue: Int64): Int64; compilerproc; inline;
+begin
+  if (value>=minvalue) and (value<=maxvalue) then
+    result:=value
+  else
+    handleerroraddrframeInd(219,get_pc_addr,get_frame);
+end;
+
+
+function fpc_do_as_qword(const value, minvalue, maxvalue: QWord): QWord; compilerproc; inline;
+begin
+  if (value>=minvalue) and (value<=maxvalue) then
+    result:=value
+  else
+    handleerroraddrframeInd(219,get_pc_addr,get_frame);
+end;
+
+
+{*****************************************************************************
+                       (I is TMyEnum) support.
+*****************************************************************************}
+
+function fpc_do_is_enum(const value, minvalue, maxvalue: SizeInt): Boolean; compilerproc; inline;
+begin
+  result := (value>=minvalue) and (value<=maxvalue);
+end;
+
+
+function fpc_do_is_int64(const value, minvalue, maxvalue: Int64): Boolean; compilerproc; inline;
+begin
+  result := (value>=minvalue) and (value<=maxvalue);
+end;
+
+
+function fpc_do_is_qword(const value, minvalue, maxvalue: QWord): Boolean; compilerproc; inline;
+begin
+  result := (value>=minvalue) and (value<=maxvalue);
+end;
+
+
+{*****************************************************************************
                        SetJmp/LongJmp support.
 *****************************************************************************}
 

J. Gareth Moreton

2019-07-13 18:23

reporter   ~0117249

Fixed a bug that caused the "as" operator to not behave properly. I have also uploaded an alternative patch that assumes enums contain valid values ("...-strict").

Issue History

Date Modified Username Field Change
2018-04-13 12:52 Ondrej Pokorny New Issue
2018-04-13 12:52 Ondrej Pokorny File Added: AS-enum-01.patch
2018-04-13 12:53 Ondrej Pokorny File Added: ValidEnumAS.lpr
2018-04-15 14:07 Ondrej Pokorny File Added: AS-IS-enum-02.patch
2018-04-15 14:08 Ondrej Pokorny File Added: ValidEnumIS.lpr
2018-04-15 14:08 Ondrej Pokorny File Added: ValidEnumAS-2.lpr
2018-04-15 14:11 Ondrej Pokorny Note Added: 0107796
2018-04-16 12:52 Thaddy de Koning Note Added: 0107808
2018-04-16 12:53 Thaddy de Koning Note Edited: 0107808 View Revisions
2018-04-16 12:54 Thaddy de Koning Note Edited: 0107808 View Revisions
2018-04-16 12:57 Thaddy de Koning Note Edited: 0107808 View Revisions
2018-04-16 12:59 Thaddy de Koning Note Edited: 0107808 View Revisions
2018-04-16 13:08 Thaddy de Koning Note Added: 0107809
2018-04-16 13:09 Thaddy de Koning Note Edited: 0107809 View Revisions
2018-04-16 13:22 Thaddy de Koning Note Added: 0107810
2018-04-16 13:23 Thaddy de Koning Note Edited: 0107810 View Revisions
2018-04-16 13:24 Thaddy de Koning Note Edited: 0107810 View Revisions
2018-04-16 13:25 Thaddy de Koning Note Edited: 0107810 View Revisions
2018-04-16 13:27 Thaddy de Koning Note Edited: 0107810 View Revisions
2018-04-16 13:31 Thaddy de Koning Note Edited: 0107810 View Revisions
2018-04-16 13:35 Ondrej Pokorny Note Added: 0107811
2018-04-16 13:36 Thaddy de Koning Note Added: 0107812
2018-04-16 13:40 Thaddy de Koning Note Added: 0107813
2018-04-16 13:43 Thaddy de Koning Note Edited: 0107813 View Revisions
2018-04-16 13:47 Thaddy de Koning Note Edited: 0107813 View Revisions
2018-04-16 14:05 Thaddy de Koning Note Added: 0107814
2018-04-16 14:06 Thaddy de Koning Note Edited: 0107814 View Revisions
2018-04-16 14:16 Thaddy de Koning Note Edited: 0107814 View Revisions
2018-04-16 14:18 Thaddy de Koning Note Added: 0107815
2018-04-16 14:19 Ondrej Pokorny Note Added: 0107816
2018-04-16 14:31 Ondrej Pokorny Note Added: 0107818
2018-04-16 16:03 Thaddy de Koning Note Added: 0107819
2018-04-16 16:51 Ondrej Pokorny File Added: AS-IS-enum-03.patch
2018-04-16 17:01 Ondrej Pokorny Note Added: 0107821
2018-04-16 17:03 Thaddy de Koning Note Edited: 0107819 View Revisions
2018-04-16 17:05 Thaddy de Koning Note Added: 0107822
2018-04-16 18:53 Thaddy de Koning Note Edited: 0107822 View Revisions
2018-04-18 14:58 Thaddy de Koning Note Added: 0107844
2018-04-18 14:59 Thaddy de Koning Note Edited: 0107844 View Revisions
2018-04-18 15:06 Ondrej Pokorny Note Added: 0107845
2018-04-19 21:47 Thaddy de Koning Note Added: 0107877
2018-04-19 21:49 Thaddy de Koning Note Edited: 0107877 View Revisions
2018-04-19 23:41 Ondrej Pokorny Note Added: 0107881
2018-04-20 20:27 Thaddy de Koning Note Added: 0107887
2018-04-20 20:28 Thaddy de Koning Note Edited: 0107887 View Revisions
2018-04-20 20:33 Thaddy de Koning Note Edited: 0107887 View Revisions
2018-04-20 20:42 Ondrej Pokorny Note Added: 0107888
2018-04-20 20:54 Thaddy de Koning Note Added: 0107889
2018-04-20 20:56 Thaddy de Koning Note Edited: 0107889 View Revisions
2018-04-20 20:59 Thaddy de Koning Note Edited: 0107889 View Revisions
2018-04-20 21:13 Ondrej Pokorny Note Added: 0107890
2018-04-21 13:42 Thaddy de Koning Note Added: 0107893
2018-04-21 13:44 Thaddy de Koning Note Edited: 0107893 View Revisions
2018-04-21 13:46 Thaddy de Koning Note Edited: 0107893 View Revisions
2018-04-21 21:09 Thaddy de Koning Note Added: 0107899
2019-07-02 21:41 J. Gareth Moreton Note Added: 0117033
2019-07-02 21:43 J. Gareth Moreton Tag Attached: compiler
2019-07-02 21:43 J. Gareth Moreton Tag Attached: patch
2019-07-02 21:43 J. Gareth Moreton Tag Attached: enumeration
2019-07-02 21:43 J. Gareth Moreton Tag Attached: range checks
2019-07-02 21:43 J. Gareth Moreton Tag Attached: Feature
2019-07-02 22:41 Ondrej Pokorny Note Added: 0117037
2019-07-02 22:46 Ondrej Pokorny Note Edited: 0117037 View Revisions
2019-07-02 22:53 J. Gareth Moreton File Added: AS-IS-enum-04.patch
2019-07-02 22:53 J. Gareth Moreton Note Added: 0117040
2019-07-02 23:00 J. Gareth Moreton File Deleted: AS-IS-enum-04.patch
2019-07-02 23:00 J. Gareth Moreton File Added: AS-IS-enum-04.patch
2019-07-02 23:01 J. Gareth Moreton File Deleted: AS-IS-enum-04.patch
2019-07-02 23:02 J. Gareth Moreton File Added: AS-IS-enum-04.patch
2019-07-04 09:02 J. Gareth Moreton Note Added: 0117056
2019-07-04 09:10 Ondrej Pokorny Note Added: 0117057
2019-07-04 09:11 Ondrej Pokorny Note Edited: 0117057 View Revisions
2019-07-04 10:13 Ondrej Pokorny Note Added: 0117058
2019-07-04 10:15 Ondrej Pokorny File Added: AS-IS-enum-05.patch
2019-07-05 21:03 J. Gareth Moreton File Added: AS-IS-enum-06.patch
2019-07-05 21:03 J. Gareth Moreton Note Added: 0117094
2019-07-06 00:10 J. Gareth Moreton Note Added: 0117096
2019-07-08 02:35 J. Gareth Moreton File Added: AS-IS-enum-07.patch
2019-07-08 02:35 J. Gareth Moreton File Added: ValidOrdIs.lpr
2019-07-08 02:35 J. Gareth Moreton Note Added: 0117108
2019-07-08 02:54 J. Gareth Moreton Note Edited: 0117108 View Revisions
2019-07-08 05:19 J. Gareth Moreton Note Added: 0117109
2019-07-08 10:27 Thaddy de Koning Note Added: 0117111
2019-07-09 08:20 J. Gareth Moreton File Added: AS-IS-enum-08.patch
2019-07-09 08:20 J. Gareth Moreton Note Added: 0117119
2019-07-09 21:17 J. Gareth Moreton File Deleted: AS-IS-enum-07.patch
2019-07-09 21:17 J. Gareth Moreton File Deleted: AS-IS-enum-08.patch
2019-07-09 21:17 J. Gareth Moreton File Added: AS-IS-enum-09.patch
2019-07-09 21:17 J. Gareth Moreton Note Added: 0117129
2019-07-10 20:30 Akira1364 Note Added: 0117142
2019-07-10 20:31 Akira1364 Note Edited: 0117142 View Revisions
2019-07-10 20:44 Akira1364 Note Edited: 0117142 View Revisions
2019-07-10 20:45 Akira1364 Note Edited: 0117142 View Revisions
2019-07-10 20:49 Akira1364 Note Edited: 0117142 View Revisions
2019-07-10 21:04 Akira1364 Note Edited: 0117142 View Revisions
2019-07-10 21:05 Akira1364 Note Edited: 0117142 View Revisions
2019-07-10 21:17 Akira1364 Note Edited: 0117142 View Revisions
2019-07-10 21:38 Akira1364 Note Edited: 0117142 View Revisions
2019-07-10 21:51 Akira1364 Note Edited: 0117142 View Revisions
2019-07-11 04:55 Akira1364 Note Edited: 0117142 View Revisions
2019-07-11 07:03 J. Gareth Moreton Note Added: 0117162
2019-07-11 11:57 J. Gareth Moreton File Deleted: AS-IS-enum-09.patch
2019-07-11 11:58 J. Gareth Moreton File Added: AS-IS-enum-10.patch
2019-07-11 11:58 J. Gareth Moreton Note Added: 0117179
2019-07-13 18:22 J. Gareth Moreton File Deleted: AS-IS-enum-10.patch
2019-07-13 18:23 J. Gareth Moreton File Added: AS-IS-enum-11.patch
2019-07-13 18:23 J. Gareth Moreton File Added: AS-IS-enum-11-strict.patch
2019-07-13 18:23 J. Gareth Moreton Note Added: 0117249