Skip to content

Commit 0b8098f

Browse files
committed
Merge remote-tracking branch 'jayrm/procptrs' into master
2 parents e43074e + 99a2926 commit 0b8098f

16 files changed

+1491
-132
lines changed

changelog.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ Version 1.10.0
6767
- Add makefile option DISABLE_STDCXX_PATH to disable usnig gcc to search for some c++ library path
6868
- fbc: allow typename.member symbol checks for #ifdef / #ifndef / defined() where member can be a data field, static data field, nested type, constructor, destructor, property, operator (self-assignment, new, new[], delete, delete[], let, cast, for, step, next), or member procedure.
6969
- rtlib: dos: add "__fb_dos_no_dpmi_yield" variable to control calling "__dpmi_yield()" and prevent a crash under some dos extenders in dosbox
70+
- fbc: PROCPTR( UDT.member [, SUB|FUNCTION ...] ) to get a procedure pointer for type member procedures. If the member is abstract, then return 0 (null function pointer of the member procedure's call signature)
71+
- fbc: PROCPTR( UDT.member VIRTUAL [, SUB|FUNCTION ...] ) to get the offset (in bytes) in to the virtual table. If there is no virtual table entry (or no virtual table at all) then return the special value of -2147483648
7072

7173
[fixed]
7274
- gas64: missing restoring of use of one virtual register on sqr for float (SARG)
@@ -129,6 +131,7 @@ Version 1.10.0
129131
- fbc: extend lifetime of temporary variables in WITH TYPE(...) expressions to the END WITH statement
130132
- fbc: #cmdline "-r -rr -R -RR -o objfile ..." needs to restart the parser and handle changes in keeping the ASM file. In the case of '-o objfile' a major restart is needed since some initialization of filenames is done before parsing starts. By default the temporary ASM file was being kept even if #cmdline options indicate to keep it.
131133
- sf.net #569: gfxlib2: GetMouse/SetMouse scaling problem in QB modes Screen 2 & 8 - adjust GetMouse/SetMouse by internal scanline_size
134+
- fbc: fbc: fix bad error recovery on BYREF intializer. 'Dim Byref As UDT u = UDT()' would case compiler crash if UDT constructor argument optional
132135

133136

134137
Version 1.09.0

src/compiler/ast-node-arg.bas

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,12 @@ function astNewARG _
10291029
'' optional/default?
10301030
if( arg = NULL ) then
10311031
arg = hCreateOptArg( param )
1032+
1033+
'' still NULL? then hCreateOptArg() failed
1034+
if( arg = NULL ) then
1035+
function = NULL
1036+
exit function
1037+
end if
10321038
end if
10331039

10341040
if( dtype = FB_DATATYPE_INVALID ) then
@@ -1049,6 +1055,7 @@ function astNewARG _
10491055
else
10501056
errReportParam( parent->sym, parent->call.args+1, NULL, FB_ERRMSG_ILLEGALASSIGNMENT )
10511057
end if
1058+
function = NULL
10521059
exit function
10531060
end if
10541061
end if

src/compiler/ir-gas64.bas

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6462,8 +6462,7 @@ private sub _emitasmline( byval asmtokenhead as ASTASMTOK ptr )
64626462

64636463
Var ofs = symbGetOfs( n->sym )
64646464
if( ofs <> 0 ) then
6465-
asmline=left(asmline,len(asmline)-1) ''to remove the first bracket
6466-
asmline+= str( ofs )+"[rbp" ''the final bracket is added just after
6465+
asmline+= str( ofs )+"[rbp]"
64676466
else
64686467
asmline+= *symbGetMangledName( n->sym )'*symbGetMangledName( n->sym )
64696468
end if

src/compiler/parser-expr-unary.bas

Lines changed: 178 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ private function hPPDefinedExpr( ) as ASTNODE ptr
2525
end if
2626

2727
'' Identifier
28-
is_defined = (cIdentifierIfDefined( ) <> NULL)
28+
is_defined = (cIdentifierOrUDTMember( ) <> NULL)
2929

3030
'' ')'
3131
if( hMatch( CHAR_RPRNT ) = FALSE ) then
@@ -444,15 +444,39 @@ function cDerefExpression( ) as ASTNODE ptr
444444
function = astBuildMultiDeref( derefcnt, expr, astGetFullType( expr ), astGetSubType( expr ) )
445445
end function
446446

447-
private function hProcPtrBody _
447+
private function hProcPtrResolveOverload _
448448
( _
449-
byval base_parent as FBSYMBOL ptr, _
449+
byval ovl_head_proc as FBSYMBOL ptr, _
450450
byval proc as FBSYMBOL ptr, _
451451
byval check_exact as boolean = FALSE _
452-
) as ASTNODE ptr
452+
) as FBSYMBOL ptr
453+
454+
dim as FBSYMBOL ptr sym = ovl_head_proc
453455

