View Issue Details

IDProjectCategoryView StatusLast Update
0029460FPCCompilerpublic2019-10-06 12:40
ReporterOndrej PokornyAssigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
Product Version3.1.1Product Build 
Target VersionFixed in Version 
Summary0029460: Cannot declare "LongInt = AnsiString" comparison operator
DescriptionWhen I want to declare "LongInt = AnsiString" comparison operator, the compiler tells me "Impossible operator overload" although it is documented to work.

http://lazarus-ccr.sourceforge.net/fpcdoc/ref/refse67.html#x156-16300012.5 :
The comparision operator can be overloaded to compare two different types or to compare two equal types that are not basic types.
Steps To ReproduceCompile the following program:

program project1;

{$mode objfpc}{$H+}
{$modeswitch advancedrecords}

operator = (z1: LongInt; z2 : ansistring) b : boolean;
begin
  b := false;
end;

var
  i: longint;
  s: string;
begin
  writeln(i = s);
  readln;
end.
TagsNo tags attached.
Fixed in Revision
FPCOldBugId
FPCTarget
Attached Files
  • longint.equals.string.operator.overload.diff (590 bytes)
    Index: compiler/htypechk.pas
    ===================================================================
    --- compiler/htypechk.pas	(revision 41788)
    +++ compiler/htypechk.pas	(working copy)
    @@ -330,6 +330,7 @@
                                  (treetyp in order_theoretic_operators)
                                ) or
                                (
    +                             (m_mac in current_settings.modeswitches) and
                                  is_stringlike(rd) and
                                  (ld.typ=orddef) and
                                  (treetyp in string_comparison_operators)) or
    

Activities

Thaddy de Koning

2016-01-21 08:12

reporter   ~0089142

Last edited: 2016-01-21 09:02

View 2 revisions

Yes, confirmed. For trunk and also for 3.0
Funny is that the operator with reversed parameter overload does work:

operator = (z1: ansistring; z2 : longint) b : boolean;
begin
  b := false;
end;

The operator in question is not already in use somewhere, because then the code would work w/o the declaration.

Bart Broersma

2019-04-03 18:22

reporter   ~0115197

The operator (left=integer, right=string) fails in
IsOperatorAcceptable:
  optoken=_EQ, count=2
  tok2node[5].tok=optoken
  ld.gettypename=LongInt, rd.gettypename=AnsiString
  tok2node[5].nod=equaln
  isbinaryoperatoroverloadable(tok2node[5].nod,ld,nothingn,rd,nothingn)=FALSE

Bart Broersma

2019-04-03 19:02

reporter   ~0115198

Last edited: 2019-04-03 19:05

View 2 revisions

in function isbinaryoperatoroverloadable
in the nested function internal_check
this block of code:

          case ld.typ of (ld.typ=orddef in this case)
....

            orddef, floatdef:
              begin
                allowed:=not (
                           (
                             (rd.typ in [orddef,floatdef]) and
                             (treetyp in order_theoretic_operators)
                           ) or
                           (
                             is_stringlike(rd) and
                             (ld.typ=orddef) and
                             (treetyp in string_comparison_operators)) or
                             { c.f. $(source)\tests\tmacpas5.pp }
                             (
                               (rd.typ=setdef) and
                               (ld.typ=orddef) and
                               (treetyp in element_set_operators)
                             )
                            { This clause may be too restrictive---not all types under
                              orddef have a corresponding set type; despite this the
                              restriction should be very unlikely to become
                              a practical obstacle, and can be relaxed by simply
                              adding an extra check on TOrdDef(rd).ordtype }
                           );
 
will set Allowed to False.

Bart Broersma

2019-04-03 23:33

reporter   ~0115209

Last edited: 2019-04-03 23:33

View 2 revisions

It seems that in MacPas mode you are allowed to do:
  if WordVariable = StringVariable
but not the other way around.
This seems to be the reason you cannot overload the operator this way (but you can the other way around).

A check for compilermode should maybe be added?

Bart Broersma

2019-04-03 23:46

reporter  

longint.equals.string.operator.overload.diff (590 bytes)
Index: compiler/htypechk.pas
===================================================================
--- compiler/htypechk.pas	(revision 41788)
+++ compiler/htypechk.pas	(working copy)
@@ -330,6 +330,7 @@
                              (treetyp in order_theoretic_operators)
                            ) or
                            (
+                             (m_mac in current_settings.modeswitches) and
                              is_stringlike(rd) and
                              (ld.typ=orddef) and
                              (treetyp in string_comparison_operators)) or

Bart Broersma

2019-04-03 23:46

reporter   ~0115210

Possible patch attached in longint.equals.string.operator.overload.diff

Bart Broersma

2019-04-07 23:23

