1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-26 05:29:30 +00:00

Merge branch 'master' into fptest

This commit is contained in:
mrdudz 2023-12-10 00:25:23 +01:00
commit 70c32a039b
27 changed files with 612 additions and 214 deletions

View File

@ -2867,6 +2867,26 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".CHARMAP" name=".CH
overridden. When using this feature, you may also get into trouble if overridden. When using this feature, you may also get into trouble if
later versions of the assembler define new keywords starting with a dot. later versions of the assembler define new keywords starting with a dot.
<tag><tt>line_continuations</tt><label id="line_continuations"></tag>
Switch on or off line continuations using the backslash character
before a newline. The option is off by default.
Note: Line continuations do not work in a comment. A backslash at the
end of a comment is treated as part of the comment and does not trigger
line continuation.
Example:
<tscreen><verb>
.feature line_continuations + ; Allow line continuations
lda \
#$20 ; This is legal now
</verb></tscreen>
For backward compatibility reasons, the <tt>.LINECONT +</tt> control command
is also supported and enables the same feature.
<tag><tt>long_jsr_jmp_rts</tt><label id="long_jsr_jmp_rts"></tag> <tag><tt>long_jsr_jmp_rts</tt><label id="long_jsr_jmp_rts"></tag>
Affects 65816 mode only. Affects 65816 mode only.
@ -3371,26 +3391,6 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".CHARMAP" name=".CH
the feature in more detail. the feature in more detail.
<sect1><tt>.LINECONT</tt><label id=".LINECONT"><p>
Switch on or off line continuations using the backslash character
before a newline. The option is off by default.
Note: Line continuations do not work in a comment. A backslash at the
end of a comment is treated as part of the comment and does not trigger
line continuation.
The command can be followed by a '+' or '-' character to switch the
option on or off respectively.
Example:
<tscreen><verb>
.linecont + ; Allow line continuations
lda \
#$20 ; This is legal now
</verb></tscreen>
<sect1><tt>.LIST</tt><label id=".LIST"><p> <sect1><tt>.LIST</tt><label id=".LIST"><p>
Enable output to the listing. The command can be followed by a boolean Enable output to the listing. The command can be followed by a boolean
@ -4489,9 +4489,9 @@ different:
<item> Macros defined with <tt><ref id=".DEFINE" name=".DEFINE"></tt> may not <item> Macros defined with <tt><ref id=".DEFINE" name=".DEFINE"></tt> may not
span more than a line. You may use line continuation (see <tt><ref span more than a line. You may use line continuation (see <tt><ref
id=".LINECONT" name=".LINECONT"></tt>) to spread the definition over id="line_continuations" name="line_continuations"></tt>) to spread the
more than one line for increased readability, but the macro itself definition over more than one line for increased readability, but the
may not contain an end-of-line token. macro itself may not contain an end-of-line token.
<item> Macros defined with <tt><ref id=".DEFINE" name=".DEFINE"></tt> share <item> Macros defined with <tt><ref id=".DEFINE" name=".DEFINE"></tt> share
the name space with classic macros, but they are detected and replaced the name space with classic macros, but they are detected and replaced

View File

@ -67,6 +67,7 @@ static const char* const FeatureKeys[FEAT_COUNT] = {
"bracket_as_indirect", "bracket_as_indirect",
"string_escapes", "string_escapes",
"long_jsr_jmp_rts", "long_jsr_jmp_rts",
"line_continuations",
}; };
@ -121,6 +122,7 @@ void SetFeature (feature_t Feature, unsigned char On)
case FEAT_BRACKET_AS_INDIRECT: BracketAsIndirect = On; break; case FEAT_BRACKET_AS_INDIRECT: BracketAsIndirect = On; break;
case FEAT_STRING_ESCAPES: StringEscapes = On; break; case FEAT_STRING_ESCAPES: StringEscapes = On; break;
case FEAT_LONG_JSR_JMP_RTS: LongJsrJmpRts = On; break; case FEAT_LONG_JSR_JMP_RTS: LongJsrJmpRts = On; break;
case FEAT_LINE_CONTINUATIONS: LineCont = On; break;
default: break; default: break;
} }
} }

View File

@ -69,6 +69,7 @@ typedef enum {
FEAT_BRACKET_AS_INDIRECT, FEAT_BRACKET_AS_INDIRECT,
FEAT_STRING_ESCAPES, FEAT_STRING_ESCAPES,
FEAT_LONG_JSR_JMP_RTS, FEAT_LONG_JSR_JMP_RTS,
FEAT_LINE_CONTINUATIONS,
/* Special value: Number of features available */ /* Special value: Number of features available */
FEAT_COUNT FEAT_COUNT

View File

@ -69,6 +69,7 @@
<ClInclude Include="cc65\coptcmp.h" /> <ClInclude Include="cc65\coptcmp.h" />
<ClInclude Include="cc65\coptind.h" /> <ClInclude Include="cc65\coptind.h" />
<ClInclude Include="cc65\coptjmp.h" /> <ClInclude Include="cc65\coptjmp.h" />
<ClInclude Include="cc65\coptlong.h" />
<ClInclude Include="cc65\coptmisc.h" /> <ClInclude Include="cc65\coptmisc.h" />
<ClInclude Include="cc65\coptptrload.h" /> <ClInclude Include="cc65\coptptrload.h" />
<ClInclude Include="cc65\coptptrstore.h" /> <ClInclude Include="cc65\coptptrstore.h" />
@ -150,6 +151,7 @@
<ClCompile Include="cc65\coptcmp.c" /> <ClCompile Include="cc65\coptcmp.c" />
<ClCompile Include="cc65\coptind.c" /> <ClCompile Include="cc65\coptind.c" />
<ClCompile Include="cc65\coptjmp.c" /> <ClCompile Include="cc65\coptjmp.c" />
<ClCompile Include="cc65\coptlong.c" />
<ClCompile Include="cc65\coptmisc.c" /> <ClCompile Include="cc65\coptmisc.c" />
<ClCompile Include="cc65\coptptrload.c" /> <ClCompile Include="cc65\coptptrload.c" />
<ClCompile Include="cc65\coptptrstore.c" /> <ClCompile Include="cc65\coptptrstore.c" />
@ -214,4 +216,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

View File

@ -723,7 +723,6 @@ void _g_getimmed(unsigned Flags, uintptr_t Val, long Offs)
/* Load a constant into the primary register */ /* Load a constant into the primary register */
{ {
unsigned char B1, B2, B3, B4; unsigned char B1, B2, B3, B4;
unsigned Done;
// LOG(("file:%s\n", file ? file : "null")); // LOG(("file:%s\n", file ? file : "null"));
// LOG(("func:%s\n", func ? func : "null")); // LOG(("func:%s\n", func ? func : "null"));
@ -767,40 +766,15 @@ void _g_getimmed(unsigned Flags, uintptr_t Val, long Offs)
B3 = (unsigned char) (Val >> 16); B3 = (unsigned char) (Val >> 16);
B4 = (unsigned char) (Val >> 24); B4 = (unsigned char) (Val >> 24);
/* Remember which bytes are done */ /* Load the value. Don't be too smart here and let
Done = 0; * the optimizer do its job.
*/
/* Load the value */ AddCodeLine ("lda #$%02X", B4);
AddCodeLine ("ldx #$%02X\t; g_getimmed LONG", B2); AddCodeLine ("sta sreg+1");
Done |= 0x02; AddCodeLine ("lda #$%02X", B3);
if (B2 == B3) { AddCodeLine ("sta sreg");
AddCodeLine ("stx sreg");
Done |= 0x04;
}
if (B2 == B4) {
AddCodeLine ("stx sreg+1");
Done |= 0x08;
}
if ((Done & 0x04) == 0 && B1 != B3) {
AddCodeLine ("lda #$%02X", B3);
AddCodeLine ("sta sreg");
Done |= 0x04;
}
if ((Done & 0x08) == 0 && B1 != B4) {
AddCodeLine ("lda #$%02X", B4);
AddCodeLine ("sta sreg+1");
Done |= 0x08;
}
AddCodeLine ("lda #$%02X", B1); AddCodeLine ("lda #$%02X", B1);
Done |= 0x01; AddCodeLine ("ldx #$%02X", B2);
if ((Done & 0x04) == 0) {
CHECK (B1 == B3);
AddCodeLine ("sta sreg");
}
if ((Done & 0x08) == 0) {
CHECK (B1 == B4);
AddCodeLine ("sta sreg+1");
}
break; break;
default: default:
@ -4096,13 +4070,7 @@ void g_dec (unsigned flags, unsigned long val)
} else { } else {
/* Inline the code */ /* Inline the code */
if (val < 0x300) { if (val < 0x300) {
if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val == 1) { if ((val & 0xFF) != 0) {
unsigned L = GetLocalLabel();
AddCodeLine ("bne %s", LocalLabelName (L));
AddCodeLine ("dex");
g_defcodelabel (L);
AddCodeLine ("dea");
} else if ((val & 0xFF) != 0) {
unsigned L = GetLocalLabel(); unsigned L = GetLocalLabel();
AddCodeLine ("sec"); AddCodeLine ("sec");
AddCodeLine ("sbc #$%02X", (unsigned char) val); AddCodeLine ("sbc #$%02X", (unsigned char) val);

View File

@ -57,6 +57,7 @@
#include "coptcmp.h" #include "coptcmp.h"
#include "coptind.h" #include "coptind.h"
#include "coptjmp.h" #include "coptjmp.h"
#include "coptlong.h"
#include "coptmisc.h" #include "coptmisc.h"
#include "coptptrload.h" #include "coptptrload.h"
#include "coptptrstore.h" #include "coptptrstore.h"
@ -150,6 +151,8 @@ static OptFunc DOptJumpTarget3 = { OptJumpTarget3, "OptJumpTarget3", 100, 0,
static OptFunc DOptLoad1 = { OptLoad1, "OptLoad1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptLoad1 = { OptLoad1, "OptLoad1", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptLoad2 = { OptLoad2, "OptLoad2", 200, 0, 0, 0, 0, 0 }; static OptFunc DOptLoad2 = { OptLoad2, "OptLoad2", 200, 0, 0, 0, 0, 0 };
static OptFunc DOptLoad3 = { OptLoad3, "OptLoad3", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptLoad3 = { OptLoad3, "OptLoad3", 0, 0, 0, 0, 0, 0 };
static OptFunc DOptLongAssign = { OptLongAssign, "OptLongAssign", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptLongCopy = { OptLongCopy, "OptLongCopy", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptNegAX1 = { OptNegAX1, "OptNegAX1", 165, 0, 0, 0, 0, 0 }; static OptFunc DOptNegAX1 = { OptNegAX1, "OptNegAX1", 165, 0, 0, 0, 0, 0 };
static OptFunc DOptNegAX2 = { OptNegAX2, "OptNegAX2", 200, 0, 0, 0, 0, 0 }; static OptFunc DOptNegAX2 = { OptNegAX2, "OptNegAX2", 200, 0, 0, 0, 0, 0 };
static OptFunc DOptPrecalc = { OptPrecalc, "OptPrecalc", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptPrecalc = { OptPrecalc, "OptPrecalc", 100, 0, 0, 0, 0, 0 };
@ -262,6 +265,8 @@ static OptFunc* OptFuncs[] = {
&DOptLoad1, &DOptLoad1,
&DOptLoad2, &DOptLoad2,
&DOptLoad3, &DOptLoad3,
&DOptLongAssign,
&DOptLongCopy,
&DOptNegAX1, &DOptNegAX1,
&DOptNegAX2, &DOptNegAX2,
&DOptPrecalc, &DOptPrecalc,
@ -632,6 +637,7 @@ static unsigned RunOptGroup1 (CodeSeg* S)
Changes += RunOptFunc (S, &DOptAdd6, 1); Changes += RunOptFunc (S, &DOptAdd6, 1);
Changes += RunOptFunc (S, &DOptSub1, 1); Changes += RunOptFunc (S, &DOptSub1, 1);
Changes += RunOptFunc (S, &DOptSub3, 1); Changes += RunOptFunc (S, &DOptSub3, 1);
Changes += RunOptFunc (S, &DOptLongAssign, 1);
Changes += RunOptFunc (S, &DOptStore4, 1); Changes += RunOptFunc (S, &DOptStore4, 1);
Changes += RunOptFunc (S, &DOptStore5, 1); Changes += RunOptFunc (S, &DOptStore5, 1);
Changes += RunOptFunc (S, &DOptShift1, 1); Changes += RunOptFunc (S, &DOptShift1, 1);
@ -641,6 +647,7 @@ static unsigned RunOptGroup1 (CodeSeg* S)
Changes += RunOptFunc (S, &DOptStore1, 1); Changes += RunOptFunc (S, &DOptStore1, 1);
Changes += RunOptFunc (S, &DOptStore2, 5); Changes += RunOptFunc (S, &DOptStore2, 5);
Changes += RunOptFunc (S, &DOptStore3, 5); Changes += RunOptFunc (S, &DOptStore3, 5);
Changes += RunOptFunc (S, &DOptLongCopy, 1);
/* Return the number of changes */ /* Return the number of changes */
return Changes; return Changes;

View File

@ -257,6 +257,7 @@ static void Parse (void)
/* Parse the initialization */ /* Parse the initialization */
ParseInit (Sym->Type); ParseInit (Sym->Type);
} else { } else {
/* This is a declaration */ /* This is a declaration */
@ -326,21 +327,19 @@ NextDecl:
} }
} }
/* Function declaration? */ /* Finish the declaration */
if (Sym && IsTypeFunc (Sym->Type)) { if (Sym) {
/* Function definition? */
/* Function */ if (IsTypeFunc (Sym->Type) && CurTok.Tok == TOK_LCURLY) {
if (CurTok.Tok == TOK_SEMI) {
/* Prototype only */
NeedClean = 0;
NextToken ();
} else if (CurTok.Tok == TOK_LCURLY) {
/* ISO C: The type category in a function definition cannot be
** inherited from a typedef.
*/
if (IsTypeFunc (Spec.Type) && TypeCmp (Sym->Type, Spec.Type).C >= TC_EQUAL) { if (IsTypeFunc (Spec.Type) && TypeCmp (Sym->Type, Spec.Type).C >= TC_EQUAL) {
/* ISO C: The type category in a function definition cannot be
** inherited from a typedef.
*/
Error ("Function cannot be defined with a typedef"); Error ("Function cannot be defined with a typedef");
} else if (comma) { } else if (comma) {
/* ISO C: A function definition cannot shall its return type
** specifier with other declarators.
*/
Error ("';' expected after top level declarator"); Error ("';' expected after top level declarator");
} }
@ -350,30 +349,19 @@ NextDecl:
/* Make sure we aren't omitting any work */ /* Make sure we aren't omitting any work */
CheckDeferredOpAllDone (); CheckDeferredOpAllDone ();
} } else {
} else {
if (Sym) {
/* Must be followed by a semicolon */ /* Must be followed by a semicolon */
if (CurTok.Tok != TOK_SEMI) { if (ConsumeSemi ()) {
NeedClean = 0;
} else {
NeedClean = -1; NeedClean = -1;
} }
ConsumeSemi ();
} }
} }
/* Try some smart error recovery */ /* Try some smart error recovery */
if (PrevErrorCount != ErrorCount && NeedClean < 0) { if (PrevErrorCount != ErrorCount && NeedClean < 0) {
/* Some fix point tokens that are used for error recovery */ SmartErrorSkip (1);
static const token_t TokenList[] = { TOK_SEMI, TOK_RCURLY };
SmartErrorSkip ();
SkipTokens (TokenList, sizeof (TokenList) / sizeof (TokenList[0]));
if (CurTok.Tok == TOK_SEMI || CurTok.Tok == TOK_RCURLY) {
NextToken ();
}
} }
} }

210
src/cc65/coptlong.c Normal file
View File

@ -0,0 +1,210 @@
/*****************************************************************************/
/* */
/* coptlong.c */
/* */
/* Long integers optimizations */
/* */
/* */
/* */
/* (C) 2001-2009, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* (C) 2023, Colin Leroy-Mira <colin@colino.net */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
/* common */
#include "cpu.h"
/* cc65 */
#include "codeent.h"
#include "coptind.h"
#include "codeinfo.h"
#include "codeopt.h"
#include "error.h"
/*****************************************************************************/
/* Remove unused loads and stores */
/*****************************************************************************/
unsigned OptLongAssign (CodeSeg* S)
/* Simplify long assignments.
** Recognize
** lda ... 0
** sta sreg+1 1
** lda ... 2
** sta sreg 3
** lda ... 4
** ldx ... 5
** sta M0002 6
** stx M0002+1 7
** ldy sreg 8
** sty M0002+2 9
** ldy sreg+1 10
** sty M0002+3 11
** and simplify if not used right after.
*/
{
unsigned Changes = 0;
/* Walk over the entries */
unsigned I = 0;
while (I < CS_GetEntryCount (S)) {
CodeEntry* L[12];
/* Get next entry */
L[0] = CS_GetEntry (S, I);
if (CS_GetEntries (S, L+1, I+1, 11)) {
if (L[0]->OPC == OP65_LDA &&
L[1]->OPC == OP65_STA &&
!strcmp (L[1]->Arg, "sreg+1") &&
L[2]->OPC == OP65_LDA &&
L[3]->OPC == OP65_STA &&
!strcmp (L[3]->Arg, "sreg") &&
L[4]->OPC == OP65_LDA &&
L[5]->OPC == OP65_LDX &&
L[6]->OPC == OP65_STA &&
L[7]->OPC == OP65_STX &&
!strncmp(L[7]->Arg, L[6]->Arg, strlen(L[6]->Arg)) &&
!strcmp(L[7]->Arg + strlen(L[6]->Arg), "+1") &&
L[8]->OPC == OP65_LDY &&
!strcmp (L[8]->Arg, "sreg") &&
L[9]->OPC == OP65_STY &&
!strncmp(L[9]->Arg, L[6]->Arg, strlen(L[6]->Arg)) &&
!strcmp(L[9]->Arg + strlen(L[6]->Arg), "+2") &&
L[10]->OPC == OP65_LDY &&
!strcmp (L[10]->Arg, "sreg+1") &&
L[11]->OPC == OP65_STY &&
!strncmp(L[11]->Arg, L[6]->Arg, strlen(L[6]->Arg)) &&
!strcmp(L[11]->Arg + strlen(L[6]->Arg), "+3") &&
!RegXUsed (S, I+11)) {
L[1]->AM = L[11]->AM;
CE_SetArg(L[1], L[11]->Arg);
L[3]->AM = L[9]->AM;
CE_SetArg(L[3], L[9]->Arg);
CS_DelEntries (S, I+8, 4);
/* Remember, we had changes */
++Changes;
}
}
/* Next entry */
++I;
}
/* Return the number of changes made */
return Changes;
}
unsigned OptLongCopy (CodeSeg* S)
/* Simplify long copies.
** Recognize
** lda XXX+3 0
** sta sreg+1 1
** lda XXX+2 2
** sta sreg 3
** ldx XXX+1 4
** lda XXX 5
** sta YYY 6
** stx YYY+1 7
** ldy sreg 8
** sty YYY+2 9
** ldy sreg+1 10
** sty YYY+3 11
** and simplify if not used right after.
*/
{
unsigned Changes = 0;
/* Walk over the entries */
unsigned I = 0;
while (I < CS_GetEntryCount (S)) {
CodeEntry* L[12];
/* Get next entry */
L[0] = CS_GetEntry (S, I);
if (CS_GetEntries (S, L+1, I+1, 11)) {
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") &&
L[1]->OPC == OP65_STA &&
!strcmp (L[1]->Arg, "sreg+1") &&
L[2]->OPC == OP65_LDA &&
!strncmp(L[2]->Arg, L[5]->Arg, strlen(L[5]->Arg)) &&
!strcmp(L[2]->Arg + strlen(L[5]->Arg), "+2") &&
L[3]->OPC == OP65_STA &&
!strcmp (L[3]->Arg, "sreg") &&
L[4]->OPC == OP65_LDX &&
!strncmp(L[4]->Arg, L[5]->Arg, strlen(L[5]->Arg)) &&
!strcmp(L[4]->Arg + strlen(L[5]->Arg), "+1") &&
L[5]->OPC == OP65_LDA &&
L[6]->OPC == OP65_STA &&
L[7]->OPC == OP65_STX &&
!strncmp(L[7]->Arg, L[6]->Arg, strlen(L[6]->Arg)) &&
!strcmp(L[7]->Arg + strlen(L[6]->Arg), "+1") &&
L[8]->OPC == OP65_LDY &&
!strcmp (L[8]->Arg, "sreg") &&
L[9]->OPC == OP65_STY &&
!strncmp(L[9]->Arg, L[6]->Arg, strlen(L[6]->Arg)) &&
!strcmp(L[9]->Arg + strlen(L[6]->Arg), "+2") &&
L[10]->OPC == OP65_LDY &&
!strcmp (L[10]->Arg, "sreg+1") &&
L[11]->OPC == OP65_STY &&
!strncmp(L[11]->Arg, L[6]->Arg, strlen(L[6]->Arg)) &&
!strcmp(L[11]->Arg + strlen(L[6]->Arg), "+3") &&
!RegXUsed (S, I+11)) {
L[1]->AM = L[11]->AM;
CE_SetArg(L[1], L[11]->Arg);
L[3]->AM = L[9]->AM;
CE_SetArg(L[3], L[9]->Arg);
CS_DelEntries (S, I+8, 4);
/* Remember, we had changes */
++Changes;
}
}
/* Next entry */
++I;
}
/* Return the number of changes made */
return Changes;
}

63
src/cc65/coptlong.h Normal file
View File

@ -0,0 +1,63 @@
/*****************************************************************************/
/* */
/* coptlong.h */
/* */
/* Long integers optimizations */
/* */
/* */
/* */
/* (C) 2001-2009, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* (C) 2023, Colin Leroy-Mira <colin@colino.net */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef COPTLONG_H
#define COPTLONG_H
/* cc65 */
#include "codeseg.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
unsigned OptLongAssign (CodeSeg* S);
/* Simplify long assigns. */
unsigned OptLongCopy (CodeSeg* S);
/* Simplify long copy. */
/* End of coptind.h */
#endif

View File

@ -497,8 +497,8 @@ Type* NewPointerTo (const Type* T)
Type* NewBitFieldOf (const Type* T, unsigned BitOffs, unsigned BitWidth) Type* NewBitFieldOf (const Type* T, unsigned BitOffs, unsigned BitWidth)
/* Return a type string that is "T : BitWidth" aligned on BitOffs. The type /* Return a type string that is "unqualified T : BitWidth" aligned on BitOffs.
** string is allocated on the heap and may be freed after use. ** The type string is allocated on the heap and may be freed after use.
*/ */
{ {
Type* P; Type* P;

View File

@ -435,8 +435,8 @@ Type* NewPointerTo (const Type* T);
*/ */
Type* NewBitFieldOf (const Type* T, unsigned BitOffs, unsigned BitWidth); Type* NewBitFieldOf (const Type* T, unsigned BitOffs, unsigned BitWidth);
/* Return a type string that is "T : BitWidth" aligned on BitOffs. The type /* Return a type string that is "unqualified T : BitWidth" aligned on BitOffs.
** string is allocated on the heap and may be freed after use. ** The type string is allocated on the heap and may be freed after use.
*/ */
const Type* AddressOf (const Type* T); const Type* AddressOf (const Type* T);

View File

@ -117,11 +117,22 @@ static int CloseBrace (Collection* C, token_t Tok)
int SmartErrorSkip (void) int SmartErrorSkip (int WholeDecl)
/* Try some smart error recovery. Skip tokens until either a comma or semicolon /* Try some smart error recovery.
** that is not enclosed in an open parenthesis/bracket/curly brace, or until an **
** unpaired right parenthesis/bracket/curly brace is reached. Return 0 if it is ** - If WholeDecl is 0:
** the former case, or -1 if it is the latter case. */ ** Skip tokens until a comma or closing curly brace that is not enclosed in
** an open parenthesis/bracket/curly brace, or until a semicolon, EOF or
** unpaired right parenthesis/bracket/curly brace is reached.
**
** - If WholeDecl is non-0:
** Skip tokens until a closing curly brace that is not enclosed in an open
** parenthesis/bracket/curly brace, or until a semicolon or EOF is reached.
**
** Return 0 if this exits as soon as it reaches an EOF. Return 0 as well if
** this exits with no open parentheses/brackets/curly braces. Otherwise, return
** -1.
*/
{ {
Collection C = AUTO_COLLECTION_INITIALIZER; Collection C = AUTO_COLLECTION_INITIALIZER;
int Res = 0; int Res = 0;
@ -142,31 +153,41 @@ int SmartErrorSkip (void)
case TOK_RPAREN: case TOK_RPAREN:
case TOK_RBRACK: case TOK_RBRACK:
if (CloseBrace (&C, CurTok.Tok)) { if (CloseBrace (&C, CurTok.Tok) < 0) {
Res = -1; if (!WholeDecl) {
goto ExitPoint; Res = -1;
goto ExitPoint;
}
NextToken ();
} }
break; break;
case TOK_RCURLY: case TOK_RCURLY:
if (CloseBrace (&C, CurTok.Tok)) { if (CloseBrace (&C, CurTok.Tok) < 0) {
Res = -1; if (!WholeDecl) {
goto ExitPoint; Res = -1;
goto ExitPoint;
}
NextToken ();
} else if (CollCount (&C) == 0) { } else if (CollCount (&C) == 0) {
goto ExitPoint; goto ExitPoint;
} }
break; break;
case TOK_COMMA: case TOK_COMMA:
if (CollCount (&C) == 0) { if (CollCount (&C) == 0 && !WholeDecl) {
goto ExitPoint; goto ExitPoint;
} }
NextToken (); NextToken ();
break; break;
case TOK_SEMI: case TOK_SEMI:
if (CollCount (&C) != 0) {
Res = -1;
}
goto ExitPoint;
case TOK_CEOF: case TOK_CEOF:
Res = -1;
goto ExitPoint; goto ExitPoint;
default: default:
@ -1058,8 +1079,9 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
while (CurTok.Tok != TOK_RCURLY) { while (CurTok.Tok != TOK_RCURLY) {
/* Get the type of the entry */ /* Get the type of the entry */
DeclSpec Spec; DeclSpec Spec;
int SignednessSpecified = 0; int SignednessSpecified = 0;
int NeedClean = 0;
/* Check for a _Static_assert */ /* Check for a _Static_assert */
if (CurTok.Tok == TOK_STATIC_ASSERT) { if (CurTok.Tok == TOK_STATIC_ASSERT) {
@ -1076,7 +1098,7 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
Declarator Decl; Declarator Decl;
/* Get type and name of the struct field */ /* Get type and name of the struct field */
ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT); NeedClean = ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
/* Check for a bit-field declaration */ /* Check for a bit-field declaration */
FieldWidth = ParseFieldWidth (&Decl); FieldWidth = ParseFieldWidth (&Decl);
@ -1172,7 +1194,18 @@ NextMember: if (CurTok.Tok != TOK_COMMA) {
} }
NextToken (); NextToken ();
} }
ConsumeSemi ();
/* Must be followed by a semicolon */
if (NeedClean >= 0 && ConsumeSemi ()) {
NeedClean = 0;
} else {
NeedClean = -1;
}
/* Try some smart error recovery */
if (NeedClean < 0) {
SmartErrorSkip (1);
}
} }
/* Skip the closing brace */ /* Skip the closing brace */
@ -1187,11 +1220,6 @@ NextMember: if (CurTok.Tok != TOK_COMMA) {
Flags |= SC_FICTITIOUS; Flags |= SC_FICTITIOUS;
} }
/* Empty union is not supported now */
if (UnionSize == 0) {
Error ("Empty union type '%s' is not supported", Name);
}
/* Make a real entry from the forward decl and return it */ /* Make a real entry from the forward decl and return it */
return AddStructSym (Name, SC_UNION | SC_DEF | Flags, UnionSize, FieldTab, DSFlags); return AddStructSym (Name, SC_UNION | SC_DEF | Flags, UnionSize, FieldTab, DSFlags);
} }
@ -1236,8 +1264,9 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
while (CurTok.Tok != TOK_RCURLY) { while (CurTok.Tok != TOK_RCURLY) {
/* Get the type of the entry */ /* Get the type of the entry */
DeclSpec Spec; DeclSpec Spec;
int SignednessSpecified = 0; int SignednessSpecified = 0;
int NeedClean = 0;
/* Check for a _Static_assert */ /* Check for a _Static_assert */
if (CurTok.Tok == TOK_STATIC_ASSERT) { if (CurTok.Tok == TOK_STATIC_ASSERT) {
@ -1262,7 +1291,7 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
} }
/* Get type and name of the struct field */ /* Get type and name of the struct field */
ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT); NeedClean = ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
/* Check for a bit-field declaration */ /* Check for a bit-field declaration */
FieldWidth = ParseFieldWidth (&Decl); FieldWidth = ParseFieldWidth (&Decl);
@ -1403,7 +1432,18 @@ NextMember: if (CurTok.Tok != TOK_COMMA) {
} }
NextToken (); NextToken ();
} }
ConsumeSemi ();
/* Must be followed by a semicolon */
if (NeedClean >= 0 && ConsumeSemi ()) {
NeedClean = 0;
} else {
NeedClean = -1;
}
/* Try some smart error recovery */
if (NeedClean < 0) {
SmartErrorSkip (1);
}
} }
if (BitOffs > 0) { if (BitOffs > 0) {
@ -1426,11 +1466,6 @@ NextMember: if (CurTok.Tok != TOK_COMMA) {
Flags |= SC_FICTITIOUS; Flags |= SC_FICTITIOUS;
} }
/* Empty struct is not supported now */
if (StructSize == 0) {
Error ("Empty struct type '%s' is not supported", Name);
}
/* Make a real entry from the forward decl and return it */ /* Make a real entry from the forward decl and return it */
return AddStructSym (Name, SC_STRUCT | SC_DEF | Flags, StructSize, FieldTab, DSFlags); return AddStructSym (Name, SC_STRUCT | SC_DEF | Flags, StructSize, FieldTab, DSFlags);
} }
@ -1778,7 +1813,7 @@ static void ParseOldStyleParamList (FuncDesc* F)
Error ("Identifier expected for parameter name"); Error ("Identifier expected for parameter name");
/* Try some smart error recovery */ /* Try some smart error recovery */
if (SmartErrorSkip () < 0) { if (SmartErrorSkip (0) < 0) {
break; break;
} }
} }
@ -1868,7 +1903,7 @@ static void ParseOldStyleParamList (FuncDesc* F)
if (PrevErrorCount != ErrorCount && CurTok.Tok != TOK_LCURLY) { if (PrevErrorCount != ErrorCount && CurTok.Tok != TOK_LCURLY) {
/* Try some smart error recovery */ /* Try some smart error recovery */
SmartErrorSkip (); SmartErrorSkip (0);
} }
} }
@ -1953,7 +1988,7 @@ static void ParseAnsiParamList (FuncDesc* F)
if (PrevErrorCount != ErrorCount) { if (PrevErrorCount != ErrorCount) {
/* Try some smart error recovery */ /* Try some smart error recovery */
if (SmartErrorSkip () < 0) { if (SmartErrorSkip (0) < 0) {
break; break;
} }
} }
@ -2335,7 +2370,7 @@ int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
/* Try some smart error recovery */ /* Try some smart error recovery */
if (CurTok.Tok != TOK_LCURLY || !IsTypeFunc (D->Type)) { if (CurTok.Tok != TOK_LCURLY || !IsTypeFunc (D->Type)) {
return SmartErrorSkip (); return SmartErrorSkip (0);
} }
} }

