* for now only auto-generate a parameterless constructor in case no

constructor is declared, rather than all constructors from the parent
    class (because it cannot be done via scanner-injection, since some
    parameter types of the parent constructors may not be visible in the
    current unit, and there is no full-blown tprocdef.getcopy yet nor
    a way to replace the type of the self-parameter afterwards)
  * added sanity checks when inserting the parameterless constructor
    (check for other identifiers called "create", and other parameterless
     methods)

git-svn-id: branches/jvmbackend@18432 -
This commit is contained in:
Jonas Maebe 2011-08-20 07:59:08 +00:00
parent c05bc8a931
commit d47f26bbca
4 changed files with 400 additions and 277 deletions

View File

@ -1788,7 +1788,7 @@ type_e_invalid_final_assignment=04104_E_Final (class) fields can only be assigne
#
# Symtable
#
# 05084 is the last used one
# 05086 is the last used one
#
% \section{Symbol handling}
% This section lists all the messages that concern the handling of symbols.
@ -2038,7 +2038,20 @@ sym_w_library_overload=05084_W_Possible library conflict: symbol "$1" from libra
% the 'libname' part is only a hint, funcname might also be loaded
% by another library. This warning appears if 'funcname' is used twice
% with two different library names.
%
sym_e_duplicate_id_create_java_constructor=05085_E_Cannot add implicit constructor 'Create' because identifier already used by "$1"
% Java does not automatically add inherited constructors to child classes, so that they can be hidden.
% However, if a class does not explicitly declare at least one constructor, the compiler is
% required to add a public, parameterless constructor. In Java, constructors are nameless,
% but in FPC they are all called ``Create''. Therefore, if you do not add a constructor to
% a Java class and furthermore use the ``Create'' identifier for another entity (e.g., a field,
% or a parameterless method), the compiler cannot satisfy this requirement.
sym_e_no_matching_inherited_parameterless_constructor=05086_E_Cannot generate default constructor for class, because parent has no parameterless constructor
% Java does not automatically add inherited constructors to child classes, so that they can be hidden.
% However, if a class does not explicitly declare at least one constructor, the compiler is
% required to add a public, parameterless constructor. This compiler must then call
% the parameterless constructor from the parent class inside this added constructor.
% This is however impossible if the parent class does not declare such a constructor.
% In this case you must add a valid constructor yourself.
% \end{description}
#
# Codegenerator

View File

@ -575,6 +575,8 @@ const
sym_e_external_class_name_mismatch1=05082;
sym_e_external_class_name_mismatch2=05083;
sym_w_library_overload=05084;
sym_e_duplicate_id_create_java_constructor=05085;
sym_e_no_matching_inherited_parameterless_constructor=05086;
cg_e_parasize_too_big=06009;
cg_e_file_must_call_by_reference=06012;
cg_e_cant_use_far_pointer_there=06013;
@ -906,9 +908,9 @@ const
option_info=11024;
option_help_pages=11025;
MsgTxtSize = 61491;
MsgTxtSize = 61683;
MsgIdxMax : array[1..20] of longint=(
26,89,318,105,85,54,111,23,202,63,
26,89,318,105,87,54,111,23,202,63,
49,20,1,1,1,1,1,1,1,1
);

File diff suppressed because it is too large Load Diff

View File

@ -46,10 +46,11 @@ implementation
uses
sysutils,cutils,
globals,verbose,systems,tokens,
symbase,symsym,symtable,symcreat,
symbase,symsym,symtable,symcreat,defcmp,
node,nld,nmem,ncon,ncnv,ncal,
fmodule,scanner,
pbase,pexpr,pdecsub,pdecvar,ptype,pdecl,ppu
pbase,pexpr,pdecsub,pdecvar,ptype,pdecl,ppu,
parabase
;
const
@ -708,6 +709,110 @@ implementation
end;
{ the JVM specs require that you add a default parameterless
constructor in case the programmer hasn't specified any }
procedure maybe_add_public_default_java_constructor(obj: tabstractrecorddef);
function find_parameterless_def(psym: tprocsym): tprocdef;
var
paras: tparalist;
begin
paras:=tparalist.create;
result:=psym.find_procdef_bypara_no_rettype(paras,[cpo_ignorehidden,cpo_openequalisexact]);
paras.free;
end;
var
sym: tsym;
ps: tprocsym;
pd: tprocdef;
topowner: tdefentry;
i: longint;
begin
{ if there is at least one constructor for a class, do nothing (for
records, we'll always also need a parameterless constructor) }
if is_javaclass(obj) and
(oo_has_constructor in obj.objectoptions) then
exit;
{ check whether the parent has a parameterless constructor that we can
call (in case of a class; all records will derive from
java.lang.Object or a shim on top of that with a parameterless
constructor) }
if is_javaclass(obj) then
begin
pd:=nil;
sym:=tsym(tobjectdef(obj).childof.symtable.find('CREATE'));
if assigned(sym) and
(sym.typ=procsym) then
begin
pd:=find_parameterless_def(tprocsym(sym));
{ make sure it's a constructor }
if assigned(pd) and
(pd.proctypeoption<>potype_constructor) then
pd:=nil;
end;
if not assigned(pd) then
begin
Message(sym_e_no_matching_inherited_parameterless_constructor);
exit
end;
end;
{ we call all constructors CREATE, because they don't have a name in
Java and otherwise we can't determine whether multiple overloads
are created with the same parameters }
sym:=tsym(obj.symtable.find('CREATE'));
if assigned(sym) then
begin
{ does another, non-procsym, symbol already exist with that name? }
if (sym.typ<>procsym) then
begin
Message1(sym_e_duplicate_id_create_java_constructor,sym.realname);
exit;
end;
ps:=tprocsym(sym);
{ is there already a parameterless function/procedure create? }
pd:=find_parameterless_def(ps);
if assigned(pd) then
begin
Message1(sym_e_duplicate_id_create_java_constructor,pd.fullprocname(false));
exit;
end;
end;
if not assigned(sym) then
begin
ps:=tprocsym.create('Create');
obj.symtable.insert(ps);
end;
{ determine symtable level }
topowner:=obj;
while not(topowner.owner.symtabletype in [staticsymtable,globalsymtable,localsymtable]) do
topowner:=topowner.owner.defowner;
{ create procdef }
pd:=tprocdef.create(topowner.owner.symtablelevel+1);
{ method of this objectdef }
pd.struct:=obj;
{ associated procsym }
pd.procsym:=ps;
{ constructor }
pd.proctypeoption:=potype_constructor;
{ needs to be exported }
include(pd.procoptions,po_global);
{ for Delphi mode }
include(pd.procoptions,po_overload);
{ synthetic, compiler-generated }
include(pd.procoptions,po_synthetic);
{ public }
pd.visibility:=vis_public;
{ result type }
pd.returndef:=obj;
{ calling convention, self, ... }
handle_calling_convention(pd);
{ register forward declaration with procsym }
proc_add_definition(pd);
end;
function method_dec(astruct: tabstractrecorddef; is_classdef: boolean): tprocdef;
procedure chkobjc(pd: tprocdef);
@ -1348,9 +1453,9 @@ implementation
hide them). Emulate the Pascal behaviour for classes implemented
in Pascal (we cannot do it for classes implemented in Java, since
we obviously cannot add constructors to those) }
if is_javaclass(current_structdef) and
not(oo_is_external in current_structdef.objectoptions) then
add_missing_parent_constructors_intf(tobjectdef(current_structdef));
if is_javaclass(current_structdef) and
not(oo_is_external in current_structdef.objectoptions) then
maybe_add_public_default_java_constructor(tobjectdef(current_structdef));
symtablestack.pop(current_structdef.symtable);
end;