454-
dim as FBSYMBOL ptr sym = any
456+
if( symbIsOperator( ovl_head_proc ) ) then
457+
dim as AST_OP op = any
458+
op = symbGetProcOpOvl( ovl_head_proc )
459+
sym = symbFindOpOvlProc( op, ovl_head_proc, proc )
455460

461+
elseif( symbIsProc( proc ) ) then
462+
dim findopts as FB_SYMBFINDOPT = FB_SYMBFINDOPT_NONE
463+
464+
'' if it is a property then let the function pointer decide
465+
'' if we are looking for the set or get procedure where
466+
'' get is expected to have a return type
467+
if( symbIsProperty( ovl_head_proc ) ) then
468+
if( symbGetType( proc ) <> FB_DATATYPE_VOID ) then
469+
findopts = FB_SYMBFINDOPT_PROPGET
470+
end if
471+
end if
472+
sym = symbFindOverloadProc( ovl_head_proc, proc, findopts )
473+
474+
end if
475+
476+
return sym
477+
end function
478+
479+
private sub hCheckEmptyProcParens()
456480
'' '('')'?
457481
if( lexGetToken( ) = CHAR_LPRNT ) then
458482
lexSkipToken( )
@@ -461,26 +485,33 @@ private function hProcPtrBody _
461485
hSkipUntil( CHAR_RPRNT, TRUE )
462486
end if
463487
end if
488+
end sub
489+
490+
private function hProcPtrBody _
491+
( _
492+
byval base_parent as FBSYMBOL ptr, _
493+
byval proc as FBSYMBOL ptr, _
494+
byval check_exact as boolean, _
495+
byval is_vtable_offset as integer _
496+
) as ASTNODE ptr
497+
498+
assert( proc <> NULL )
499+
assert( symbIsProc( proc ) )
464500

465501
'' resolve overloaded procs
466-
if( (symbIsOverloaded( proc ) <> 0) or (check_exact <> FALSE) ) then
467-
if( parser.ctxsym <> NULL ) then
468-
if( symbIsProc( parser.ctxsym ) ) then
469-
sym = symbFindOverloadProc( proc, parser.ctxsym )
470-
if( sym <> NULL ) then
471-
proc = sym
472-
elseif( check_exact ) then
473-
errReport( FB_ERRMSG_NOMATCHINGPROC, TRUE )
474-
return astNewCONSTi( 0 )
475-
end if
502+
if( parser.ctxsym <> NULL ) then
503+
if( symbIsOverloaded( proc ) or check_exact ) then
504+
dim as FBSYMBOL ptr sym = any
505+
sym = hProcPtrResolveOverload( proc, parser.ctxsym )
506+
507+
if( sym ) then
508+
proc = sym
509+
elseif( check_exact ) then
510+
errReport( FB_ERRMSG_NOMATCHINGPROC, TRUE )
511+
return astNewCONSTi( 0 )
476512
end if
477513
end if
478-
end if
479514

480-
'' taking the address of an method? pointer to methods not supported yet..
481-
if( symbIsMethod( proc ) ) then
482-
errReportEx( FB_ERRMSG_ACCESSTONONSTATICMEMBER, symbGetFullProcName( proc ) )
483-
return astNewCONSTi( 0 )
484515
end if
485516

486517
'' Check visibility of the proc
@@ -494,7 +525,125 @@ private function hProcPtrBody _
494525
callback( proc )
495526
end if
496527

497-
function = astBuildProcAddrof( proc )
528+
if( is_vtable_offset ) then
529+
'' if not virtual or abstract then procedure doesn't exist in
530+
'' the virtual table. Don't throw an error, just return an
531+
'' invalid vtable offset. vtable offsets are something that
532+
'' the user will have to deal with anyway
533+
dim as integer vtableoffset = -2147483648u
534+
535+
if( symbIsAbstract( proc ) or symbIsVirtual( proc ) ) then
536+
vtableoffset = ( symbProcGetVtableIndex( proc ) - 2 ) * env.pointersize
537+
endif
538+
539+
var expr = astNewCONSTi( vtableoffset )
540+
return expr
541+
end if
542+
543+
if( symbIsAbstract( proc ) )then
544+
'' member is abstract and is not something we can get the address of
545+
'' until a virtual lookup at runtime ...
546+
'' return a null pointer of the function pointer instead
547+
548+
var expr = astNewCONSTi( 0 )
549+
expr = astNewCONV( typeAddrOf( FB_DATATYPE_FUNCTION ), symbAddProcPtrFromFunction( proc ), expr )
550+
return expr
551+
end if
552+
553+
return astBuildProcAddrof( proc )
554+
end function
555+
556+
'' PROCPTR '(' Proc ('('')')? VIRTUAL? ( ',' signature )? ')'
557+
function cProcPtrBody _
558+
( _
559+
byval dtype as integer, _
560+
byval subtype as FBSYMBOL ptr _
561+
) as ASTNODE ptr
562+
563+
dim as FBSYMCHAIN ptr chain_ = any
564+
dim as FBSYMBOL ptr sym = any, base_parent = any
565+
dim as ASTNODE ptr expr = any
566+
dim as integer is_vtable_offset = FALSE
567+
568+
if( dtype = FB_DATATYPE_STRUCT ) then
569+
base_parent = subtype
570+
chain_ = NULL
571+
572+
else
573+
chain_ = cIdentifier( base_parent, _
574+
FB_IDOPT_CHECKSTATIC or _
575+
FB_IDOPT_ALLOWSTRUCT or _
576+
FB_IDOPT_ALLOWOPERATOR )
577+
578+
end if
579+
580+
sym = cIdentifierOrUDTMember( base_parent, chain_ )
581+
582+
if( sym = NULL ) then
583+
errReport( FB_ERRMSG_UNDEFINEDSYMBOL )
584+
'' error recovery: skip until ')' and fake a node
585+
hSkipUntil( CHAR_RPRNT, TRUE )
586+
return astNewCONSTi( 0 )
587+
end if
588+
589+
if( symbGetClass( sym ) <> FB_SYMBCLASS_PROC ) then
590+
errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
591+
'' error recovery: skip until ')' and fake a node
592+
hSkipUntil( CHAR_RPRNT, TRUE )
593+
return astNewCONSTi( 0 )
594+
end if
595+
596+
hCheckEmptyProcParens()
597+
598+
'' ','?
599+
if( hMatch( CHAR_COMMA ) ) then
600+
dim as integer dtype = FB_DATATYPE_VOID
601+
dim as FBSYMBOL ptr subtype = NULL
602+
dim as integer is_exact = FALSE
603+
604+
'' VIRTUAL?
605+
if( lexGetToken( ) = FB_TK_VIRTUAL ) then
606+
is_vtable_offset = TRUE
607+
lexSkipToken( LEXCHECK_POST_SUFFIX )
608+
end if
609+
610+
'' only if anything but ')' follows...
611+
if( lexGetToken( ) <> CHAR_RPRNT ) then
612+
if( cSymbolType( dtype, subtype ) = FALSE ) then
613+
errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
614+
'' error recovery: skip until ')' and fake a node
615+
hSkipUntil( CHAR_RPRNT, TRUE )
616+
return astNewCONSTi( 0 )
617+
end if
618+
619+
select case typeGetDtAndPtrOnly( dtype )
620+
case FB_DATATYPE_VOID
621+
'' 'ANY' matches first declaration
622+
case typeAddrOf( FB_DATATYPE_FUNCTION )
623+
is_exact = TRUE
624+
case else
625+
errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
626+
'' error recovery: skip until ')' and fake a node
627+
hSkipUntil( CHAR_RPRNT, TRUE )
628+
return astNewCONSTi( 0 )
629+
end select
630+
end if
631+
632+
dim as FBSYMBOL ptr oldsym = parser.ctxsym
633+
dim as integer old_dtype = parser.ctx_dtype
634+
parser.ctxsym = subtype
635+
parser.ctx_dtype = dtype
636+
637+
expr = hProcPtrBody( base_parent, sym, is_exact, is_vtable_offset )
638+
639+
parser.ctxsym = oldsym
640+
parser.ctx_dtype = old_dtype
641+
642+
else
643+
expr = hProcPtrBody( base_parent, sym, FALSE, is_vtable_offset )
644+
end if
645+
646+
return expr
498647
end function
499648

