mirror of
https://github.com/cc65/cc65.git
synced 2024-06-08 15:29:37 +00:00
Merge branch 'master' into fptest
This commit is contained in:
commit
650868854d
|
@ -5,16 +5,17 @@ SYMBOLS {
|
|||
__BANK1BLOCKSIZE__: type = weak, value = $0000; # bank 1 block size
|
||||
__EXEHDR__: type = import;
|
||||
__BOOTLDR__: type = import;
|
||||
__DEFDIR__: type = import;
|
||||
__UPLOADER__: type = import;
|
||||
__UPLOADERSIZE__: type = export, value = $61;
|
||||
__HEADERSIZE__: type = export, value = 64;
|
||||
}
|
||||
MEMORY {
|
||||
ZP: file = "", define = yes, start = $0000, size = $0100;
|
||||
HEADER: file = %O, start = $0000, size = $0040;
|
||||
HEADER: file = %O, start = $0000, size = __HEADERSIZE__;
|
||||
BOOT: file = %O, start = $0200, size = __STARTOFDIRECTORY__;
|
||||
DIR: file = %O, start = $0000, size = 8;
|
||||
MAIN: file = %O, define = yes, start = $0200, size = $BD38 - __STACKSIZE__;
|
||||
UPLDR: file = %O, define = yes, start = $BFDC, size = $005C;
|
||||
DIR: file = %O, start = $0000, size = 16;
|
||||
MAIN: file = %O, define = yes, start = $0200, size = $C038 - __UPLOADERSIZE__ - $200 - __STACKSIZE__;
|
||||
UPLOAD: file = %O, define = yes, start = $C038 - __UPLOADERSIZE__, size = $0061;
|
||||
}
|
||||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp;
|
||||
|
@ -30,8 +31,8 @@ SEGMENTS {
|
|||
RODATA: load = MAIN, type = ro, define = yes;
|
||||
DATA: load = MAIN, type = rw, define = yes;
|
||||
BSS: load = MAIN, type = bss, define = yes;
|
||||
UPCODE: load = UPLDR, type = ro, define = yes;
|
||||
UPDATA: load = UPLDR, type = rw, define = yes;
|
||||
UPCODE: load = UPLOAD, type = ro, define = yes;
|
||||
UPDATA: load = UPLOAD, type = rw, define = yes;
|
||||
}
|
||||
FEATURES {
|
||||
CONDES: type = constructor,
|
||||
|
|
|
@ -331,12 +331,28 @@ usage.
|
|||
<item>_filetype
|
||||
<item>_datetime
|
||||
<item>get_ostype
|
||||
<item>gmtime_dt
|
||||
<item>mktime_dt
|
||||
<item>rebootafterexit
|
||||
<item>ser_apple2_slot
|
||||
<item>tgi_apple2_mix
|
||||
</itemize>
|
||||
|
||||
|
||||
<sect1>Apple IIgs specific functions in accelerator.h<p>
|
||||
|
||||
In addition to those, the <tt/accelerator.h/ header file contains three functions
|
||||
to help determine whether the program is running on a IIgs, and change the IIgs
|
||||
CPU speed. See the <url url="funcref.html" name="function reference"> for declaration and
|
||||
usage.
|
||||
|
||||
<itemize>
|
||||
<item>detect_iigs
|
||||
<item>get_iigs_speed
|
||||
<item>set_iigs_speed
|
||||
</itemize>
|
||||
|
||||
|
||||
<sect1>Hardware access<p>
|
||||
|
||||
There's currently no support for direct hardware access. This does not mean
|
||||
|
|
|
@ -332,6 +332,8 @@ usage.
|
|||
<item>_filetype
|
||||
<item>_datetime
|
||||
<item>get_ostype
|
||||
<item>gmtime_dt
|
||||
<item>mktime_dt
|
||||
<item>rebootafterexit
|
||||
<item>ser_apple2_slot
|
||||
<item>tgi_apple2_mix
|
||||
|
@ -340,6 +342,20 @@ usage.
|
|||
</itemize>
|
||||
|
||||
|
||||
<sect1>Apple IIgs specific functions in accelerator.h<p>
|
||||
|
||||
In addition to those, the <tt/accelerator.h/ header file contains three functions
|
||||
to help determine whether the program is running on a IIgs, and change the IIgs
|
||||
CPU speed. See the <url url="funcref.html" name="function reference"> for declaration and
|
||||
usage.
|
||||
|
||||
<itemize>
|
||||
<item>detect_iigs
|
||||
<item>get_iigs_speed
|
||||
<item>set_iigs_speed
|
||||
</itemize>
|
||||
|
||||
|
||||
<sect1>Hardware access<p>
|
||||
|
||||
There's currently no support for direct hardware access. This does not mean
|
||||
|
|
|
@ -71,18 +71,21 @@ function.
|
|||
<item><ref id="detect_c64dtv" name="detect_c64dtv">
|
||||
<item><ref id="detect_c65" name="detect_c65">
|
||||
<item><ref id="detect_chameleon" name="detect_chameleon">
|
||||
<item><ref id="detect_iigs" name="detect_iigs">
|
||||
<item><ref id="detect_scpu" name="detect_scpu">
|
||||
<item><ref id="detect_turbomaster" name="detect_turbomaster">
|
||||
<item><ref id="get_c128_speed" name="get_c128_speed">
|
||||
<item><ref id="get_c64dtv_speed" name="get_c64dtv_speed">
|
||||
<item><ref id="get_c65_speed" name="get_c65_speed">
|
||||
<item><ref id="get_chameleon_speed" name="get_chameleon_speed">
|
||||
<item><ref id="get_iigs_speed" name="get_iigs_speed">
|
||||
<item><ref id="get_scpu_speed" name="get_scpu_speed">
|
||||
<item><ref id="get_turbomaster_speed" name="get_turbomaster_speed">
|
||||
<item><ref id="set_c128_speed" name="set_c128_speed">
|
||||
<item><ref id="set_c64dtv_speed" name="set_c64dtv_speed">
|
||||
<item><ref id="set_c65_speed" name="set_c65_speed">
|
||||
<item><ref id="set_chameleon_speed" name="set_chameleon_speed">
|
||||
<item><ref id="set_iigs_speed" name="set_iigs_speed">
|
||||
<item><ref id="set_scpu_speed" name="set_scpu_speed">
|
||||
<item><ref id="set_turbomaster_speed" name="set_turbomaster_speed">
|
||||
</itemize>
|
||||
|
@ -104,6 +107,8 @@ function.
|
|||
<itemize>
|
||||
<item>_dos_type
|
||||
<item><ref id="get_ostype" name="get_ostype">
|
||||
<item><ref id="gmtime_dt" name="gmtime_dt">
|
||||
<item><ref id="mktime_dt" name="mktime_dt">
|
||||
<item>rebootafterexit
|
||||
<item><ref id="videomode" name="videomode">
|
||||
</itemize>
|
||||
|
@ -3453,6 +3458,26 @@ used in presence of a prototype.
|
|||
</quote>
|
||||
|
||||
|
||||
<sect1>detect_iigs<label id="detect_iigs"><p>
|
||||
|
||||
<quote>
|
||||
<descrip>
|
||||
<tag/Function/Check whether we are running on an Apple IIgs..
|
||||
<tag/Header/<tt/<ref id="accelerator.h" name="accelerator.h">/
|
||||
<tag/Declaration/<tt/unsigned char detect_iigs (void);/
|
||||
<tag/Description/The function returns a 1 if running on an Apple IIgs.
|
||||
<tag/Notes/<itemize>
|
||||
<item>The function is specific to the Apple2 and Apple2enh platforms.
|
||||
</itemize>
|
||||
<tag/Availability/cc65 (not all platforms)
|
||||
<tag/See also/
|
||||
<ref id="get_iigs_speed" name="get_iigs_speed">,
|
||||
<ref id="set_iigs_speed" name="set_iigs_speed">,
|
||||
<tag/Example/None.
|
||||
</descrip>
|
||||
</quote>
|
||||
|
||||
|
||||
<sect1>detect_scpu<label id="detect_scpu"><p>
|
||||
|
||||
<quote>
|
||||
|
@ -4167,6 +4192,27 @@ header files define constants that can be used to check the return code.
|
|||
</quote>
|
||||
|
||||
|
||||
<sect1>get_iigs_speed<label id="get_iigs_speed"><p>
|
||||
|
||||
<quote>
|
||||
<descrip>
|
||||
<tag/Function/Get the current speed of the Apple IIgs.
|
||||
<tag/Header/<tt/<ref id="accelerator.h" name="accelerator.h">/
|
||||
<tag/Declaration/<tt/unsigned char get_iigs_speed (void);/
|
||||
<tag/Description/The function returns the current speed of the Apple IIgs.
|
||||
<tag/Notes/<itemize>
|
||||
<item>The function is specific to the Apple2 and Apple2enh platforms.
|
||||
<item>See the accelerator.h header for the speed definitions.
|
||||
</itemize>
|
||||
<tag/Availability/cc65 (not all platforms)
|
||||
<tag/See also/
|
||||
<ref id="detect_iigs" name="detect_iigs">,
|
||||
<ref id="set_iigs_speed" name="set_iigs_speed">,
|
||||
<tag/Example/None.
|
||||
</descrip>
|
||||
</quote>
|
||||
|
||||
|
||||
<sect1>get_scpu_speed<label id="get_scpu_speed"><p>
|
||||
|
||||
<quote>
|
||||
|
@ -6985,6 +7031,30 @@ clean-up when exiting the program.
|
|||
</quote>
|
||||
|
||||
|
||||
<sect1>set_iigs_speed<label id="set_iigs_speed"><p>
|
||||
|
||||
<quote>
|
||||
<descrip>
|
||||
<tag/Function/Set the current speed of the Apple IIgs.
|
||||
<tag/Header/<tt/<ref id="accelerator.h" name="accelerator.h">/
|
||||
<tag/Declaration/<tt/unsigned char __fastcall__ set_iigs_speed (unsigned char speed);/
|
||||
<tag/Description/The function sets the speed of the Apple IIgs CPU (and returns
|
||||
the new speed).
|
||||
<tag/Notes/<itemize>
|
||||
<item>The function is specific to the Apple2 and Apple2enh platforms.
|
||||
<item>See the accelerator.h header for the speed definitions.
|
||||
<item>Accepted parameters are SPEED_SLOW and SPEED_FAST (all other values are
|
||||
considered SPEED_FAST).
|
||||
</itemize>
|
||||
<tag/Availability/cc65 (not all platforms)
|
||||
<tag/See also/
|
||||
<ref id="detect_iigs" name="detect_iigs">,
|
||||
<ref id="get_iigs_speed" name="get_iigs_speed">,
|
||||
<tag/Example/None.
|
||||
</descrip>
|
||||
</quote>
|
||||
|
||||
|
||||
<sect1>set_scpu_speed<label id="set_scpu_speed"><p>
|
||||
|
||||
<quote>
|
||||
|
|
|
@ -304,6 +304,36 @@ unsigned char detect_turbomaster (void);
|
|||
* 0x01 : C64 Turbo Master cartridge present
|
||||
*/
|
||||
|
||||
unsigned char __fastcall__ set_iigs_speed (unsigned char speed);
|
||||
|
||||
/* Set the speed of the Apple IIgs CPU.
|
||||
*
|
||||
* Possible values:
|
||||
* SPEED_SLOW : 1 Mhz mode
|
||||
* SPEED_FAST : Fast mode (2.8MHz or more, depending on the presence of
|
||||
* an accelerator)
|
||||
*
|
||||
* Any other value will be interpreted as SPEED_FAST.
|
||||
*/
|
||||
|
||||
unsigned char get_iigs_speed (void);
|
||||
|
||||
/* Get the speed of the Apple IIgs CPU.
|
||||
*
|
||||
* Possible return values:
|
||||
* SPEED_SLOW : 1 Mhz mode
|
||||
* SPEED_FAST : Fast mode (2.8MHz or more, depending on the presence of
|
||||
* an accelerator)
|
||||
*/
|
||||
|
||||
unsigned char detect_iigs (void);
|
||||
|
||||
/* Check whether we are running on an Apple IIgs.
|
||||
*
|
||||
* Possible return values:
|
||||
* 0x00 : No
|
||||
* 0x01 : Yes
|
||||
*/
|
||||
|
||||
/* End of accelerator.h */
|
||||
#endif
|
||||
|
||||
|
|
17
libsrc/apple2/detect_iigs.s
Normal file
17
libsrc/apple2/detect_iigs.s
Normal file
|
@ -0,0 +1,17 @@
|
|||
;
|
||||
; Colin Leroy-Mira <colin@colino.net>, 2024
|
||||
;
|
||||
; void __fastcall__ detect_iigs(void)
|
||||
;
|
||||
|
||||
.export _detect_iigs
|
||||
.import ostype, return0, return1
|
||||
|
||||
.include "apple2.inc"
|
||||
|
||||
; Returns 1 if running on IIgs, 0 otherwise
|
||||
_detect_iigs:
|
||||
lda ostype
|
||||
bpl :+
|
||||
jmp return1
|
||||
: jmp return0
|
22
libsrc/apple2/get_iigs_speed.s
Normal file
22
libsrc/apple2/get_iigs_speed.s
Normal file
|
@ -0,0 +1,22 @@
|
|||
;
|
||||
; Colin Leroy-Mira <colin@colino.net>, 2024
|
||||
;
|
||||
; unsigned char __fastcall__ get_iigs_speed(void)
|
||||
;
|
||||
|
||||
.export _get_iigs_speed
|
||||
.import ostype, return0
|
||||
|
||||
.include "apple2.inc"
|
||||
.include "accelerator.inc"
|
||||
|
||||
_get_iigs_speed:
|
||||
lda ostype ; Return SLOW if not IIgs
|
||||
bpl :+
|
||||
lda CYAREG ; Check current setting
|
||||
bpl :+
|
||||
lda #SPEED_FAST
|
||||
ldx #$00
|
||||
rts
|
||||
.assert SPEED_SLOW = 0, error
|
||||
: jmp return0 ; SPEED_SLOW
|
|
@ -5,7 +5,7 @@
|
|||
;
|
||||
|
||||
.constructor initostype, 9
|
||||
.export _get_ostype
|
||||
.export _get_ostype, ostype
|
||||
|
||||
; Identify machine according to:
|
||||
; Apple II Miscellaneous TechNote #7, Apple II Family Identification
|
||||
|
|
29
libsrc/apple2/set_iigs_speed.s
Normal file
29
libsrc/apple2/set_iigs_speed.s
Normal file
|
@ -0,0 +1,29 @@
|
|||
;
|
||||
; Colin Leroy-Mira <colin@colino.net>, 2024
|
||||
;
|
||||
; unsigned char __fastcall__ detect_iigs(unsigned char speed)
|
||||
;
|
||||
|
||||
.export _set_iigs_speed
|
||||
.import ostype, return0
|
||||
|
||||
.include "apple2.inc"
|
||||
.include "accelerator.inc"
|
||||
|
||||
_set_iigs_speed:
|
||||
tax ; Keep parameter
|
||||
lda ostype ; Return if not IIgs
|
||||
bmi :+
|
||||
jmp return0
|
||||
|
||||
: lda CYAREG
|
||||
cpx #SPEED_SLOW
|
||||
beq :+
|
||||
ora #%10000000
|
||||
bne set_speed
|
||||
: and #%01111111
|
||||
set_speed:
|
||||
sta CYAREG
|
||||
txa
|
||||
ldx #$00
|
||||
rts
|
54
libsrc/apple2/sleep.s
Normal file
54
libsrc/apple2/sleep.s
Normal file
|
@ -0,0 +1,54 @@
|
|||
;
|
||||
; Colin Leroy-Mira <colin@colino.net>, 2024
|
||||
;
|
||||
; void __fastcall__ sleep(unsigned s)
|
||||
;
|
||||
;
|
||||
|
||||
.export _sleep
|
||||
.import _get_iigs_speed
|
||||
.import _set_iigs_speed
|
||||
.import WAIT
|
||||
.importzp tmp1
|
||||
|
||||
.include "accelerator.inc"
|
||||
|
||||
; This functions uses the Apple2 WAIT ROM routine to waste a certain
|
||||
; amount of cycles and returns approximately after the numbers of
|
||||
; seconds passed in AX.
|
||||
;
|
||||
; It takes 1023730 cycles when called with AX=1 (1,0007s),
|
||||
; 10236364 cycles when called with AX=10 (10,006 seconds),
|
||||
; 306064298 cycles with AX=300 (299.2 seconds).
|
||||
;
|
||||
; Caveat: IRQs firing during calls to sleep will make the sleep longer
|
||||
; by the amount of cycles it takes to handle the IRQ.
|
||||
;
|
||||
_sleep:
|
||||
stx tmp1 ; High byte of s in X
|
||||
tay ; Low byte in A
|
||||
ora tmp1
|
||||
bne :+
|
||||
rts
|
||||
: jsr _get_iigs_speed ; Save current CPU speed
|
||||
pha
|
||||
lda #SPEED_SLOW ; Down to 1MHz for consistency around WAIT
|
||||
jsr _set_iigs_speed
|
||||
sleep_1s:
|
||||
ldx #$0A ; Loop 10 times
|
||||
sleep_100ms:
|
||||
lda #$C7 ; Sleep about 99ms
|
||||
jsr WAIT
|
||||
lda #$0D ; About 1ms
|
||||
jsr WAIT
|
||||
dex
|
||||
bne sleep_100ms
|
||||
dey
|
||||
bne sleep_1s
|
||||
dec tmp1
|
||||
bmi done
|
||||
dey ; Down to #$FF
|
||||
bne sleep_1s
|
||||
done:
|
||||
pla ; Restore CPU speed
|
||||
jmp _set_iigs_speed
|
20
libsrc/apple2/wait.s
Normal file
20
libsrc/apple2/wait.s
Normal file
|
@ -0,0 +1,20 @@
|
|||
;
|
||||
; Colin Leroy-Mira, 2024
|
||||
;
|
||||
; WAIT routine
|
||||
;
|
||||
|
||||
.export WAIT
|
||||
|
||||
.include "apple2.inc"
|
||||
|
||||
.segment "LOWCODE"
|
||||
|
||||
WAIT:
|
||||
; Switch in ROM and call WAIT
|
||||
bit $C082
|
||||
jsr $FCA8 ; Vector to WAIT routine
|
||||
|
||||
; Switch in LC bank 2 for R/O and return
|
||||
bit $C080
|
||||
rts
|
|
@ -5,21 +5,11 @@
|
|||
;
|
||||
.ifdef __APPLE2ENH__
|
||||
|
||||
.constructor initvsync
|
||||
.export _waitvsync
|
||||
.import _get_ostype
|
||||
.import ostype
|
||||
|
||||
.include "apple2.inc"
|
||||
|
||||
.segment "ONCE"
|
||||
|
||||
initvsync:
|
||||
jsr _get_ostype
|
||||
sta ostype
|
||||
rts
|
||||
|
||||
.code
|
||||
|
||||
_waitvsync:
|
||||
bit ostype
|
||||
bmi iigs ; $8x
|
||||
|
@ -53,8 +43,4 @@ iic: sei
|
|||
cli
|
||||
rts
|
||||
|
||||
.segment "INIT"
|
||||
|
||||
ostype: .res 1
|
||||
|
||||
.endif ; __APPLE2ENH__
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
.import ldeaxysp, decsp2, pushax, incsp8
|
||||
.import tosandeax,decax1,tosdiveax,axlong,ldaxysp
|
||||
.import lynxskip0, lynxblock,tosasreax
|
||||
.import __BLOCKSIZE__
|
||||
.import __BANK0BLOCKSIZE__
|
||||
.importzp _FileCurrBlock
|
||||
|
||||
.segment "CODE"
|
||||
|
@ -32,15 +32,15 @@
|
|||
jsr ldeaxysp
|
||||
jsr pusheax
|
||||
ldx #$00
|
||||
lda #<(__BLOCKSIZE__/1024 + 9)
|
||||
lda #<(__BANK0BLOCKSIZE__/1024 + 9)
|
||||
jsr tosasreax
|
||||
sta _FileCurrBlock
|
||||
jsr lynxblock
|
||||
ldy #$05
|
||||
jsr ldeaxysp
|
||||
jsr pusheax
|
||||
lda #<(__BLOCKSIZE__-1)
|
||||
ldx #>(__BLOCKSIZE__-1)
|
||||
lda #<(__BANK0BLOCKSIZE__-1)
|
||||
ldx #>(__BANK0BLOCKSIZE__-1)
|
||||
jsr axlong
|
||||
jsr tosandeax
|
||||
eor #$FF
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
.include "extzp.inc"
|
||||
.export lynxskip0, lynxread0
|
||||
.export lynxblock
|
||||
.import __BLOCKSIZE__
|
||||
.import __BANK0BLOCKSIZE__
|
||||
|
||||
.code
|
||||
|
||||
|
@ -88,7 +88,7 @@ lynxblock:
|
|||
lda __iodat
|
||||
sta IODAT
|
||||
stz _FileBlockByte
|
||||
lda #<($100-(>__BLOCKSIZE__))
|
||||
lda #<($100-(>__BANK0BLOCKSIZE__))
|
||||
sta _FileBlockByte+1
|
||||
ply
|
||||
plx
|
||||
|
|
|
@ -33,7 +33,7 @@ loop1:
|
|||
cont1:
|
||||
jsr read_byte
|
||||
sta (load_ptr2),y
|
||||
sta PALETTE ; feedback ;-)
|
||||
sta PALETTE + 1 ; feedback ;-)
|
||||
iny
|
||||
bne loop1
|
||||
inc load_ptr2+1
|
||||
|
@ -69,6 +69,8 @@ again:
|
|||
; last action : clear interrupt
|
||||
;
|
||||
exit:
|
||||
lda #$10
|
||||
sta INTRST
|
||||
clc
|
||||
rts
|
||||
|
||||
|
|
|
@ -8,12 +8,18 @@
|
|||
.import incsp2
|
||||
.importzp sp, ptr1
|
||||
|
||||
.macpack cpu
|
||||
|
||||
.proc popptr1 ; 14 bytes (four usages = at least 2 bytes saved)
|
||||
ldy #1
|
||||
lda (sp),y ; get hi byte
|
||||
sta ptr1+1 ; into ptr hi
|
||||
dey ; no optimization for 65C02 here to have Y=0 at exit!
|
||||
dey ; dey even for for 65C02 here to have Y=0 at exit!
|
||||
.if (.cpu .bitand ::CPU_ISET_65SC02)
|
||||
lda (sp) ; get lo byte
|
||||
.else
|
||||
lda (sp),y ; get lo byte
|
||||
.endif
|
||||
sta ptr1 ; to ptr lo
|
||||
jmp incsp2
|
||||
.endproc
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
.export push0, pusha0, pushax
|
||||
.importzp sp
|
||||
|
||||
.macpack cpu
|
||||
|
||||
push0: lda #0
|
||||
pusha0: ldx #0
|
||||
|
||||
|
@ -29,7 +31,11 @@ pusha0: ldx #0
|
|||
sta (sp),y ; (27)
|
||||
pla ; (31)
|
||||
dey ; (33)
|
||||
.if (.cpu .bitand ::CPU_ISET_65SC02)
|
||||
sta (sp) ; (37)
|
||||
.else
|
||||
sta (sp),y ; (38)
|
||||
rts ; (44)
|
||||
.endif
|
||||
rts ; (44/43)
|
||||
|
||||
.endproc
|
||||
|
|
|
@ -121,7 +121,7 @@ static void Parse (void)
|
|||
}
|
||||
|
||||
/* Read the declaration specifier */
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_NONE);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT | TS_FUNCTION_SPEC, SC_NONE);
|
||||
|
||||
/* Don't accept illegal storage classes */
|
||||
if ((Spec.StorageClass & SC_STORAGEMASK) == SC_AUTO ||
|
||||
|
@ -163,19 +163,19 @@ static void Parse (void)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Check if we must reserve storage for the variable. We do this,
|
||||
**
|
||||
** - if it is not a typedef or function,
|
||||
** - if we don't had a storage class given ("int i")
|
||||
** - if the storage class is explicitly specified as static,
|
||||
** - or if there is an initialization.
|
||||
**
|
||||
** This means that "extern int i;" will not get storage allocated
|
||||
** in this translation unit.
|
||||
*/
|
||||
/* The symbol is now visible in the file scope */
|
||||
if ((Decl.StorageClass & SC_TYPEMASK) != SC_FUNC &&
|
||||
(Decl.StorageClass & SC_TYPEMASK) != SC_TYPEDEF) {
|
||||
/* The variable is visible in the file scope */
|
||||
/* Check if we must reserve storage for the variable. We do this,
|
||||
**
|
||||
** - if it is not a typedef or function,
|
||||
** - if we don't had a storage class given ("int i")
|
||||
** - if the storage class is explicitly specified as static,
|
||||
** - or if there is an initialization.
|
||||
**
|
||||
** This means that "extern int i;" will not get storage allocated
|
||||
** in this translation unit.
|
||||
*/
|
||||
if ((Decl.StorageClass & SC_STORAGEMASK) == SC_NONE ||
|
||||
(Decl.StorageClass & SC_STORAGEMASK) == SC_STATIC ||
|
||||
((Decl.StorageClass & SC_STORAGEMASK) == SC_EXTERN &&
|
||||
|
@ -189,7 +189,6 @@ static void Parse (void)
|
|||
** or semicolon, it must be followed by a function body.
|
||||
*/
|
||||
if ((Decl.StorageClass & SC_TYPEMASK) == SC_FUNC) {
|
||||
/* The function is now visible in the file scope */
|
||||
if (CurTok.Tok == TOK_LCURLY) {
|
||||
/* A definition */
|
||||
Decl.StorageClass |= SC_DEF;
|
||||
|
@ -560,6 +559,10 @@ void Compile (const char* FileName)
|
|||
if ((Entry->Flags & SC_STORAGEMASK) == SC_STATIC && SymIsRef (Entry)) {
|
||||
Warning ("Static function '%s' used but never defined",
|
||||
Entry->Name);
|
||||
} else if ((Entry->Flags & SC_INLINE) != 0) {
|
||||
Warning ("Inline function '%s' %s but never defined",
|
||||
Entry->Name,
|
||||
SymIsRef (Entry) ? "used" : "declared");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@ unsigned OptLongAssign (CodeSeg* S)
|
|||
L[0] = CS_GetEntry (S, I);
|
||||
|
||||
if (CS_GetEntries (S, L+1, I+1, 12)) {
|
||||
CodeEntry* N;
|
||||
if (/* Check the opcode sequence */
|
||||
L[0]->OPC == OP65_LDA &&
|
||||
L[1]->OPC == OP65_STA &&
|
||||
|
@ -119,11 +120,13 @@ unsigned OptLongAssign (CodeSeg* S)
|
|||
!RegXUsed (S, I+12) &&
|
||||
!CS_RangeHasLabel(S, I, 12)) {
|
||||
|
||||
L[1]->AM = L[11]->AM;
|
||||
CE_SetArg(L[1], L[11]->Arg);
|
||||
N = NewCodeEntry (OP65_STA, L[11]->AM, L[11]->Arg, 0, L[11]->LI);
|
||||
CS_DelEntry (S, I+1);
|
||||
CS_InsertEntry (S, N, I+1);
|
||||
|
||||
L[3]->AM = L[9]->AM;
|
||||
CE_SetArg(L[3], L[9]->Arg);
|
||||
N = NewCodeEntry (OP65_STA, L[9]->AM, L[9]->Arg, 0, L[9]->LI);
|
||||
CS_DelEntry (S, I+3);
|
||||
CS_InsertEntry (S, N, I+3);
|
||||
|
||||
CS_DelEntries (S, I+8, 4);
|
||||
|
||||
|
@ -179,6 +182,7 @@ unsigned OptLongCopy (CodeSeg* S)
|
|||
L[0] = CS_GetEntry (S, I);
|
||||
|
||||
if (CS_GetEntries (S, L+1, I+1, 12)) {
|
||||
CodeEntry *N;
|
||||
if (L[0]->OPC == OP65_LDA &&
|
||||
!strncmp(L[0]->Arg, L[5]->Arg, strlen(L[5]->Arg)) &&
|
||||
!strcmp(L[0]->Arg + strlen(L[5]->Arg), "+3") &&
|
||||
|
@ -210,11 +214,13 @@ unsigned OptLongCopy (CodeSeg* S)
|
|||
!RegXUsed (S, I+11) &&
|
||||
!CS_RangeHasLabel(S, I, 12)) {
|
||||
|
||||
L[1]->AM = L[11]->AM;
|
||||
CE_SetArg(L[1], L[11]->Arg);
|
||||
N = NewCodeEntry (OP65_STA, L[11]->AM, L[11]->Arg, 0, L[11]->LI);
|
||||
CS_DelEntry (S, I+1);
|
||||
CS_InsertEntry (S, N, I+1);
|
||||
|
||||
L[3]->AM = L[9]->AM;
|
||||
CE_SetArg(L[3], L[9]->Arg);
|
||||
N = NewCodeEntry (OP65_STA, L[9]->AM, L[9]->Arg, 0, L[9]->LI);
|
||||
CS_DelEntry (S, I+3);
|
||||
CS_InsertEntry (S, N, I+3);
|
||||
|
||||
CS_DelEntries (S, I+8, 4);
|
||||
|
||||
|
|
|
@ -124,9 +124,37 @@ static unsigned ParseOneStorageClass (void)
|
|||
|
||||
|
||||
|
||||
static unsigned ParseOneFuncSpec (void)
|
||||
/* Parse and return a function specifier */
|
||||
{
|
||||
unsigned FuncSpec = 0;
|
||||
|
||||
/* Check the function specifier given */
|
||||
switch (CurTok.Tok) {
|
||||
|
||||
case TOK_INLINE:
|
||||
FuncSpec = SC_INLINE;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_NORETURN:
|
||||
FuncSpec = SC_NORETURN;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FuncSpec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int ParseStorageClass (DeclSpec* Spec)
|
||||
/* Parse storage class specifiers. Return true if a specifier is read even if
|
||||
** it was duplicated or disallowed. */
|
||||
** it was duplicated or disallowed.
|
||||
*/
|
||||
{
|
||||
/* Check the storage class given */
|
||||
unsigned StorageClass = ParseOneStorageClass ();
|
||||
|
@ -151,6 +179,31 @@ static int ParseStorageClass (DeclSpec* Spec)
|
|||
|
||||
|
||||
|
||||
static int ParseFuncSpecClass (DeclSpec* Spec)
|
||||
/* Parse function specifiers. Return true if a specifier is read even if it
|
||||
** was duplicated or disallowed.
|
||||
*/
|
||||
{
|
||||
/* Check the function specifiers given */
|
||||
unsigned FuncSpec = ParseOneFuncSpec ();
|
||||
|
||||
if (FuncSpec == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (FuncSpec != 0) {
|
||||
if ((Spec->StorageClass & FuncSpec) != 0) {
|
||||
Warning ("Duplicate function specifier");
|
||||
}
|
||||
Spec->StorageClass |= FuncSpec;
|
||||
FuncSpec = ParseOneFuncSpec ();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DuplicateQualifier (const char* Name)
|
||||
/* Print an error message */
|
||||
{
|
||||
|
@ -303,7 +356,8 @@ static void OptionalSpecifiers (DeclSpec* Spec, TypeCode* Qualifiers, typespec_t
|
|||
*/
|
||||
{
|
||||
TypeCode Q = T_QUAL_NONE;
|
||||
int Continue;
|
||||
int HasStorageClass;
|
||||
int HasFuncSpec;
|
||||
|
||||
do {
|
||||
/* There may be type qualifiers *before* any storage class specifiers */
|
||||
|
@ -311,11 +365,17 @@ static void OptionalSpecifiers (DeclSpec* Spec, TypeCode* Qualifiers, typespec_t
|
|||
*Qualifiers |= Q;
|
||||
|
||||
/* Parse storage class specifiers anyway then check */
|
||||
Continue = ParseStorageClass (Spec);
|
||||
if (Continue && (TSFlags & (TS_STORAGE_CLASS_SPEC | TS_FUNCTION_SPEC)) == 0) {
|
||||
HasStorageClass = ParseStorageClass (Spec);
|
||||
if (HasStorageClass && (TSFlags & TS_STORAGE_CLASS_SPEC) == 0) {
|
||||
Error ("Unexpected storage class specified");
|
||||
}
|
||||
} while (Continue || Q != T_QUAL_NONE);
|
||||
|
||||
/* Parse function specifiers anyway then check */
|
||||
HasFuncSpec = ParseFuncSpecClass (Spec);
|
||||
if (HasFuncSpec && (TSFlags & TS_FUNCTION_SPEC) == 0) {
|
||||
Error ("Unexpected function specifiers");
|
||||
}
|
||||
} while (Q != T_QUAL_NONE || HasStorageClass || HasFuncSpec);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2375,6 +2435,14 @@ int ParseDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
|||
/* Parse attributes for this declarator */
|
||||
ParseAttribute (D);
|
||||
|
||||
/* 'inline' is only allowed on functions */
|
||||
if (Mode != DM_ACCEPT_PARAM_IDENT &&
|
||||
(D->StorageClass & SC_TYPEMASK) != SC_FUNC &&
|
||||
(D->StorageClass & SC_INLINE) == SC_INLINE) {
|
||||
Error ("'inline' on non-function declaration");
|
||||
D->StorageClass &= ~SC_INLINE;
|
||||
}
|
||||
|
||||
/* Check a few pre-C99 things */
|
||||
if (D->Ident[0] != '\0' && (Spec->Flags & DS_TYPE_MASK) == DS_DEF_TYPE) {
|
||||
/* Check and warn about an implicit int return in the function */
|
||||
|
@ -2478,7 +2546,7 @@ void ParseDeclSpec (DeclSpec* Spec, typespec_t TSFlags, unsigned DefStorage)
|
|||
Spec->Flags &= ~DS_DEF_STORAGE;
|
||||
|
||||
/* Parse the type specifiers */
|
||||
ParseTypeSpec (Spec, TSFlags | TS_STORAGE_CLASS_SPEC | TS_FUNCTION_SPEC);
|
||||
ParseTypeSpec (Spec, TSFlags | TS_STORAGE_CLASS_SPEC);
|
||||
|
||||
/* If no explicit storage class is given, use the default */
|
||||
if ((Spec->StorageClass & SC_STORAGEMASK) == 0) {
|
||||
|
@ -2495,7 +2563,9 @@ void CheckEmptyDecl (const DeclSpec* Spec)
|
|||
** warning if not.
|
||||
*/
|
||||
{
|
||||
if ((Spec->Flags & DS_TYPE_MASK) == DS_NONE) {
|
||||
if ((Spec->StorageClass & SC_INLINE) == SC_INLINE) {
|
||||
Error ("'inline' on empty declaration");
|
||||
} else if ((Spec->Flags & DS_TYPE_MASK) == DS_NONE) {
|
||||
/* No declaration at all */
|
||||
} else if ((Spec->Flags & DS_EXTRA_TYPE) == 0) {
|
||||
Warning ("Declaration does not declare anything");
|
||||
|
|
|
@ -1421,7 +1421,7 @@ static void Primary (ExprDesc* E)
|
|||
} else {
|
||||
/* Let's see if this is a C99-style declaration */
|
||||
DeclSpec Spec;
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE | TS_FUNCTION_SPEC, SC_AUTO);
|
||||
|
||||
if ((Spec.Flags & DS_TYPE_MASK) != DS_NONE) {
|
||||
Error ("Mixed declarations and code are not supported in cc65");
|
||||
|
|
|
@ -518,6 +518,12 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
|||
Error ("'main' cannot be declared as __fastcall__");
|
||||
}
|
||||
|
||||
/* main() cannot be an inline function */
|
||||
if ((Func->Flags & SC_INLINE) == SC_INLINE) {
|
||||
Error ("'main' cannot be declared inline");
|
||||
Func->Flags &= ~SC_INLINE;
|
||||
}
|
||||
|
||||
/* Check return type */
|
||||
if (GetUnqualRawTypeCode (ReturnType) == T_INT) {
|
||||
/* Determine if this is a main function in a C99 environment that
|
||||
|
@ -685,9 +691,6 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
|||
/* Leave the lexical level */
|
||||
LeaveFunctionLevel ();
|
||||
|
||||
/* Eat the closing brace */
|
||||
ConsumeRCurly ();
|
||||
|
||||
/* Restore the old literal pool, remembering the one for the function */
|
||||
Func->V.F.LitPool = PopLiteralPool ();
|
||||
|
||||
|
@ -699,6 +702,12 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
|||
/* Switch back to the old segments */
|
||||
PopSegContext ();
|
||||
|
||||
/* Eat the closing brace after we've done everything with the function
|
||||
** definition. This way we won't have troubles with pragmas right after
|
||||
** the closing brace.
|
||||
*/
|
||||
ConsumeRCurly();
|
||||
|
||||
/* Reset the current function pointer */
|
||||
FreeFunction (CurrentFunc);
|
||||
CurrentFunc = 0;
|
||||
|
|
|
@ -584,7 +584,7 @@ void DeclareLocals (void)
|
|||
}
|
||||
|
||||
/* Read the declaration specifier */
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_AUTO);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT | TS_FUNCTION_SPEC, SC_AUTO);
|
||||
|
||||
/* Check variable declarations. We need distinguish between a default
|
||||
** int type and the end of variable declarations. So we will do the
|
||||
|
|
|
@ -76,6 +76,7 @@ typedef enum token_t {
|
|||
|
||||
/* Function specifiers */
|
||||
TOK_INLINE,
|
||||
TOK_NORETURN,
|
||||
TOK_FASTCALL,
|
||||
TOK_CDECL,
|
||||
|
||||
|
|
|
@ -151,6 +151,10 @@ struct CodeEntry;
|
|||
#define SC_THREAD 0x08000000U /* UNSUPPORTED: Thread-local storage class */
|
||||
#define SC_STORAGEMASK 0x0F000000U /* Storage type mask */
|
||||
|
||||
/* Function specifiers */
|
||||
#define SC_INLINE 0x10000000U /* Inline function */
|
||||
#define SC_NORETURN 0x20000000U /* Noreturn function */
|
||||
|
||||
|
||||
|
||||
/* Label definition or reference */
|
||||
|
|
|
@ -557,8 +557,10 @@ static SymEntry* FindSymInTable (const SymTable* T, const char* Name, unsigned H
|
|||
|
||||
|
||||
|
||||
static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name)
|
||||
/* Find the symbol with the given name in the table tree that starts with T */
|
||||
static SymEntry* FindVisibleSymInTree (const SymTable* Tab, const char* Name)
|
||||
/* Find the visible symbol with the given name in the table tree that starts
|
||||
** with Tab.
|
||||
*/
|
||||
{
|
||||
/* Get the hash over the name */
|
||||
unsigned Hash = HashStr (Name);
|
||||
|
@ -574,7 +576,7 @@ static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name)
|
|||
}
|
||||
|
||||
/* Bail out if we found it */
|
||||
if (E != 0) {
|
||||
if (E != 0 && (Tab != SymTab0 || (E->Flags & SC_LOCALSCOPE) == 0)) {
|
||||
return E;
|
||||
}
|
||||
|
||||
|
@ -589,9 +591,9 @@ static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name)
|
|||
|
||||
|
||||
SymEntry* FindSym (const char* Name)
|
||||
/* Find the symbol with the given name */
|
||||
/* Find with the given name the symbol visible in the current scope */
|
||||
{
|
||||
return FindSymInTree (SymTab, Name);
|
||||
return FindVisibleSymInTree (SymTab, Name);
|
||||
}
|
||||
|
||||
|
||||
|
@ -613,9 +615,9 @@ SymEntry* FindLocalSym (const char* Name)
|
|||
|
||||
|
||||
SymEntry* FindTagSym (const char* Name)
|
||||
/* Find the symbol with the given name in the tag table */
|
||||
/* Find with the given name the tag symbol visible in the current scope */
|
||||
{
|
||||
return FindSymInTree (TagTab, Name);
|
||||
return FindVisibleSymInTree (TagTab, Name);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1356,6 +1358,13 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
|||
Name);
|
||||
Entry = 0;
|
||||
} else if ((Flags & SC_TYPEMASK) != SC_TYPEDEF) {
|
||||
/* If we are adding the symbol in the file scope, it is now
|
||||
** visible there.
|
||||
*/
|
||||
if (SymTab == SymTab0) {
|
||||
Entry->Flags &= ~SC_LOCALSCOPE;
|
||||
}
|
||||
|
||||
/* The C standard specifies that the result is undefined if the
|
||||
** same thing has both internal and external linkage. Most
|
||||
** compilers choose to either give an error at compile time, or
|
||||
|
@ -1415,6 +1424,13 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
|||
}
|
||||
|
||||
if (Entry == 0) {
|
||||
/* Hide the symbol in the file scope if we are declaring it in a
|
||||
** local scope.
|
||||
*/
|
||||
if (Tab == SymTab0 && SymTab != SymTab0) {
|
||||
Flags |= SC_LOCALSCOPE;
|
||||
}
|
||||
|
||||
/* Create a new entry */
|
||||
Entry = NewSymEntry (Name, Flags);
|
||||
|
||||
|
@ -1439,6 +1455,16 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
|||
Entry->V.F.WrappedCall = WrappedCall;
|
||||
Entry->V.F.WrappedCallData = WrappedCallData;
|
||||
}
|
||||
|
||||
/* A files cope function declaration with the 'extern' storage
|
||||
** class or without the 'inline' specifier ensures that the
|
||||
** function definition (if any) is a non-inline definition.
|
||||
*/
|
||||
if (SymTab == SymTab0 &&
|
||||
((Flags & SC_STORAGEMASK) == SC_EXTERN ||
|
||||
(Flags & SC_INLINE) == 0)) {
|
||||
Entry->Flags |= SC_NOINLINEDEF;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add an alias of the global symbol to the local symbol table */
|
||||
|
@ -1575,7 +1601,7 @@ void EmitExternals (void)
|
|||
if (SymIsRef (Entry) && !SymIsDef (Entry)) {
|
||||
/* An import */
|
||||
g_defimport (Entry->Name, Flags & SC_ZEROPAGE);
|
||||
} else if (SymIsDef (Entry)) {
|
||||
} else if (SymIsDef (Entry) && ((Flags & SC_NOINLINEDEF) || (Flags & SC_INLINE) == 0)) {
|
||||
/* An export */
|
||||
g_defexport (Entry->Name, Flags & SC_ZEROPAGE);
|
||||
}
|
||||
|
|
|
@ -142,7 +142,7 @@ void LeaveStructLevel (void);
|
|||
|
||||
|
||||
SymEntry* FindSym (const char* Name);
|
||||
/* Find the symbol with the given name */
|
||||
/* Find with the given name the symbol visible in the current scope */
|
||||
|
||||
SymEntry* FindGlobalSym (const char* Name);
|
||||
/* Find the symbol with the given name in the global symbol table only */
|
||||
|
@ -151,7 +151,7 @@ SymEntry* FindLocalSym (const char* Name);
|
|||
/* Find the symbol with the given name in the current symbol table only */
|
||||
|
||||
SymEntry* FindTagSym (const char* Name);
|
||||
/* Find the symbol with the given name in the tag table */
|
||||
/* Find with the given name the tag symbol visible in the current scope */
|
||||
|
||||
SymEntry FindStructField (const Type* TypeArray, const char* Name);
|
||||
/* Find a struct/union field in the fields list.
|
||||
|
|
15
test/err/bug2304-var-use.c
Normal file
15
test/err/bug2304-var-use.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
/* Bug 2304 - Visibility of objects/functions undeclared in file scope but 'extern'-declared in unrelated block scopes */
|
||||
|
||||
void f1(void)
|
||||
{
|
||||
extern int a;
|
||||
}
|
||||
|
||||
/* 'a' is still invisible in the file scope */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return a * 0; /* Usage of 'a' should be an error */
|
||||
}
|
||||
|
||||
int a = 42;
|
|
@ -133,6 +133,12 @@ $(WORKDIR)/goto.$1.$2.prg: goto.c $(ISEQUAL) | $(WORKDIR)
|
|||
$(CC65) -t sim$2 -$1 -o $$@ $$< 2>$(WORKDIR)/goto.$1.$2.out
|
||||
$(ISEQUAL) $(WORKDIR)/goto.$1.$2.out goto.ref
|
||||
|
||||
# this one requires failure with --std=c89, it fails with --std=cc65 due to
|
||||
# stricter checks
|
||||
$(WORKDIR)/bug2304-implicit-func.$1.$2.prg: bug2304-implicit-func.c | $(WORKDIR)
|
||||
$(if $(QUIET),echo misc/bug2304-implicit-func.$1.$2.prg)
|
||||
$(NOT) $(CC65) --standard c89 -t sim$2 -$1 -o $$@ $$< $(NULLERR)
|
||||
|
||||
# should not compile until 3-byte struct by value tests are re-enabled
|
||||
$(WORKDIR)/struct-by-value.$1.$2.prg: struct-by-value.c | $(WORKDIR)
|
||||
$(if $(QUIET),echo misc/struct-by-value.$1.$2.prg)
|
||||
|
|
21
test/misc/bug2304-implicit-func.c
Normal file
21
test/misc/bug2304-implicit-func.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* Bug 2304 - Visibility of objects/functions undeclared in file scope but 'extern'-declared in unrelated block scopes */
|
||||
|
||||
/* This one should fail even in C89 */
|
||||
|
||||
void f1(void)
|
||||
{
|
||||
extern unsigned int f();
|
||||
}
|
||||
|
||||
/* 'f' is still invisible in the file scope */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
f(); /* Should be a conflict since the implicit function type is incompatible */
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int f()
|
||||
{
|
||||
return 42;
|
||||
}
|
|
@ -63,6 +63,7 @@ CUSTOMSOURCES = \
|
|||
# exact error output is required
|
||||
ERRORSOURCES = \
|
||||
custom-reference-error.c \
|
||||
inline-error.c \
|
||||
bug1889-missing-identifier.c \
|
||||
bug2312-preprocessor-error.c
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
bug1889-missing-identifier.c:3: Error: Identifier or ';' expected after declaration specifiers
|
||||
bug1889-missing-identifier.c:3: Warning: Implicit 'int' is an obsolete feature
|
||||
bug1889-missing-identifier.c:4: Error: Declaration specifier or identifier expected
|
||||
bug1889-missing-identifier.c:4: Error: 'inline' on empty declaration
|
||||
bug1889-missing-identifier.c:6: Error: Expression expected
|
||||
|
|
36
test/ref/inline-error.c
Normal file
36
test/ref/inline-error.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* C99 inline in declarations */
|
||||
|
||||
inline typedef int; /* Error */
|
||||
static inline int; /* Error */
|
||||
inline static int a1; /* Error */
|
||||
int inline (*fp1)(void); /* Error */
|
||||
typedef inline int f1_t(void); /* Error */
|
||||
inline int f1a(void); /* OK here warning later */
|
||||
inline extern int f1b(void); /* OK here warning later */
|
||||
extern inline int f1b(void); /* Same as above */
|
||||
inline static int f1c(void); /* OK here warning later */
|
||||
static inline int f1c(void); /* Same as above */
|
||||
|
||||
void foo(inline int x); /* Error */
|
||||
int a = sizeof (inline int); /* TODO: better error message */
|
||||
int b = sizeof (inline int (int)); /* TODO: better error message */
|
||||
|
||||
inline int main(void) /* Error */
|
||||
{
|
||||
inline typedef int; /* Error */
|
||||
static inline int; /* Error */
|
||||
extern inline int a2; /* Error */
|
||||
int inline (*fp2)(void); /* Error */
|
||||
typedef inline int f2_t(void); /* Error */
|
||||
inline int f2a(void); /* OK here warning later */
|
||||
inline extern int f2b(void); /* OK here warning later */
|
||||
extern inline int f2b(void); /* Same as above */
|
||||
|
||||
f1a(); /* Still imported */
|
||||
f1b(); /* Still imported */
|
||||
f1c(); /* Not imported */
|
||||
f2a(); /* Still imported */
|
||||
f2b(); /* Still imported */
|
||||
}
|
||||
|
||||
/* Warning: non-external inline functions declared but undefined in TU */
|
20
test/ref/inline-error.cref
Normal file
20
test/ref/inline-error.cref
Normal file
|
@ -0,0 +1,20 @@
|
|||
inline-error.c:3: Error: 'inline' on empty declaration
|
||||
inline-error.c:4: Error: 'inline' on empty declaration
|
||||
inline-error.c:5: Error: 'inline' on non-function declaration
|
||||
inline-error.c:6: Error: 'inline' on non-function declaration
|
||||
inline-error.c:7: Error: 'inline' on non-function declaration
|
||||
inline-error.c:14: Error: Unexpected function specifiers
|
||||
inline-error.c:15: Error: Mixed declarations and code are not supported in cc65
|
||||
inline-error.c:16: Error: Mixed declarations and code are not supported in cc65
|
||||
inline-error.c:19: Error: 'main' cannot be declared inline
|
||||
inline-error.c:20: Error: 'inline' on empty declaration
|
||||
inline-error.c:21: Error: 'inline' on empty declaration
|
||||
inline-error.c:22: Error: 'inline' on non-function declaration
|
||||
inline-error.c:23: Error: 'inline' on non-function declaration
|
||||
inline-error.c:24: Error: 'inline' on non-function declaration
|
||||
inline-error.c:34: Warning: Variable 'fp2' is defined but never used
|
||||
inline-error.c:37: Warning: Inline function 'f1a' used but never defined
|
||||
inline-error.c:37: Warning: Inline function 'f1b' used but never defined
|
||||
inline-error.c:37: Warning: Static function 'f1c' used but never defined
|
||||
inline-error.c:37: Warning: Inline function 'f2a' used but never defined
|
||||
inline-error.c:37: Warning: Inline function 'f2b' used but never defined
|
38
test/val/bug2357.c
Normal file
38
test/val/bug2357.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* bug #2357 - Compiler produces invalid code after d8a3938
|
||||
*/
|
||||
|
||||
unsigned long test;
|
||||
|
||||
unsigned long longarray[7];
|
||||
|
||||
void jsr_threebytes(void) {
|
||||
|
||||
}
|
||||
|
||||
/* having replaced two sty $zp with two sta $abs, but forgetting
|
||||
* to update the instruction size, coptlong.c could cause a build
|
||||
* error "Error: Range error (131 not in [-128..127])" if the
|
||||
* computed codesize was under 126, but the real codesize was above
|
||||
* 127.
|
||||
* This tests verifies that the bug is fixed.
|
||||
*/
|
||||
unsigned char __fastcall__ foo (unsigned char res)
|
||||
{
|
||||
if (res == 0) {
|
||||
longarray[1]=test; /* 24 bytes - but the compiler thought 22 */
|
||||
longarray[2]=test; /* 48 bytes - but 44 */
|
||||
longarray[3]=test; /* 72 bytes - 66 */
|
||||
longarray[4]=test; /* 96 bytes - 88 */
|
||||
longarray[6]=test; /* 120 bytes - 110 */
|
||||
jsr_threebytes(); /* 123 - 113 */
|
||||
jsr_threebytes(); /* 126 - 116 */
|
||||
jsr_threebytes(); /* 129 - 119 */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
foo(42);
|
||||
return 0;
|
||||
}
|
20
test/val/inline-func.c
Normal file
20
test/val/inline-func.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* C99 inline */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
inline static int f(int x, ...)
|
||||
{
|
||||
return x * 2;
|
||||
}
|
||||
|
||||
extern inline int g(int x);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return f(g(7)) == 42 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int g(int x)
|
||||
{
|
||||
return x * 3;
|
||||
}
|
Loading…
Reference in New Issue
Block a user