View File

@ -128,11 +128,22 @@ typedef enum {
int SmartErrorSkip (void); int SmartErrorSkip (int WholeDecl);
/* Try some smart error recovery. Skip tokens until either a comma or semicolon /* Try some smart error recovery.
** that is not enclosed in an open parenthesis/bracket/curly brace, or until an **
** unpaired right parenthesis/bracket/curly brace is reached. Return 0 if it is ** - If WholeDecl is 0:
** the former case, or -1 if it is the latter case. */ ** Skip tokens until a comma or closing curly brace that is not enclosed in
** an open parenthesis/bracket/curly brace, or until a semicolon, EOF or
** unpaired right parenthesis/bracket/curly brace is reached.
**
** - If WholeDecl is non-0:
** Skip tokens until a closing curly brace that is not enclosed in an open
** parenthesis/bracket/curly brace, or until a semicolon or EOF is reached.
**
** Return 0 if this exits as soon as it reaches an EOF. Return 0 as well if
** this exits with no open parentheses/brackets/curly braces. Otherwise, return
** -1.
*/
Type* ParseType (Type* Type); Type* ParseType (Type* Type);
/* Parse a complete type specification */ /* Parse a complete type specification */

View File

@ -1426,9 +1426,9 @@ static void Primary (ExprDesc* E)
} else { } else {
/* Let's see if this is a C99-style declaration */ /* Let's see if this is a C99-style declaration */
DeclSpec Spec; DeclSpec Spec;
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_AUTO); ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO);
if (Spec.Type->C != T_END) { if ((Spec.Flags & DS_DEF_TYPE) == 0) {
/* Recognized but not supported */ /* Recognized but not supported */
Error ("Mixed declarations and code are not supported in cc65"); Error ("Mixed declarations and code are not supported in cc65");
@ -4816,9 +4816,10 @@ static void hieQuest (ExprDesc* Expr)
/* Avoid further errors */ /* Avoid further errors */
ResultType = NewPointerTo (type_void); ResultType = NewPointerTo (type_void);
} else { } else {
/* Result has the composite type */ /* Result has the properly qualified composite type */
ResultType = TypeDup (Expr2.Type); ResultType = TypeDup (Expr2.Type);
TypeComposition (ResultType, Expr3.Type); TypeComposition (ResultType, Expr3.Type);
ResultType[1].C |= GetQualifier (Indirect (Expr3.Type));
} }
} }
} else if (IsClassPtr (Expr2.Type) && Expr3IsNULL) { } else if (IsClassPtr (Expr2.Type) && Expr3IsNULL) {

View File

@ -533,18 +533,20 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
/* This may be an anonymous bit-field, in which case it doesn't /* This may be an anonymous bit-field, in which case it doesn't
** have an initializer. ** have an initializer.
*/ */
if (SymIsBitField (TagSym) && (IsAnonName (TagSym->Name))) { if (SymIsBitField (TagSym) && IsAnonName (TagSym->Name)) {
/* Account for the data and output it if we have at least a full if (!IsTypeUnion (T)) {
** byte. We may have more if there was storage unit overlap, for /* Account for the data and output it if we have at least a full
** example two consecutive 7 bit fields. Those would be packed ** byte. We may have more if there was storage unit overlap, for
** into 2 bytes. ** example two consecutive 7 bit fields. Those would be packed
*/ ** into 2 bytes.
SI.ValBits += TagSym->Type->A.B.Width; */
CHECK (SI.ValBits <= CHAR_BIT * sizeof(SI.BitVal)); SI.ValBits += TagSym->Type->A.B.Width;
/* TODO: Generalize this so any type can be used. */ CHECK (SI.ValBits <= CHAR_BIT * sizeof(SI.BitVal));
CHECK (SI.ValBits <= LONG_BITS); /* TODO: Generalize this so any type can be used. */
while (SI.ValBits >= CHAR_BITS) { CHECK (SI.ValBits <= LONG_BITS);
DefineBitFieldData (&SI); while (SI.ValBits >= CHAR_BITS) {
DefineBitFieldData (&SI);
}
} }
/* Avoid consuming the comma if any */ /* Avoid consuming the comma if any */
goto NextMember; goto NextMember;
@ -650,15 +652,15 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
/* Skip the comma next round */ /* Skip the comma next round */
SkipComma = 1; SkipComma = 1;
NextMember: /* For unions, only the first named member can be initialized */
/* Next member. For unions, only the first one can be initialized */
if (IsTypeUnion (T)) { if (IsTypeUnion (T)) {
/* Union */
TagSym = 0; TagSym = 0;
} else { continue;
/* Struct */
TagSym = TagSym->NextSym;
} }
NextMember:
/* Next member */
TagSym = TagSym->NextSym;
} }
if (HasCurly) { if (HasCurly) {

View File

@ -178,7 +178,7 @@ static void CheckSymTable (SymTable* Tab)
if (IS_Get (&WarnUnusedFunc)) { if (IS_Get (&WarnUnusedFunc)) {
Warning ("Function '%s' is defined but never used", Entry->Name); Warning ("Function '%s' is defined but never used", Entry->Name);
} }
} else { } else if (!IsAnonName (Entry->Name)) {
if (IS_Get (&WarnUnusedVar)) { if (IS_Get (&WarnUnusedVar)) {
Warning ("Variable '%s' is defined but never used", Entry->Name); Warning ("Variable '%s' is defined but never used", Entry->Name);
} }
@ -919,14 +919,8 @@ SymEntry* AddStructSym (const char* Name, unsigned Flags, unsigned Size, SymTabl
/* SCType must be struct or union */ /* SCType must be struct or union */
PRECONDITION (SCType == SC_STRUCT || SCType == SC_UNION); PRECONDITION (SCType == SC_STRUCT || SCType == SC_UNION);
if ((Flags & SC_FICTITIOUS) == 0) { /* Do we have an entry with this name already? */
/* Do we have an entry with this name already? */ TagEntry = FindSymInTable (CurTagTab, Name, HashStr (Name));
TagEntry = FindSymInTable (CurTagTab, Name, HashStr (Name));
} else {
/* Add a fictitious symbol in the fail-safe table */
TagEntry = 0;
CurTagTab = FailSafeTab;
}
if (TagEntry) { if (TagEntry) {
@ -954,6 +948,15 @@ SymEntry* AddStructSym (const char* Name, unsigned Flags, unsigned Size, SymTabl
if (DSFlags != 0) { if (DSFlags != 0) {
*DSFlags |= DS_NEW_TYPE_DEF; *DSFlags |= DS_NEW_TYPE_DEF;
} }
if ((Flags & SC_FICTITIOUS) == SC_FICTITIOUS) {
/* Add a fictitious symbol in the fail-safe table */
TagEntry = 0;
} else if (Size == 0) {
/* Empty struct is not supported now */
Error ("Empty %s type '%s' is not supported", SCType == SC_STRUCT ? "struct" : "union", Name);
TagEntry = 0;
}
} }
} }
@ -1023,6 +1026,7 @@ SymEntry* AddBitField (const char* Name, const Type* T, unsigned Offs,
} else { } else {
Entry->Type = NewBitFieldOf (T, BitOffs, BitWidth); Entry->Type = NewBitFieldOf (T, BitOffs, BitWidth);
} }
Entry->Type[0].C |= GetQualifier (T) & T_MASK_QUAL;
/* Add the entry to the symbol table */ /* Add the entry to the symbol table */
AddSymEntry (FieldTab, Entry); AddSymEntry (FieldTab, Entry);

View File

@ -69,6 +69,7 @@ static int EqualFuncParams (const FuncDesc* F1, const FuncDesc* F2)
/* Get the symbol types */ /* Get the symbol types */
const Type* Type1 = Sym1->Type; const Type* Type1 = Sym1->Type;
const Type* Type2 = Sym2->Type; const Type* Type2 = Sym2->Type;
typecmp_t CmpResult;
/* If either of both functions is old style, apply the default /* If either of both functions is old style, apply the default
** promotions to the parameter type. ** promotions to the parameter type.
@ -84,9 +85,10 @@ static int EqualFuncParams (const FuncDesc* F1, const FuncDesc* F2)
} }
} }
/* Compare this field */ /* Compare types of this parameter */
if (TypeCmp (Type1, Type2).C < TC_EQUAL) { CmpResult = TypeCmp (Type1, Type2);
/* Field types not equal */ if (CmpResult.C < TC_EQUAL || (CmpResult.F & TCF_MASK_PARAM_DIFF) != 0) {
/* The types are not compatible */
return 0; return 0;
} }

View File

@ -68,15 +68,17 @@ typedef enum {
TCF_VOID_PTR_ON_LEFT = 0x01, /* lhs is a void pointer */ TCF_VOID_PTR_ON_LEFT = 0x01, /* lhs is a void pointer */
TCF_VOID_PTR_ON_RIGHT = 0x02, /* rhs is a void pointer */ TCF_VOID_PTR_ON_RIGHT = 0x02, /* rhs is a void pointer */
TCF_MASK_VOID_PTR = TCF_VOID_PTR_ON_LEFT | TCF_VOID_PTR_ON_RIGHT, TCF_MASK_VOID_PTR = TCF_VOID_PTR_ON_LEFT | TCF_VOID_PTR_ON_RIGHT,
TCF_QUAL_DIFF = 0x04, /* CVR qualifiers differ in a way that doesn't matter */ TCF_QUAL_DIFF = 0x04, /* lhs doesn't have all of CVR qualifiers of rhs */
TCF_QUAL_IMPLICIT = 0x08, /* CVR qualifiers of lhs are stricter than those of rhs */ TCF_QUAL_IMPLICIT = 0x08, /* CVR qualifiers of lhs are stricter than those of rhs */
TCF_PTR_QUAL_DIFF = 0x10, /* CVR qualifiers of pointers differ */ TCF_MASK_CVR_DIFF = 0x0C, /* All CVR qualifiers */
TCF_PTR_QUAL_IMPLICIT = 0x20, /* CVR qualifiers of pointers are stricter on lhs than those on rhs */ TCF_PTR_QUAL_DIFF = 0x10, /* lhs pointee doesn't have all of CVR qualifiers of rhs pointee */
TCF_MASK_C_QUAL_DIFF = 0x3C, /* All C Standard qualifiers */ TCF_PTR_QUAL_IMPLICIT = 0x20, /* CVR qualifiers of pointees are stricter on lhs than those on rhs */
TCF_MASK_PTR_QUAL_DIFF = 0x30, /* All CVR qualifiers of pointees */
TCF_ADDRSIZE_QUAL_DIFF = 0x40, /* Address size qualifiers differ */ TCF_ADDRSIZE_QUAL_DIFF = 0x40, /* Address size qualifiers differ */
TCF_CCONV_QUAL_DIFF = 0x80, /* Function calling conventions differ. Unused now */ TCF_CCONV_QUAL_DIFF = 0x80, /* Function calling conventions differ. Unused now */
TCF_INCOMPATIBLE_QUAL = TCF_ADDRSIZE_QUAL_DIFF | TCF_CCONV_QUAL_DIFF, TCF_INCOMPATIBLE_QUAL = TCF_ADDRSIZE_QUAL_DIFF | TCF_CCONV_QUAL_DIFF,
TCF_MASK_QUAL = TCF_MASK_C_QUAL_DIFF | TCF_INCOMPATIBLE_QUAL, TCF_MASK_PARAM_DIFF = TCF_MASK_PTR_QUAL_DIFF | TCF_INCOMPATIBLE_QUAL,
TCF_MASK_QUAL = TCF_MASK_CVR_DIFF | TCF_MASK_PTR_QUAL_DIFF | TCF_INCOMPATIBLE_QUAL,
} typecmpflag_t; } typecmpflag_t;
typedef struct { typedef struct {

View File

@ -530,13 +530,6 @@ void TypeComposition (Type* lhs, const Type* rhs)
} else if (RightCount != UNSPECIFIED) { } else if (RightCount != UNSPECIFIED) {
SetElementCount (lhs, RightCount); SetElementCount (lhs, RightCount);
} }
} else {
/* Combine the qualifiers */
if (IsClassPtr (lhs)) {
++lhs;
++rhs;
lhs->C |= GetQualifier (rhs);
}
} }
/* Next type string element */ /* Next type string element */

