![]() |
Delphi 12: Enum Value to Record per Implicit-Operator ist kaputt
Hallo zusammen,
ich bin gerade dabei Delphi 12 zu installieren und einzurichten und bin über ein Stück Code in unserer Software gestolpert, welches Probleme bereitet. Anscheinend hat der Compiler eine Regression erfahren. Der Original-Code mappt einen Enumerationstyp (im Beispiel unten
Delphi-Quellcode:
) mit weit über 256 Elementen in ein Hilfs-Record, welches ein
TMyEnum
Delphi-Quellcode:
ersetzt (weil eine Menge nicht mehr als 256 Elemente aufnehmen kann).
Set of TMyEnum
Im Beispiel sind es weniger Enum-Elemente, weil es für das Problem egal ist. Dieses Stückchen Quelltext hat im Laufe der Jahre (eher Jahrzehnte) gut funktioniert. Ein leeres Array mit [] wird dem Record zugewiesen und per Implicit-Operator wird es intern umgewandelt. Siehe
Delphi-Quellcode:
im unteren Beispiel.
procedure Main
In Delphi 11.3 funktioniert das zuweisen per Implicit-Operator sehr schön ohne Probleme. In Delphi 12 bekomme ich im
Delphi-Quellcode:
einen
procedure TMyEnumWrapper.Create(const a: array of TMyEnum);
Delphi-Quellcode:
bei Auswertung des Low()/High().
ERangeError
Wie seht ihr das, sollte ich einen Bug im Emba Jira anlegen?
Delphi-Quellcode:
program EnumToRecordImplicitBroken;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type TMyEnum = (entry_1, entry_2, entry_3, entry_4, entry_5, entry_6, entry_7, entry_8, entry_9, entry_10, entry_11, entry_12, entry_13, entry_14, entry_15, entry_16, entry_17, entry_18, entry_19, entry_20, entry_21, entry_22, entry_23, entry_24, entry_25, entry_26, entry_27, entry_28, entry_29, entry_30, entry_31, entry_32, entry_33, entry_34, entry_35, entry_36, entry_37, entry_38, entry_39, entry_40, entry_41, entry_42, entry_43, entry_44, entry_45, entry_46, entry_47, entry_48, entry_49, entry_50, entry_51, entry_52, entry_53, entry_54, entry_55, entry_56, entry_57, entry_58, entry_59, entry_60, entry_61, entry_62, entry_63, entry_64, entry_65, entry_66, entry_67, entry_68, entry_69, entry_70, entry_71, entry_72, entry_73, entry_74, entry_75, entry_76, entry_77, entry_78, entry_79, entry_80, entry_81, entry_82, entry_83, entry_84, entry_85, entry_86, entry_87, entry_88, entry_89, entry_90, entry_91, entry_92, entry_93, entry_94, entry_95, entry_96, entry_97, entry_98, entry_99, entry_100, entry_101, entry_102, entry_103, entry_104, entry_105, entry_106, entry_107, entry_108, entry_109, entry_110, entry_111, entry_112, entry_113, entry_114, entry_115, entry_116, entry_117, entry_118, entry_119, entry_120, entry_121, entry_122, entry_123, entry_124, entry_125, entry_126, entry_127, entry_128, entry_129, entry_130, entry_131, entry_132, entry_133, entry_134, entry_135, entry_136, entry_137, entry_138, entry_139, entry_140, entry_141, entry_142, entry_143, entry_144, entry_145, entry_146, entry_147, entry_148, entry_149, entry_150, entry_151, entry_152, entry_153, entry_154, entry_155, entry_156, entry_157, entry_158, entry_159, entry_160, entry_161, entry_162, entry_163, entry_164, entry_165, entry_166, entry_167, entry_168, entry_169, entry_170, entry_171, entry_172, entry_173, entry_174, entry_175, entry_176, entry_177, entry_178, entry_179, entry_180, entry_181, entry_182, entry_183, entry_184, entry_185, entry_186, entry_187, entry_188, entry_189, entry_190, entry_191, entry_192, entry_193, entry_194, entry_195, entry_196, entry_197, entry_198, entry_199, entry_200); TMyEnumWrapper = record FMyEnumSet: array [0 .. (Ord(High(TMyEnum)) div 32) + 1] of Cardinal; function ToString: string; procedure IndexOf(const a: TMyEnum; out Index: Integer; out Mask: Cardinal); inline; procedure SetItem(const a: TMyEnum); inline; procedure Create(); overload; procedure Create(const a: TMyEnum); overload; procedure Create(const a: array of TMyEnum); overload; class operator Implicit(const a: array of TMyEnum): TMyEnumWrapper; overload; class operator Implicit(const a: TMyEnum): TMyEnumWrapper; overload; class operator In (const a: TMyEnum; const b: TMyEnumWrapper): Boolean; end; class operator TMyEnumWrapper.Implicit(const a: array of TMyEnum): TMyEnumWrapper; begin // in Delphi 12 ist das im Local Variables Window ein "Inaccessible value" -> da fängt der Fehler schon an // in Delphi 11.3 steht im Local Variables Window ein "()" -> richtig und schön Result.Create(a); end; procedure TMyEnumWrapper.Create; begin FillChar(Self, sizeof(TMyEnumWrapper), 0); end; procedure TMyEnumWrapper.Create(const a: array of TMyEnum); var i: Integer; begin Create(); for i := Low(a) to High(a) do begin SetItem(a[i]); end; end; procedure TMyEnumWrapper.Create(const a: TMyEnum); begin Create(); SetItem(a); end; class operator TMyEnumWrapper.Implicit(const a: TMyEnum): TMyEnumWrapper; begin Result.Create(); end; class operator TMyEnumWrapper.In(const a: TMyEnum; const b: TMyEnumWrapper): Boolean; var i: Integer; m: Cardinal; begin b.IndexOf(a, i, m); Result := (b.FMyEnumSet[i] and (m)) <> 0; end; procedure TMyEnumWrapper.IndexOf(const a: TMyEnum; out Index: Integer; out Mask: Cardinal); var i: Integer; begin i := Ord(a); Index := (i div 32); Mask := $01 shl (i - (Index * 32)); // Maske (Bit) end; procedure TMyEnumWrapper.SetItem(const a: TMyEnum); var i: Integer; m: Cardinal; begin IndexOf(a, i, m); FMyEnumSet[i] := (FMyEnumSet[i] or m); end; function TMyEnumWrapper.ToString: string; var i: Integer; begin Result := ''; for i := 0 to Length(self.FMyEnumSet) - 1 do begin if (Result <> '') then Result := Result + ', '; Result := Result + Ord(FMyEnumSet[i]).ToString; end; end; procedure Main; var MyEnumWrapperVar: TMyEnumWrapper; begin MyEnumWrapperVar := []; Writeln(MyEnumWrapperVar.ToString); end; begin try Main; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; readln; end. |
AW: Delphi 12: Enum Value to Record per Implicit-Operator ist kaputt
Wichtiger Hinweis fehlt: Passiert nur bei Target = Win64!
|
AW: Delphi 12: Enum Value to Record per Implicit-Operator ist kaputt
Ja, stimmt! Guter Hinweis.
Ich debugge meistens in der Zielplattform Win64. Das Problem muss irgendwie mit dem Implicit-Operator zu tun haben, denn eine reine Funktion geht ohne Probleme in 64-Bit.
Delphi-Quellcode:
function Convert(const a: array of TMyEnum): TMyEnumWrapper;
begin Result.Create(a); end; |
AW: Delphi 12: Enum Value to Record per Implicit-Operator ist kaputt
Da haben sie wohl beim open array 64-bit machen ne Stelle im Compiler vergessen.
Reported: ![]() |
AW: Delphi 12: Enum Value to Record per Implicit-Operator ist kaputt
Zitat:
@Alle: Bitte für den RSP voten! :thumb: |
AW: Delphi 12: Enum Value to Record per Implicit-Operator ist kaputt
Abgestimmt!
Ich bin ja sowas von beunruhigt, daß die bei Embarcadero Unit Tests nicht besser machen als ich. |
AW: Delphi 12: Enum Value to Record per Implicit-Operator ist kaputt
Hier die generierten Debug Win64 Disassembler-Views zwischen begin und end des TRec.Implicit-Operators.
Sieht schon blöd anders aus unterhalb der for-Schleife.
Delphi-Quellcode:
// Delphi 11.3
SteviesExample.dpr.20: begin 000000000042BC50 55 push rbp 000000000042BC51 4883EC10 sub rsp,$10 000000000042BC55 488BEC mov rbp,rsp 000000000042BC58 895528 mov [rbp+$28],edx SteviesExample.dpr.24: for i := Low(values) to High(values) do 000000000042BC5B 33C0 xor eax,eax 000000000042BC5D 8B4D28 mov ecx,[rbp+$28] 000000000042BC60 894508 mov [rbp+$08],eax 000000000042BC63 394D08 cmp [rbp+$08],ecx 000000000042BC66 7F10 jnle TRec.&op_Implicit + $28 000000000042BC68 2BC8 sub ecx,eax 000000000042BC6A 83C101 add ecx,$01 SteviesExample.dpr.28: end; 000000000042BC6D 83450801 add dword ptr [rbp+$08],$01 SteviesExample.dpr.24: for i := Low(values) to High(values) do 000000000042BC71 83E901 sub ecx,$01 000000000042BC74 85C9 test ecx,ecx 000000000042BC76 75F5 jnz TRec.&op_Implicit + $1D 000000000042BC78 90 nop SteviesExample.dpr.31: end; 000000000042BC79 8B450C mov eax,[rbp+$0c] 000000000042BC7C 488D6510 lea rsp,[rbp+$10] 000000000042BC80 5D pop rbp 000000000042BC81 C3 ret // Delphi 12 SteviesExample.dpr.20: begin 000000000042C4C0 55 push rbp 000000000042C4C1 4883EC30 sub rsp,$30 000000000042C4C5 488BEC mov rbp,rsp 000000000042C4C8 48895548 mov [rbp+$48],rdx SteviesExample.dpr.24: for i := Low(values) to High(values) do 000000000042C4CC 488B4548 mov rax,[rbp+$48] 000000000042C4D0 B900000080 mov ecx,$80000000 000000000042C4D5 488D0C01 lea rcx,[rcx+rax] 000000000042C4D9 BAFFFFFFFF mov edx,$ffffffff 000000000042C4DE 483BCA cmp rcx,rdx 000000000042C4E1 7605 jbe TRec.&op_Implicit + $28 000000000042C4E3 E8E8B8FDFF call @BoundErr 000000000042C4E8 33C9 xor ecx,ecx 000000000042C4EA 894D28 mov [rbp+$28],ecx 000000000042C4ED 394528 cmp [rbp+$28],eax 000000000042C4F0 7F10 jnle TRec.&op_Implicit + $42 000000000042C4F2 2BC1 sub eax,ecx 000000000042C4F4 83C001 add eax,$01 SteviesExample.dpr.28: end; 000000000042C4F7 83452801 add dword ptr [rbp+$28],$01 SteviesExample.dpr.24: for i := Low(values) to High(values) do 000000000042C4FB 83E801 sub eax,$01 000000000042C4FE 85C0 test eax,eax 000000000042C500 75F5 jnz TRec.&op_Implicit + $37 000000000042C502 90 nop SteviesExample.dpr.31: end; 000000000042C503 8B452C mov eax,[rbp+$2c] 000000000042C506 488D6530 lea rsp,[rbp+$30] 000000000042C50A 5D pop rbp 000000000042C50B C3 ret |
AW: Delphi 12: Enum Value to Record per Implicit-Operator ist kaputt
Könnte das damit zusammenhängen?
Die Stichwörter sind alle da: ![]() Zitat:
|
AW: Delphi 12: Enum Value to Record per Implicit-Operator ist kaputt
|
AW: Delphi 12: Enum Value to Record per Implicit-Operator ist kaputt
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:52 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz