diff --git a/compiler/nobj.pas b/compiler/nobj.pas index 2f14fc0f41..83c88435da 100644 --- a/compiler/nobj.pas +++ b/compiler/nobj.pas @@ -240,6 +240,10 @@ implementation // returns true if we can stop checking, false if we have to continue function found_entry(var vmtpd: tprocdef; var vmtentryvis: tvisibility; updatevalues: boolean): boolean; +{$ifdef jvm} + var + javanewtreeok: boolean; +{$endif jvm} begin result:=false; @@ -269,9 +273,16 @@ implementation hasequalpara:=(compare_paras(vmtpd.paras,pd.paras,cp_none,[cpo_ignoreuniv,cpo_ignorehidden])>=te_equal); { check that we are not trying to override a final method } + { in Java, new virtual inheritance trees can never be started -> + treat all methods as "overriding" in the context of this check + (Java does check whether the mangled names are identical, so if they + are not we can stil get away with it) } if (po_finalmethod in vmtpd.procoptions) and - hasequalpara and (po_overridingmethod in pd.procoptions) and - (is_class(_class) or is_objectpascal_helper(_class)) then + hasequalpara and + ((po_overridingmethod in pd.procoptions) or + (is_javaclass(_class) and + (pd.mangledname=vmtpd.mangledname))) and + (is_class(_class) or is_objectpascal_helper(_class) or is_javaclass(_class)) then MessagePos1(pd.fileinfo,parser_e_final_can_no_be_overridden,pd.fullprocname(false)) else { old definition has virtual @@ -296,9 +307,21 @@ implementation hasequalpara ) then begin - if not(po_reintroduce in pd.procoptions) then - if not(is_objc_class_or_protocol(_class)) and - not(is_java_class_or_interface(_class)) then +{$ifdef jvm} + { if the mangled names are different, the inheritance trees + are different too in Java } + javanewtreeok:= + is_java_class_or_interface(_class) and + (pd.jvmmangledbasename(false)<>vmtpd.jvmmangledbasename(false)); +{$endif} + if not(po_reintroduce in pd.procoptions) and + not(po_java_nonvirtual in vmtpd.procoptions) then + if not(is_objc_class_or_protocol(_class)) +{$ifdef jvm} + and (not is_java_class_or_interface(_class) or + javanewtreeok) +{$endif jvm} + then MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false)) else begin @@ -341,6 +364,15 @@ implementation dec(tobjectdef(pd.owner.defowner).abstractcnt); result:=true; exit; +{$ifdef jvm} + end + else + if not javanewtreeok and + is_java_class_or_interface(_class) then + begin + { mangled names are the same -> can only override } + MessagePos1(pd.fileinfo,parser_e_must_use_override,FullTypeName(tdef(vmtpd.owner.defowner),nil)) +{$endif jvm} end; { disable/hide old VMT entry } if updatevalues then diff --git a/compiler/pdecobj.pas b/compiler/pdecobj.pas index 267ac65aeb..c0cd06fcc5 100644 --- a/compiler/pdecobj.pas +++ b/compiler/pdecobj.pas @@ -782,6 +782,24 @@ implementation begin if is_java_class_or_interface(pd.struct) then begin + { mark all non-virtual instance methods as "virtual; final;", + because + a) that's the only way to guarantee "non-virtual" behaviour + (other than making them class methods with an explicit self + pointer, but that causes problems with interface mappings + and procvars) + b) if we don't mark them virtual, they don't get added to the + vmt and we can't check whether child classes try to override + them + } + if is_javaclass(pd.struct) and + not(po_virtualmethod in pd.procoptions) and + not(po_classmethod in pd.procoptions) then + begin + include(pd.procoptions,po_virtualmethod); + include(pd.procoptions,po_finalmethod); + include(pd.procoptions,po_java_nonvirtual); + end; end; end; diff --git a/compiler/symconst.pas b/compiler/symconst.pas index 87e9b3fa0f..d6d01cd69a 100644 --- a/compiler/symconst.pas +++ b/compiler/symconst.pas @@ -315,7 +315,10 @@ type (when calling a regular procedure using the above convention, it will simply not see the frame pointer parameter, and since the caller cleans up the stack will also remain balanced) } - po_delphi_nested_cc + po_delphi_nested_cc, + { Non-virtual method of a Java class that has been transformed into a + "virtual; final;" method for JVM-implementation reasons } + po_java_nonvirtual ); tprocoptions=set of tprocoption; diff --git a/compiler/utils/ppudump.pp b/compiler/utils/ppudump.pp index 36c1912908..6c73d9f4f7 100644 --- a/compiler/utils/ppudump.pp +++ b/compiler/utils/ppudump.pp @@ -1148,7 +1148,8 @@ const (mask:po_objc; str:'ObjC'), (mask:po_enumerator_movenext; str:'EnumeratorMoveNext'), (mask:po_optional; str: 'Optional'), - (mask:po_delphi_nested_cc;str: 'Delphi-style nested frameptr') + (mask:po_delphi_nested_cc;str: 'Delphi-style nested frameptr'), + (mask:po_java_nonvirtual; str: 'Java non-virtual method') ); var proctypeoption : tproctypeoption;