![]() |
|||||||||||||||||
|
|
|||||||||||||||||
|
|
|||||||||
|
Delphi |
DELPHI DEVELOPER SUPPORT
Areas of concentration under: compiler
Area: compiler\delphi Problem: In investigating the previous problem I caused an interal compiler error E4129. Steps:
1) The code
interface
procedure AProcedure(const IA: array of integer;
const IB: array of integer; SA: array of string; B:
integer);overload;
implementation
procedure AProcedure(const IA: array of integer;
const IB: array of integer; SA: array of string; B:
integer);
begin
{ body of procedure }
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
AProcedure([1, 2],['One', 'Two'], 3); // Kills
compiler here
end;
2) the error.
[Fatal Error] Unit1.pas(45): Internal error: E4129
Area: compiler\delphi Problem: Type information is generated in illogical manner for Cardinals. Cardinals are now true unsigned 32-bit numnbers with a range from 0 to 4G-1 However the compiler still generates type information for them as if they were implemented as signed longs Area: compiler\delphi Problem: The follow code gives an incorrect compiler error. When a procedure is declare as overloaded and it is declared as taking two const arrays the 1st of integer and the second of type string and an integer. If no other procedure is supplied with a similar partial parameter list you get an erroneous error message Steps:
1) Add the following code
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~
procedure AProcedure(const IA: array of integer;
SA: array of string; B: integer);overload;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure AProcedure(const IA: array of integer;
{const IB: array of integer;} SA: array of string; B:
integer);
begin
{Nothing needed here }
end;
procedure TForm1.Button1Click(Sender: TObject);
var StrArray: Array[0..1] of string;
begin
AProcedure([1, 2],['One', 'Two'], 3); // Call 1
This causes the error
StrArray[0] := 'One';
StrArray[1] := 'Two';
AProcedure([1, 2], StrArray, 3); // Call 2
NOTE the compiler does not barf on this???
end;
2)
the error messages:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~
[Error] Unit1.pas(45): Ordinal type required
[Error] Unit1.pas(45): There is no overloaded
version of 'AProcedure' that can be called with
these arguments
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~
the > > Ordinal type required < < < Messages
is the wierd one??
Comments:
1) adding another procedure:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~
procedure AProcedure(const A: string; SA: array of
string); overload; // Dummy procedure
procedure AProcedure(const A: string; SA: array of
string);
begin
{ nothing }
end;
Area: compiler\delphi Problem: Compiler allows double hash-sign within string constant. eg. S := ##13; is equivalent to S := #0#13; I found this accidentally. I was intending to write #13 and typed ##13 instead. It compiled, but didn't give the result I expected. Steps:
procedure TForm1.Button1Click(Sender: TObject);
var
S : string;
begin
S := ##13;
if S = #0#13 then // condition is true
Caption := 'Same';
end;
Area: compiler\delphi Problem: Result fails to return string value assigned to it when it's a record type Steps:
1. Create a new application.
2. Paste the GetMyRecord function below into the
implementation section of the unit.
3. Paste the following declaration for TMyRecord
into the type clause of the unit.
4. Drop a button on the form apply button click
code below to the onclick event.
5. Run and click the button, the string being
returned is blank.
type
TMyRecord = record
MyString : Ansistring;
end;
function GetMyRecord : TMyRecord;
begin
Result.MyString := 'You will not see this';
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Showmessage(GetMyRecord.MyString);
end;
The compiler seems to be applying the rule for
functions returning 4-byte sized records, i.e.,
function result is returned in EAX. However, it
should be applying the rule for AnsiStrings,
WideStrings, etc.: the result is returned in an implicit
var param passed to the function. If you change
MyString's type to be ShortString everything works
fine.
Area: compiler\delphi Problem: Add a keyword SHAREDVAR to declare shared variables. Similar in spirit to THREADVAR, SHAREDVAR declarations can be at the unit level only. Variables that are declared with SHAREDVAR instead of VAR are shared across all applications and DLLs that use the enclosing unit. Area: compiler\delphi\basm Problem: Note that this is a change in behavior from Delphi 3. Certain arithmetic combinations seem to produce unexpected results in code. Area: compiler\delphi\basm Problem: BASM doesn't appear to support MMX extensions. Area: compiler\delphi\basm Problem: The instruction asm jcxz @1 @1: has bad encoding. An address size override ($67) is emitted before the instruction. It appears to be harmless but shouldn't be there. Area: compiler\delphi\basm Problem: BASM parser accepts syntax that must cause an error. Steps: Encode the following in a Delphi program. asm lea ecx,[eax + ebx + ecx + edx + esi + edi] end; Once compiled, you will see that the code for the following instruction is generated. lea ecx, [eax + edi] Area: compiler\delphi\basm Problem: The compiler accepts asm imul bl,cl which is not a valid instruction Note from edj: If this is as-designed, it seems that if the compiler is going to do magic, it should do it a little smarter. It would be safer to translate to: 660FAFD9 imul bx,cx Steps: dcc32 -cc dcc31400.pas td32 dcc31400.exe View|CPU Notice that: asm imul bl, cl end; Has been translated (magically) to: 0FAFD9 imul ebx,ecx Area: compiler\delphi\basm Problem: BASM supports incorrect coding for SLDT and SMSW. Steps:
begin
asm
SLDT ecx
end;
end;
generates the code for SLDT CX which the
disassembler displays as expected.
This is a corner case as these instructions are of no
practical use to applications programmers.
And from reading the newsgroups encoding for
INVLPG is also suspect though also equally not
useful.
Area: compiler\delphi\code generation\optimization Problem: Guid constants assigned an empty string, as in const IID : TIID = ''; are not initialized to all zeros (not equal to GUID_NULL). Steps:
uses
ActiveX;
procedure Form1.FormCreate(Sender: TObject);
const
IID : TIID = '';
begin
if not IsEqualIID(IID, GUID_NULL) then
Beep
end;
Area: compiler\delphi\code generation\optimization Problem: Having the following in the implementation of Form1 crashes the compiler (AV in DCC.DLL): var i : (i1, i2) = i1; A workaround is of course to have a type (ti = (i1, i2)). Area: compiler\delphi\code generation\optimization Problem:
This program and unit, when compiled with Delphi 3
will cause an internal URW376 error followed by an
AV in DFWEDIT.DLL.
{URW376.DPR}
program URW376;
uses
URW376U;
begin
InterfacedRoutine;
end.
{URW376U.PAS}
unit URW376U;
{With these compiler options turned off (ie, set to -),
compiling with
Delphi 3 causes a fatal error ("Internal error
URW376"). Turning them
on (ie, set to +) the unit will compile perfectly}
{$D-,L-}
interface
procedure InterfacedRoutine;
implementation
procedure LocalRoutine;
type
TMyEnum = (Zero, One, Two);
const
MyEnumArray : array [TMyEnum] of char = ('0', '1',
'2');
begin
end;
procedure InterfacedRoutine;
begin
LocalRoutine;
end;
end.
Area: compiler\delphi\code generation\optimization Problem: If an application declares a typed constant that is a wide string, the application does terminate correctly. This occurs NT4. Steps: Declare a constant like: const wtext : widestring = '123'; Area: compiler\delphi\code generation\optimization Problem: With a default parameter of set type, compilation causes internal error URW527 (syntax check works fine, instead). After this error loading and compiling other projects results in memory errors in Delphi packages, and eventually a system crash. Steps:
1. Add the following to a unit:
function MyMsg (const Msg: string;
AButtons: TMsgDlgButtons = [mbOK]): Word;
begin
Result := MessageDlg (Msg, mtInformation,
AButtons, 0);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
MyMsg ('Hello');
end;
2. Compile: gives error
3. load and run another project: bad error!
Area: compiler\delphi\code generation\optimization Problem: The attached project causes Internal Error L511 upon compile. The problem appears to stem from the fact that the two units within the project reference each other in the implementation section. Steps: 1. Compile the attached project. // Internal Error L511 occurs Area: compiler\delphi\code generation\optimization Problem: In Delphi, this causes the dataset designer to AV when when creating persistent fields. Steps: Build or install the 4.01 inline. Make sure the DB dictionary/repository is setup. Drop a TTable and connect it to customer.db. Bring up the fields editor. Add all fields. // Note the AV. Area: compiler\delphi\code generation\optimization Problem: The compiler generates initialization and finalization code for units where it is not required. This tends to cause the OS to page fault when loading a Delphi application thus causing lots of 4kb pages to be loaded making the footprint of the application very large. There has been an extensive thread on the private newsgroup concerning this issue. The following code was posted in response to this issue to help reduce the working set size of any Delphi application: procedure TrimWorkingSet; var MainHandle : THandle; begin MainHandle := OpenProcess(PROCESS_ALL_ACCESS, false, GetCurrentProcessID); SetProcessWorkingSetSize(MainHandle,-1,-1); CloseHandle(MainHandle); end; Steps: The code mentioned in Description can reduce the memory footprint of the IDE by 40%. Area: compiler\delphi\code generation\optimization Problem: A C788 internal error. Area: compiler\delphi\code generation\optimization Problem:
The Delphi 3.02 linker is a bit too clever when
removing symbols.
It also has a severe code generation bug (the
compiler may be involved
too - I just don't care, since the net effect is the
same)
In a nutshell, if one tries to FLD (BASM) data that
has been declared
using the absolute directive, then bad code is
generated. This will
make the application crash at runtime with access
violations.
You will get an access violation (in this case a
Runtime Error 216,
otherwise an exception EAccessViolation) on
execution of
fld test1
This is because the first few lines of assembler code
look like this
fld test1
0052768C: DD0502504A30 FLD QWORD PTR
[+02504A30]
fld test2
00527692: DD0500528884 FLD QWORD PTR
[+00528884]
[my applications are always based at $500000]
First result:
-------------
Clearly [+02504A30] looks a bit like garbage (and
it is plain
wrong, of course)... This explains the crash, since
$2504A30
is way beyond reach for this application.
Second result:
--------------
Run the code as shown above up to the first FLD
(breakpoint
or single-step).
Have tooltip expression or "Evaluate" tell you
that:
test1 -- > "Symbol was eliminated by linker"
"Touching" the Constant variable, e.g. Constant[1]
:= 0;, does
apparently make the linker sort of include "test1",
but does _NOT_
remove the crash (!).
Even worse, touching the Test1 variable, e.g.
Test1 := 0;, does not
change this behaviour, either.
The only solution to this problem is to have the
absolute declaration
turned around, e.g.
Test3: double = 0;
Constant2: array[1..8] of byte absolute Test3;
Steps:
Found on the delphi.basm newsgroup:
{$A+,B-,C+,D+,E-,F-,G+,H+,I+,J+,K-,L+,M-,N+,O+,P
+,Q+,R+,S-,T+,U-,V+,W-,X+,Y+,Z1}
unit TestMe;
interface
implementation
var
Constant: array[1..8] of byte;
Test1: double absolute Constant;
Test2: double = 0;
procedure RunMe;
asm
fld test1
fld test2
fstp st(0)
fstp st(0)
end;
initialization
RunMe;
end.
Area: compiler\delphi\code generation\optimization Problem: The compiler currently allows declaration of class properties, i.e. properties where both the read and write methods are class methods. However, there is no straigtforward way to access such a property. It is possible, but you have to do weird type casts (see the example code). Also accessing such a property in the natural way (with Instance.Property) will cause Access Violations if the class methods access the VMT in anyway (i.e. use the implied Self: TClass parameter). Steps:
1. Create a new application project
2. Drop a button on the form
3. Double-click the button to add an event handler
4. Add the following code:
type
TClassProp = class(TObject)
private
FValue: integer;
class function GetValue: integer;
class procedure SetValue(Value: integer);
public
// D3 and Allegro actually supports declaring
class properties..
property Value: integer read GetValue write
SetValue; // This compiles, but no easy way to
access it
property Value1: integer read FValue write
SetValue; // This compiles, but does not make
much sense!?
property Value2: integer read GetValue write
FValue; // This compiles, but does not make much
sense!?
end;
var
TClassProp_Value: integer;
implementation
class function TClassProp.GetValue: integer;
begin
// Self could be a VMT or a object instance ptr
here
Result := TClassProp_Value;
// Try to use the VMT, this will crash when Self is
an object
// instance instead of a class reference
ShowMessage(Format('%s.GetValue = %d',
[Self.Classname, Result]));
end;
class procedure TClassProp.SetValue(Value:
integer);
begin
TClassProp_Value := Value;
// Try to use the VMT, this will crash when Self is
an object
// instance instead of a class reference
ShowMessage(Format('%s.SetValue(%d)',
[Self.Classname, Value]));
end;
procedure TForm4.Button1Click(Sender: TObject);
var
CP: TClassProp;
begin
// But D3/Allegro does not support accessing
them directly through a class-reference
// This does not compile
// TClassProp.Value := 3; // Method identifier
expected
// writeln(TClassProp.Value); // Method identifier
expected
// This compiles and runs as expected!! - Special
syntax for accessing class properties through a
class reference
TClassProp(TClassProp).Value := 1;
ShowMessage(Format('TClassProp(TClassProp).Val
ue = %d', [TClassProp(TClassProp).Value]));
// This compiles and runs ok
CP := TClassProp.Create;
TClassProp(CP.ClassType).Value := 2;
ShowMessage(Format('TClassProp(CP.ClassType).
Value = %d', [TClassProp(CP.ClassType).Value]));
// Compiles, but crashes with an AV if methods
access the VMT
// This is caused by Self being an object instance,
not a class reference
// To work around this the compiler should
convert Self from a TObject to a TClass!
CP.Value := 3;
ShowMessage(Format('CP.Value = %d',
[CP.Value]));
end;
Area: compiler\delphi\code generation\optimization Problem: The following code makes the compiler AV in DCC.DLL: var V : array [0..1] of Variant; begin Initialize(V); end. Area: compiler\delphi\code generation\optimization Problem:
The following inline assembly will cause an AV in
DCC40.DLL during compile time:
asm
mov ebx,[ClientWidth]
end;
Steps:
1. File | New App
2. In the OnCreate for instance, put this code:
asm
mov ebx,[ClientWidth]
end;
3. Compile, and BOOM!
Area: compiler\delphi\code generation\optimization Problem: A writeln after an exception causes an unexpected access violation in the IDE. Steps:
the following code in Unit1.pas.
constructor TFoo.CreateNew;
begin
Writeln('In TFoo.CreateNew'); // Set Breakpoint
here
raise EMyException.Create('Will this be seen?');
Writeln('Out Foo.CreateNew'); //Statement causes
an Access Violation
end;
Set the breakpoint where specified, run and click
the button.
Step past the first WRITELN and RAISE
statements and then step through the second
WRITELN.
See the Access Violation appear.
Area: compiler\delphi\code generation\optimization Problem:
When using packed records and optimizations, the
code gen fails. AV in run-time.
The following is a small snippet that shows the
problem.
type
TMyRecord = packed record
C : Char;
w : Word;
end;
PTab = ^TTab;
TTab = array [1..10] of TMyRecord;
var
Tab1, Tab2 : PTab;
procedure TForm1.Button1Click(Sender: TObject);
var
i : Integer;
begin
New(Tab1);
New(Tab2);
for i:=1 to 10 do
Tab2^[i]:=Tab1^[i]; { This AVs }
end;
Steps: 1. File | New app 2. Drop a button down, and add an event handler for OnClick 3. Cut and paste the code from the description into your app. 4. Run and hit the button Area: compiler\delphi\code generation\optimization Problem: Sorry, this is hard core assembler programming, but nevertheless a code generation bug: Both D2 and D3 (and probably D4, too) generate wrong code for this instruction: asm mov es, word ptr es:[$2c] end; The binary code generated is: 66 26 8E 05 2C 00 E8 D5 which the built-in CPU window (correctly!) disassembles to mov es, es:[$D5E8002C] ; the "word ptr" is implicit [ The "D5 E8" comes from an immediately following relative jump (E8 < offset > ). ] TASM 5.2b on the other hand assembles the above instruction to: 67 26 8E 06 00 2C ; shouldn't that be "2C 00"? which (surprisingly < g > ) translates to "MOV ES, ES:[+002C]" Obviously, Delphi 2/3 incorrectly generate an _operand size_ prefix ($66 - documented to be optional, BTW) instead of an _address size_ prefix ($67) for this instruction. Steps: Assemble with BASM asm mov es, word ptr es:[$2c] end; and disassemble it again with any working disassembler (the CPU window, TD32, anything) Area: compiler\delphi\error recovery Problem: Internal error URW882 is reported when compiling a unit which defines a constant using SizeOf. See the test unit below for a simple example. unit Test; interface uses Sysutils; function PtrNew(Size: longint; ZeroIt: boolean): pointer; implementation const MemSizeSize = sizeof(integer); // < -- This line causes the error function PtrNew(Size: longint; ZeroIt: boolean): pointer; begin Inc(PChar(Result), MemSizeSize); end; end. Area: compiler\delphi\error recovery Problem: Duplicating the uses keyword causes the compiler to report that it could not compile the unit it says just compiled. (not a typo) Steps: dcc32 -cc a.pas Result: A.PAS(2) Error: Identifier expected but 'USES' found B.PAS(5) A.PAS(3) Fatal: Could not compile used unit 'b.pas' Expected result: If the compiler shows that it got to B.PAS(5) (the last line of B.PAS) with no errors, it should not say it couldn't compile the unit Area: compiler\delphi\errors and warnings Problem: Internal Compiler error L1086 on line: TInternalError = type TObject; Area: compiler\delphi\errors and warnings Problem: The hint "Overriding virtual method 'b.y' has a lower visibility than base class 'b'" is ambiguous. Can we improve it to include which sections the two methods are declared in? Steps: Example: Method 'descendant.foo', declared as 'private' lowers the visibility of 'ancestor.foo' which is declared 'public' Area: compiler\delphi\errors and warnings Problem: When the compiler encounters the error "Unsatisfied forward or external declaration" it can cause a bogus file open error message if the file with the error is not in the directory of the currently open project. Area: compiler\delphi\errors and warnings Problem: Code generates internal compiler error C1127 Steps:
compile the console applicaion code below:
(delphi 4, newest patch applied)
===================================
{$A+,B-,C+,D+,E-,F-,G+,H+,I+,J+,K-,L+,M-,N+,O+,P
+,Q+,R+,S-,T+,U-,V+,W-,X+,Y+,Z1}
{$MINSTACKSIZE $00004000}
{$MAXSTACKSIZE $00100000}
{$IMAGEBASE $00500000}
{$APPTYPE CONSOLE}
program Project1;
uses
Windows;
procedure BugMe;
asm int 3 end;
asm aas end; // error here
begin
BugMe;
end.
Area: compiler\delphi\errors and warnings Problem: Invalid procedure or function declaration produces compiler error rather than diagnostic. Steps: Start with a new project. Define a procedure within Fom1, private section (really doesn't matter): procedure test(x: integer; y:integer;); Compile The incorrect ';' causes a compiler termination with message 'Error, expected an identifier' rather than an error diagnostic. Area: compiler\delphi\errors and warnings Problem: Casting an integer to string doesn't cause compiler error. User may expect it to work like IntToStr, but it causes a AV at runtime. Area: compiler\delphi\execution Problem: Putting Strings inside plain objects fail inside of Init Constructors causing Av's at runtime. Steps:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
pListNode = ^ListNode;
ListNode = object
public
Foo: string;
Bar: string[20];
constructor Init;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
constructor ListNode.Init;
begin
foo := 'one'; {This is the offending line - causes
A.V.}
// foo := Form1.Name; {This also fails}
Bar := 'eye';
end;
procedure TForm1.FormCreate(Sender: TObject);
var
ln: ListNode;
begin
//ln.Foo := 'foo'; {This does not fail}
New(pListNode, Init);
end;
end.
Area: compiler\delphi\execution Problem: A class with a dynamic constructor created through a class reference variable will cause an access violation. The problem is that the compiler is generating a call to CallDynaInst (you can find this routine in the System.pas file, called _CallDynaInst). The code should be generated as CallDynaClass, which assumes that the EAX register then contains the VMT address instead of a pointer to the VMT address (as would be the first pointer in an instantiated class). Area: compiler\delphi\execution Problem:
The following project crashes the compiler
DCC.DLL at address 00831F2D for read of
FFFFFFFF.
UNIT1.PAS and DFM
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls,
Forms, Dialogs,
Unit3, Unit2;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
var
AOBject: TObject;
begin
AObject := TUnary.Create(utMinus);
end;
end.
object Form1: TForm1
Left = 418
Top = 159
Width = 696
Height = 480
Caption = 'Form1'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
end
========================================
============
UNIT2.PAS
unit Unit2;
interface
uses Unit3;
type
TUnary = class(TObject)
private
FTest : TUnary;
public
constructor Create(UT : TUnary);
end;
implementation
constructor TUnary.Create(UT : TUnary);
begin
FTest := UT;
end;
end.
========================================
=============unit Unit3;
interface
type
TUnary = (utPlus, utMinus, utInvert);
implementation
end.
Area: compiler\delphi\interaction with ui Problem: When you save a project in the IDE, a CFG file is generated to facilitate command-line compilation with the same compiler/linker options This file is not generated very reliably, so causing potential compilation failures To rememdy the problem, the programmer may have to go and edit the CFG file manually which is a bit of a chore since this file presumably gets regenerated by the IDE whenever the project is saved Steps: Create a pair of directories on your C: drive called "C:\EXE Bin" and "C:\DCU Bin" Make a new project in Allegro Choose Project | Options... | Directories\Conditionals Set the Output directory to be C:\Exe Bin Set the Unit output directory to be C:\DCU Bin Set the BPL output directory to be C:\Exe Bin Set the DCP output directory to be C:\DCU Bin Save the project as DCC32Test This causes these command-line switches (amongst others) to be stored in DCC32Test.CFG: -Ec:\Temp\Exe Bin -Nc:\Temp\DCU Bin -LEc:\Temp\Exe Bin -LNc:\Temp\DCU Bin Notice the lack of quotes around the long directory names? Bring up a command prompt & navigate to where you saved the project Execute DCC32 DCC32Test.Dpr Four warnings are generated followed by a compilation failure error, due to long file names (without surrounding quotes) being misinterpreted: Warning: Invalid compiler directive: 'Bin' Warning: Invalid compiler directive: 'Bin' Warning: Invalid compiler directive: 'Bin' Warning: Invalid compiler directive: 'Bin' Unit1.pas(24) Unit1.pas(25) Error: Could not create output file 'c:\Temp\DCU\Unit1.dcu' DCC32Test.dpr(14) Area: compiler\delphi\interaction with ui Problem: The package project option to generate namespaces is ignored Steps: -Create a project with a component source module (or see attached) -Options | Linker | Generate C++ Object files ON -Include namespaces ON -Compile Area: compiler\delphi\interfaces Problem: Using the Implements property on a class results in an additional AddRef in either the delegating or delegated object. Area: compiler\delphi\interfaces Problem: An automation interface will not compile when the interface in the TLB is the same name as the unit which implements it. Also occures in D3. This probably should be allowed, but if it can't be then at lease give a compiler message that means something... Steps: Create a project. Save all. AddAutomation object to project. Name automation object Unit2 in the expert. Save as iUnit2. Compile. Receive error: "(PascalError) iUnit2.pas(9): '.' expected but ')' found." and so on.... Area: compiler\delphi\language Problem: On Dcc32.exe Command line online info layout is off. Steps: - type dcc32 on dos prompt. - You will see online info in French wich is off layout Area: compiler\delphi\language Problem: Generally, the compiler error for overloaded methods should be made stricter. It should give more errors at the declaration level for classes that contain overloaded methods that can never be called because of 'Ambiguous overloaded call' errors. These errors should be caugth at declaration level rather than at call-level. Some calls that really are ambiguous from the programmers perspective should also not be allowed. The following bug reports will contain examples of this. For all of these examples, the following steps should be performed before entering the supplied code: Steps:
1. Create a new Application project
2. Drop a button on the form
3. Double click the button and enter the following
code in the event handler:
procedure TForm1.Button1Click(Sender: TObject);
var
A: TFoo;
begin
A:= TFoo.Create;
try
A.Test;
finally
A.Free;
end;
end;
4. The follwing bug-reports will give the code
examples that define the TFoo class.
Area: compiler\delphi\language Problem: The compiler allows FUNCTION in interface but PROCEDURE in implementation. I know that I don't need to fully define a routine in the implementation section, i.e. I don't have to list parameters and function return type. But certainly function/procedure should be kept distrinct. [This is new to Delphi 4 - MD] Area: compiler\delphi\language Problem: The compiler does not allow a class parent type to be prefixed by a unit name. This makes it impossible to declare two classes in the same unit inheriting from two different classes with the same name in two different units. Steps:
1. Create a new form
2. Modify the class declaration so that it looks like
the one below
3. Note the usage of unit qualification in the class
inhertance
4. Try to compile
5. You don't get a normal compiler-error message in
the error log, but rather a modal dialog saying:
> Error
> Expected ")".
unit Unit15;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs;
type
TForm15 = class(Forms.TForm) // Note: Forms.
syntax
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form15: TForm15;
implementation
{$R *.DFM}
end.
Area: compiler\delphi\language\dynamic arrays Problem: If an attempt to allocate a 2 dimensional dynamic array raises an out of memory exception, the memory that has been allocted so far is not freed. It will not be freed until the program is exited, making it impossible to allocate any more memory. Steps:
1) Create a form with three buttons and the
following private declaration and event handlers:
type
TForm1 = class(TForm)
{ ... }
private
{ Private declarations }
FArray : array of array of double;
public
{ Public declarations }
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SetLength(Farray,1500,1500); { allocate 18 Mb
array }
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
SetLength(Farray,8000,8000); {allocate 512 Mb
array }
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
{ FArray := nil;}
Finalize(Farray);
end;
2) Run the program alongside some utility that will
show the amount of memory allocated (the NT4
Task Manager is ideal as it can show the memory
usage and VM size of each process).
3) Press the second button to allocate a 5000x5000
array of doubles (512 Mb in size). It will allocate
memory for a few seconds, then fail with a
EOutOfMemory exception (unless you've got a lot of
RAM and swap file space!).
4) Note the memory allocated as shown in the Task
Manager. The memory allocated for a portion of the
2d array so far has not been freed.
5) Click the third button, which should deallocate
the array. This has no effect and the memory isn't
deallocated until the program is exited. Any further
attempts to allocate memory, even small amounts,
will fail.
6) For comparison, click the first button which
allocates an 18Mb array. This should work OK and
the allocation will show up on the Task Manager.
Clicking the deallocate button will free the memory
and the Task Manager will show the reduced
memory allocation.
Area: compiler\delphi\language\overloading\method Problem: Combining Overloading with Default parameters can cause stack to corrupt with invalid data passed, but only when overloaded methods are declared in a specific order. Area: compiler\delphi\language\overloading\method Problem: If you have overloaded routines in a DLL, you seem only to be able to export the first one Steps:
Make a DLL like the one below. When you compile
it, the blue bullet markers, idicating code generated
appear by the first version of Foo. If you swap the
two overloaded routines around, so that they are in
the opposite order, the same occurs, in that code is
generated for the first one.
We need a mechanism to specify which one is
being exported, which is more scientific than code
positioning.
library Project1;
uses
SysUtils,
Dialogs,
Classes;
procedure Foo(A: AnsiChar); overload;
begin
ShowMessage('FooA')
end;
procedure Foo(I: Integer); overload;
begin
ShowMessage('FooI')
end;
exports
Foo;
begin
end.
Area: compiler\delphi\language\overloading\method Problem: Method overloading goes bad when Booleans are used as parameter types Steps:
Try compiling this unit. Even though the overloaded
methods are declared fine, the compiler rejects the
second call.
Changing the 40.0 to 40 makes the code compile
just fine
unit MethodOverloadUnit2;
interface
implementation
type
TFoo = class(TObject)
public
procedure Bar(B: Boolean); overload;
procedure Bar(D: Double); overload;
end; { TFoo }
procedure TFoo.Bar(B: Boolean);
begin
end;
procedure TFoo.Bar(D: Double);
begin
end;
var
Foo: TFoo;
begin
Foo := TFoo.Create;
Foo.Bar(40.0); //Compiler complains:
"Incompatible types: 'Boolean' and 'Real'"
Foo.Free
end.
Area: compiler\delphi\language\overloading\method Problem: Cannot override an overloaded method when the immediate ancestor does not also override ALL overloaded methods. Steps:
Try to compile the following code, not the error
compiling class C. However, if you change class C
to inherit from class B2, then it works.
type
A = class
protected
procedure Foo(X: integer); overload; virtual;
procedure Foo(const S: string); overload; virtual;
end;
B = class(A)
protected
procedure Foo(X: integer); override;
end;
B2 = class(A)
protected
procedure Foo(X: integer); overload; override;
procedure Foo(const S: string); overload;
override;
end;
C = class(B)
protected
procedure Foo(const S: string); override;
end;
Area: compiler\delphi\language\overloading\method Problem: tighten up overloading rules, and introduce a new compiler error with the message: "Method < identifier > with ambiguous parameters already exists)" Replaceing "Ambiguous overload call to ..." Steps:
You should define very clearly what parameter
types are considered unique with respect to define
new signatures for overloaded methods.
These rules should be based on single, simple goal:
"There should be no possible ambiguity when
calling overloaded methods with constant
expressiosn".
With this in mind, there should be only a few groups
of parameter types that will be considered unique.
For instance all integer-types would map to the
same group, so that even declaring two methods
with integer-type parameter at the same position
would be illegal. For instance, currently this
compiles:
type
TFoo = class
public
procedure Bar(A: integer); overload;
procedure Bar(A: byte); overload;
end;
Calling Bar with a constant expression, as in :
Foo.Bar(1);
is clearly ambiguous, so these declaration should be
disallowed altogether.
Introduce a new compiler error with the message:
"Method < identifier > with ambiguous
parameters already exists)"
This message should apply to by aliasing the
following types:
All string/char types:
char, string, AnsiString, shortstring, type
TString10=string[10], array of char, PChar
All integer numeric types:
byte, shortint, smallint, integer, word, cardinal,
longint, int64...
All floating-point numeric types:
comp, double, single, real...
Area: compiler\delphi\language\variants Problem: Comparing any variant whose type is varString to any other variant with type less than varByte causes an invalid variant operation. Yet all these variants can be converted to varString types. Steps:
procedure Comp(V1, V2: Variant);
begin
try
if V1 = V2 then Writeln('Equal');
except
Writeln(Format('Exception V1: %x V2: %x',
[VarType(V1), VarType(V2)]));
end;
end;
procedure Comp2(V1, V2: Variant);
var S1, S2: string;
begin
S1 := V1;
S2 := V2;
if S1 = S2 then Writeln('Equal');
end;
var
V1, V2, V3, V4, V5: Variant;
begin
V1 := 3333333;
V2 := 1.234;
V3 := '12/12/98 1:23:34 AM';
V3 := VarAsType(V3, VarDate);
V4 := 4;
V4 := VarAsType(V4, varByte);
V5 := 'aaaaa';
Comp(V1, V5);
Comp(V2, V5);
Comp(V3, V5);
Comp(V4, V5);
Comp2(V1, V5);
Comp2(V2, V5);
Comp2(V3, V5);
Comp2(V4, V5);
Readln;
end.
Area: compiler\delphi\linker Problem: Internal error L1086 caused by type declaration Steps:
unit TypeBugU;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs;
type
TForm1 = class(TForm)
end;
TInternalError = type TObject; { < < This is the
line which crashes }
var
Form1: TForm1;
implementation
{$R *.DFM}
end.
The first attempt to compile this gives:
"Fatal Error: (0): Internal error: L1086."
On subsequent compilations I get:
"Fatal Error: ...: Unit SysUtils was compiled with a
different version of System"}
Area: compiler\delphi\linker Problem: RES files with large string tables can cause an AV in RLINK32.DLL Area: compiler\delphi\make logic Problem: Compiling direct40.dpk causes internal error in the linker. This is because the version for resource strings was not initialized in CalcSymbolVersions(). Area: compiler\delphi\other compiler Problem: An Include file that includes itself will cause Delphi to hang (i.e. it is self referential) Steps:
1) Create a text file called CIRCLE.INC
2) Put the following line in it:
{$I CIRCLE.INC}
3) Put the ablove line in a Delphi applicaiton.
Area: compiler\delphi\other compiler Problem: In the PACKAGEINFO resource of an EXE bits 30-31 of the first four bytes are not correctly set to 0 - EXE, instead they are set to 3 which is undefined. Steps: 1) File | New Application 2) Save the project and MAKE it. 3) At a DOS prompt in the directory the project resides type in "tdump -v project1.exe project1.dmp" using the BCB tdump. 4) look at text file project1.dmp, at the end of the file at the binary resource PACKAGEINFO. The first four bytes should be 01 00 00 0C. Area: compiler\delphi\thread local storage Problem: setting a boolean threadvar to an expression including another threadvar yields incorrect results. Steps:
{$A+,B-,C+,D+,E-,F-,G+,H+,I+,J+,K-,L+,M-,N+,O+,P
+,Q+,R+,S-,T+,U-,V+,W-,X+,Y+
,Z1}
{$MINSTACKSIZE $00004000}
{$MAXSTACKSIZE $00100000}
{$IMAGEBASE $00400000}
{$APPTYPE CONSOLE}
program Project1;
uses
SysUtils;
const
BoolText: array[boolean] of string = ('false', 'true');
threadvar
BytesRemaining: integer;
FetchFailure: boolean;
procedure TestMe;
begin
WriteLn('Remaining = 0? - > ' +
BoolText[BytesRemaining = 0]);
FetchFailure := BytesRemaining = 0; // gets set
incorrectly
WriteLn('Remaining = 0? - > ' +
BoolText[FetchFailure]);
end;
begin
BytesRemaining := 200;
TestMe;
ReadLn;
end.
// the program outputs 'false true' instead of 'false
false'
NOTE: These listings are for informational use only. It is not intended for use when calling Borland's Developer Support Department. If you have any suggestions or complaints about these 'Delphi Enhancements and Fixes' pages, please contact the Delphi Administrator. This e-mail address is not intended for support issues. |
|
|
|
|||||
| Made in Borland® Copyright© 1994-2003 Borland Software Corporation. All rights reserved. Report Piracy, Legal Notices, Privacy Policy Last Modified Thursday, 22-Mar-2001 18:57:03 EST |
|||||