500649
private function hVarPtrBody _
@@ -517,6 +666,7 @@ private function hVarPtrBody _
517666
'' hand, we need to make sure we don't prematurely optimize
518667
'' the CONST specifier away in the event that it is needed
519668
'' to be known with AST type checking later.
669+
520670
dim as ASTNODE ptr t = astSkipConstCASTs( expr )
521671

522672
select case as const astGetClass( t )
@@ -596,11 +746,12 @@ function cAddrOfExpression( ) as ASTNODE ptr
596746
'' proc?
597747
if( sym <> NULL ) then
598748
lexSkipToken( LEXCHECK_POST_LANG_SUFFIX )
599-
return hProcPtrBody( base_parent, sym )
600-
'' anything else..
601-
else
602-
return hVarPtrBody( base_parent, chain_ )
749+
hCheckEmptyProcParens()
750+
return hProcPtrBody( base_parent, sym, FALSE, FALSE )
603751
end if
752+
753+
'' anything else
754+
return hVarPtrBody( base_parent, chain_ )
604755
end if
605756

606757
select case as const lexGetToken( )
@@ -625,7 +776,7 @@ function cAddrOfExpression( ) as ASTNODE ptr
625776
hSkipUntil( CHAR_RPRNT, TRUE )
626777
end if
627778

628-
'' PROCPTR '(' Proc ('('')')? ')'
779+
'' PROCPTR '(' Proc ('('')')? VIRTUAL? ( ',' signature )? ')'
629780
case FB_TK_PROCPTR
630781
lexSkipToken( LEXCHECK_POST_SUFFIX )
631782

@@ -637,51 +788,7 @@ function cAddrOfExpression( ) as ASTNODE ptr
637788
return astNewCONSTi( 0 )
638789
end if
639790

640-
'' proc?
641-
dim as FBSYMCHAIN ptr chain_ = any
642-
dim as FBSYMBOL ptr sym = any, base_parent = any
643-
644-
chain_ = cIdentifier( base_parent, _
645-
FB_IDOPT_DEFAULT or FB_IDOPT_ALLOWSTRUCT )
646-
sym = symbFindByClass( chain_, FB_SYMBCLASS_PROC )
647-
if( sym = NULL ) then
648-
errReport( FB_ERRMSG_UNDEFINEDSYMBOL )
649-
'' error recovery: skip until ')' and fake a node
650-
hSkipUntil( CHAR_RPRNT, TRUE )
651-
return astNewCONSTi( 0 )
652-
else
653-
lexSkipToken( LEXCHECK_POST_LANG_SUFFIX )
654-
end if
655-
656-
'' ',' ?
657-
if( hMatch( CHAR_COMMA ) ) then
658-
dim dtype as integer
659-
dim subtype as FBSYMBOL ptr
660-
if( cSymbolType( dtype, subtype ) = FALSE ) then
661-
errReport( FB_ERRMSG_SYNTAXERROR, TRUE )
662-
'' error recovery: skip until ')' and fake a node
663-
hSkipUntil( CHAR_RPRNT, TRUE )
664-
return astNewCONSTi( 0 )
665-
else
666-
if( typeGetDtAndPtrOnly( dtype ) = typeAddrOf( FB_DATATYPE_FUNCTION ) ) then
667-
dim oldsym as FBSYMBOL ptr = parser.ctxsym
668-
dim old_dtype as integer = parser.ctx_dtype
669-
parser.ctxsym = subtype
670-
parser.ctx_dtype = dtype
671-
expr = hProcPtrBody( base_parent, sym, TRUE )
672-
parser.ctxsym = oldsym
673-
parser.ctx_dtype = old_dtype
674-
else
675-
errReport( FB_ERRMSG_SYNTAXERROR, TRUE )
676-
'' error recovery: skip until ')' and fake a node
677-
hSkipUntil( CHAR_RPRNT, TRUE )
678-
return astNewCONSTi( 0 )
679-
end if
680-
end if
681-
682-
else
683-
expr = hProcPtrBody( base_parent, sym )
684-
end if
791+
expr = cProcPtrBody( 0, NULL )
685792

686793
'' ')'
687794
if( hMatch( CHAR_RPRNT ) = FALSE ) then

0 commit comments

Comments
 (0)