Przeglądaj źródła

* Generate stub bodies for abstract methods, so corresponding symbols can be referenced from code. Resolves #24536.

git-svn-id: trunk@25260 -
sergei 12 lat temu
rodzic
commit
92811d09c1
3 zmienionych plików z 48 dodań i 1 usunięć
  1. 1 0
      .gitattributes
  2. 26 1
      compiler/ncgvmt.pas
  3. 21 0
      tests/webtbs/tw24536.pp

+ 1 - 0
.gitattributes

@@ -13467,6 +13467,7 @@ tests/webtbs/tw2435.pp svneol=native#text/plain
 tests/webtbs/tw2438.pp svneol=native#text/plain
 tests/webtbs/tw2442.pp svneol=native#text/plain
 tests/webtbs/tw2452.pp svneol=native#text/plain
+tests/webtbs/tw24536.pp svneol=native#text/plain
 tests/webtbs/tw2454.pp svneol=native#text/plain
 tests/webtbs/tw24651.pp svneol=native#text/pascal
 tests/webtbs/tw24705.pp svneol=native#text/pascal

+ 26 - 1
compiler/ncgvmt.pas

@@ -87,6 +87,7 @@ implementation
         function  genintmsgtab(list : TAsmList) : tasmlabel;
         function  genpublishedmethodstable(list : TAsmList) : tasmlabel;
         function  generate_field_table(list : TAsmList) : tasmlabel;
+        procedure generate_abstract_stub(list:TAsmList;pd:tprocdef);
 {$ifdef WITHDMT}
         { generates a DMT for _class }
         function  gendmt : tasmlabel;
@@ -714,6 +715,27 @@ implementation
       end;
 
 
+    procedure TVMTWriter.generate_abstract_stub(list:TAsmList;pd:tprocdef);
+      var
+        sym: TAsmSymbol;
+      begin
+        { Generate stubs for abstract methods, so their symbols are present and
+          can be used e.g. to take address (see issue #24536). }
+        sym:=current_asmdata.GetAsmSymbol(pd.mangledname);
+        if assigned(sym) and (sym.bind<>AB_EXTERNAL) then
+          exit;
+        maybe_new_object_file(list);
+        new_section(list,sec_code,lower(pd.mangledname),target_info.alignment.procalign);
+        if (po_global in pd.procoptions) then
+          sym:=current_asmdata.DefineAsmSymbol(pd.mangledname,AB_GLOBAL,AT_FUNCTION)
+        else
+          sym:=current_asmdata.DefineAsmSymbol(pd.mangledname,AB_LOCAL,AT_FUNCTION);
+        list.concat(Tai_symbol.Create(sym,0));
+        cg.g_external_wrapper(list,pd,'FPC_ABSTRACTERROR');
+        list.concat(Tai_symbol_end.Create(sym));
+      end;
+
+
     procedure TVMTWriter.writevirtualmethods(List:TAsmList);
       var
          vmtpd : tprocdef;
@@ -736,7 +758,10 @@ implementation
            if vmtpd.extnumber<>i then
              internalerror(200611083);
            if (po_abstractmethod in vmtpd.procoptions) then
-             procname:='FPC_ABSTRACTERROR'
+             begin
+               procname:='FPC_ABSTRACTERROR';
+               generate_abstract_stub(current_asmdata.AsmLists[al_procedures],vmtpd);
+             end
            else if (cs_opt_remove_emtpy_proc in current_settings.optimizerswitches) and RedirectToEmpty(vmtpd) then
              procname:='FPC_EMPTYMETHOD'
            else if not wpoinfomanager.optimized_name_for_vmt(_class,vmtpd,procname) then

+ 21 - 0
tests/webtbs/tw24536.pp

@@ -0,0 +1,21 @@
+{$ifdef fpc}{$mode objfpc}{$endif}
+type
+  TMyClass = class
+    procedure MyAbstractMethod; virtual; abstract;
+    procedure MyAbstractMethod2; virtual; abstract;
+  end;
+
+  TMyClass2 = class(TMyClass)
+  end;
+
+var
+  Foo,Foo2: Pointer;
+begin
+  Foo := @TMyClass.MyAbstractMethod;
+  Foo2 := @TMyClass.MyAbstractMethod2;
+  if Foo=Foo2 then
+    Halt(1);
+  Foo2 := @TMyClass2.MyAbstractMethod;
+  if Foo<>Foo2 then
+    Halt(1);
+end.