reporter   ~0115313

Last edited: 2019-07-12 11:40

View 2 revisions

Is it even possible to do operator overloading in MacPas mode?
ETA: No.

Bart Broersma

2019-10-04 17:35

reporter   ~0118327

Some feedback on the patch would be nice.

Sven Barth

2019-10-05 10:42

manager   ~0118345

You can't do overloading in MacPas mode, but the compiler will nevertheless pick up overloads from other units that are in a mode that can. So it needs to be tested that a overload for Integer = String in a non-MacPas unit does not mess up code for a unit in mode MacPas. Probably it needs a similar check like the one I added for the + operator of dynamic arrays that is not used if the corresponding modeswitch is not set.

Bart Broersma

2019-10-05 14:18

reporter   ~0118349

Last edited: 2019-10-05 14:35

View 3 revisions

Thanks for the feedback.


Given:

-----------------
unit opovr;

{$mode objfpc}
{$H+}

interface

operator = (L: dword; R: String) z: Boolean;


implementation

operator = (L: dword; R: String) z: Boolean;
begin
  writeln('operator = (dword, string)');
  z:=False;
end;

end.

--------
program op;

uses opovr;

procedure test;
var
  d: dword;
begin
  d:=(65 shl 24) or (66 shl 16) or (67 shl 8) or 68;
  if (d<>'ABCD') then
    writeln('d <> "ABCD"')
  else
    writeln('d = "ABCD"');
end;


begin
  test;
end.

With patched (longint.equals.string.operator.overload.diff) fpc:

C:\Users\Bart\LazarusProjecten\bugs\Console\operator>fpc op.lpr
Free Pascal Compiler version 3.3.1 [2019/10/05] for i386
Copyright (c) 1993-2018 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling op.lpr
Linking op.exe
27 lines compiled, 0.0 sec, 28704 bytes code, 1316 bytes data

C:\Users\Bart\LazarusProjecten\bugs\Console\operator>op
operator = (dword, string)
d <> "ABCD"

C:\Users\Bart\LazarusProjecten\bugs\Console\operator>fpc -Mmacpas op.lpr
Free Pascal Compiler version 3.3.1 [2019/10/05] for i386
Copyright (c) 1993-2018 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling op.lpr
Linking op.exe
27 lines compiled, 0.1 sec, 70640 bytes code, 4292 bytes data

C:\Users\Bart\LazarusProjecten\bugs\Console\operator>op
d = "ABCD"

So in MacPas mode the operator overload from unit opovr is not picked up, which is what we want.

Trying to build the program clean however fails:

C:\Users\Bart\LazarusProjecten\bugs\Console\operator>fpc -B -Mmacpas op.lpr
Free Pascal Compiler version 3.3.1 [2019/10/05] for i386
Copyright (c) 1993-2018 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling op.lpr
Compiling opovr.pp
opovr.pp(3,2) Error: Mode switch "OBJFPC" not allowed here

Is that expected, or a new error introduced by my patch?

Bart Broersma

2019-10-06 12:40

reporter   ~0118371

> Is that expected, or a new error introduced by my patch?
Well I should have investigated that myself.
This seems to be existing behaviour (tested with 3.0.4). You cannot build something with -MMacpas if some other unit has {$mode ObjFcp} (only tested that mode).

Issue History

Date Modified Username Field Change
2016-01-21 02:18 Ondrej Pokorny New Issue
2016-01-21 08:12 Thaddy de Koning Note Added: 0089142
2016-01-21 09:02 Thaddy de Koning Note Edited: 0089142 View Revisions
2019-04-03 18:22 Bart Broersma Note Added: 0115197
2019-04-03 19:02 Bart Broersma Note Added: 0115198
2019-04-03 19:05 Bart Broersma Note Edited: 0115198 View Revisions
2019-04-03 23:33 Bart Broersma Note Added: 0115209
2019-04-03 23:33 Bart Broersma Note Edited: 0115209 View Revisions
2019-04-03 23:46 Bart Broersma File Added: longint.equals.string.operator.overload.diff
2019-04-03 23:46 Bart Broersma Note Added: 0115210
2019-04-07 23:23 Bart Broersma Note Added: 0115313
2019-07-12 11:40 Bart Broersma Note Edited: 0115313 View Revisions
2019-10-04 17:35 Bart Broersma Note Added: 0118327
2019-10-05 10:42 Sven Barth Note Added: 0118345
2019-10-05 14:18 Bart Broersma Note Added: 0118349
2019-10-05 14:35 Bart Broersma Note Edited: 0118349 View Revisions
2019-10-05 14:35 Bart Broersma Note Edited: 0118349 View Revisions
2019-10-06 12:40 Bart Broersma Note Added: 0118371