View File

@ -0,0 +1,14 @@
/* Bug #2018 - Compiler has problems with const struct fields */
typedef union U {
int a : 16;
const int b : 16;
} U;
int main(void)
{
U x = { 42 };
x.b = 0;
return 0;
}

View File

@ -0,0 +1,5 @@
/* Bug #2285 - Regression in type composition */
void foo(); /* OK */
void foo(int (*)(int)); /* OK */
void foo(int (*)(long)); /* WRONG: Should be an error */

View File

@ -0,0 +1,4 @@
/* Bug #2286 - Qualifiers of pointees of function parameters ignored for type compatibility check */
void woo(int* p);
void woo(const int* p); /* WRONG: Should be an error */

View File

@ -58,24 +58,6 @@ $(ISEQUAL): ../isequal.c | $(WORKDIR)
define PRG_template define PRG_template
# should compile, but gives an error
$(WORKDIR)/int-static-1888.$1.$2.prg: int-static-1888.c | $(WORKDIR)
@echo "FIXME: " $$@ "currently does not compile."
$(if $(QUIET),echo misc/int-static-1888.$1.$2.prg)
$(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
# should compile, but gives an error
$(WORKDIR)/bug760.$1.$2.prg: bug760.c | $(WORKDIR)
@echo "FIXME: " $$@ "currently does not compile."
$(if $(QUIET),echo misc/bug760.$1.$2.prg)
$(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
# should compile, but gives an error
$(WORKDIR)/bug1437.$1.$2.prg: bug1437.c | $(WORKDIR)
@echo "FIXME: " $$@ "currently does not compile."
$(if $(QUIET),echo misc/bug1437.$1.$2.prg)
$(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
# should compile, but gives an error # should compile, but gives an error
$(WORKDIR)/bug1209-ind-goto-rev.$1.$2.prg: bug1209-ind-goto-rev.c | $(WORKDIR) $(WORKDIR)/bug1209-ind-goto-rev.$1.$2.prg: bug1209-ind-goto-rev.c | $(WORKDIR)
@echo "FIXME: " $$@ "currently does not compile." @echo "FIXME: " $$@ "currently does not compile."
@ -106,18 +88,6 @@ $(WORKDIR)/pptest2.$1.$2.prg: pptest2.c | $(WORKDIR)
$(if $(QUIET),echo misc/pptest2.$1.$2.prg) $(if $(QUIET),echo misc/pptest2.$1.$2.prg)
$(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR) $(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
# should compile, but gives an error
$(WORKDIR)/bug1263.$1.$2.prg: bug1263.c | $(WORKDIR)
@echo "FIXME: " $$@ "currently does not compile."
$(if $(QUIET),echo misc/bug1263.$1.$2.prg)
$(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
# should compile, but gives an error
$(WORKDIR)/bug1357.$1.$2.prg: bug1357.c | $(WORKDIR)
@echo "FIXME: " $$@ "currently does not compile."
$(if $(QUIET),echo misc/bug1357.$1.$2.prg)
$(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
# should compile, but compiler exits with internal error # should compile, but compiler exits with internal error
$(WORKDIR)/bug1211-ice-move-refs-2.$1.$2.prg: bug1211-ice-move-refs-2.c | $(WORKDIR) $(WORKDIR)/bug1211-ice-move-refs-2.$1.$2.prg: bug1211-ice-move-refs-2.c | $(WORKDIR)
@echo "FIXME: " $$@ "currently does not compile." @echo "FIXME: " $$@ "currently does not compile."

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2020 The cc65 Authors Copyright 2020-2023 The cc65 Authors
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@ -25,6 +25,7 @@
#include <stdio.h> #include <stdio.h>
typedef union { typedef union {
const unsigned int : 1;
unsigned int bf; unsigned int bf;
struct { struct {
@ -38,8 +39,12 @@ static unsigned char failures = 0;
int main (void) int main (void)
{ {
bitfield_t bitfield = {0}; bitfield_t bitfield = { 42 };
printf ("Bitfield: %u\n", bitfield.bf);
if (bitfield.bf != 42) failures++;
bitfield.bf ^= 42;
printf ("Bitfield: %u\n", bitfield.bf); printf ("Bitfield: %u\n", bitfield.bf);
if (bitfield.bf != 0) failures++; if (bitfield.bf != 0) failures++;

41
test/val/long.c Normal file
View File

@ -0,0 +1,41 @@
#include <stdint.h>
#include <stdio.h>
int res = 0;
int main(void)
{
long a, b;
a = 0x12345678L;
/* Test assignment */
b = a;
if (b != a) {
res++;
}
/* Test increment */
b++;
if (b != 0x12345679L) {
res++;
}
/* Test decrement */
b--;
if (b != 0x12345678L) {
res++;
}
/* Test pre-decrement with test */
if (--b != 0x12345677L) {
res++;
}
a = --b;
if (a != 0x12345676L) {
res++;
}
return res;
}

41
test/val/static-long.c Normal file
View File

@ -0,0 +1,41 @@
#include <stdint.h>
#include <stdio.h>
int res = 0;
int main(void)
{
static long a, b;
a = 0x12345678L;
/* Test assignment */
b = a;
if (b != a) {
res++;
}
/* Test increment */
b++;
if (b != 0x12345679L) {
res++;
}
/* Test decrement */
b--;
if (b != 0x12345678L) {
res++;
}
/* Test pre-decrement with test */
if (--b != 0x12345677L) {
res++;
}
a = --b;
if (a != 0x12345676L) {
res++;
}
return res;
}

View File

@ -168,6 +168,31 @@ void post_dec_assign_test(void)
failures++; failures++;
} }
void dex_tests(void) {
static unsigned int a, b;
a = 257;
b = a - 1;
if (b != 256) {
printf("fail 257 => 256\n");
failures++;
}
a = 256;
b = a - 1;
if (b != 255) {
printf("fail 256 => 255\n");
failures++;
}
a = 255;
b = a - 1;
if (b != 254) {
printf("fail 255 => 254\n");
failures++;
}
}
int main(void) int main(void)
{ {
int0 = 5; int0 = 5;
@ -186,6 +211,8 @@ int main(void)
int1 = 5; int1 = 5;
post_dec_assign_test(); post_dec_assign_test();
dex_tests();
printf("failures: %d\n",failures); printf("failures: %d\n",failures);
return failures; return failures;