mirror of
https://github.com/cc65/cc65.git
synced 2024-12-27 00:29:31 +00:00
The change from #2495 didn't take into account that recursive calls to main()
are legal in C. With the changes from #2495, such calls will usually crash the machine. But recursive calls to main() are rare and on the 6502 every byte saved is precious. So this change limits the effect of #2495 to cc65 mode and at the same time disallows recursive calls to main() in this mode. If recursive calls to main() are actually required, the code must be compiled in c89 or c99 mode.
This commit is contained in:
parent
5e5dd1d6c4
commit
cd4357057f
@ -823,6 +823,11 @@ and the one defined by the ISO standard:
|
||||
as it sounds, since the 6502 has so few registers that it isn't
|
||||
possible to keep values in registers anyway.
|
||||
<p>
|
||||
<item> In <tt/cc65/ mode, <tt/main()/ cannot be called recursively. If this
|
||||
is necessary, the program must be compiled in <tt/c89/ or <tt/c99/ mode
|
||||
using the <tt><ref id="option--standard" name="--standard"></tt>
|
||||
command line option.
|
||||
<p>
|
||||
</itemize>
|
||||
|
||||
There may be some more minor differences I'm currently not aware of. The
|
||||
|
@ -507,13 +507,13 @@ void g_enter (unsigned flags, unsigned argsize)
|
||||
|
||||
|
||||
|
||||
void g_leave (int IsMainFunc)
|
||||
void g_leave (int DoCleanup)
|
||||
/* Function epilogue */
|
||||
{
|
||||
/* In the main function nothing has to be dropped because the program
|
||||
** is terminated anyway.
|
||||
/* In the main function in cc65 mode nothing has to be dropped because
|
||||
** the program is terminated anyway.
|
||||
*/
|
||||
if (!IsMainFunc) {
|
||||
if (DoCleanup) {
|
||||
/* How many bytes of locals do we have to drop? */
|
||||
unsigned ToDrop = (unsigned) -StackPtr;
|
||||
|
||||
|
@ -247,7 +247,7 @@ void g_scale (unsigned flags, long val);
|
||||
void g_enter (unsigned flags, unsigned argsize);
|
||||
/* Function prologue */
|
||||
|
||||
void g_leave (int IsMainFunc);
|
||||
void g_leave (int DoCleanup);
|
||||
/* Function epilogue */
|
||||
|
||||
|
||||
|
@ -1219,9 +1219,6 @@ static void Primary (ExprDesc* E)
|
||||
/* Is the symbol known? */
|
||||
if (Sym) {
|
||||
|
||||
/* We found the symbol - skip the name token */
|
||||
NextToken ();
|
||||
|
||||
/* Check for illegal symbol types */
|
||||
CHECK ((Sym->Flags & SC_TYPEMASK) != SC_LABEL);
|
||||
if ((Sym->Flags & SC_TYPEMASK) == SC_TYPEDEF) {
|
||||
@ -1230,9 +1227,14 @@ static void Primary (ExprDesc* E)
|
||||
/* Assume an int type to make E valid */
|
||||
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
||||
E->Type = type_int;
|
||||
/* Skip the erroneous token */
|
||||
NextToken ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Skip the name token */
|
||||
NextToken ();
|
||||
|
||||
/* Mark the symbol as referenced */
|
||||
Sym->Flags |= SC_REF;
|
||||
|
||||
@ -1286,7 +1288,23 @@ static void Primary (ExprDesc* E)
|
||||
** rvalue, too, because we cannot store anything in a function.
|
||||
** So fix the flags depending on the type.
|
||||
*/
|
||||
if (IsTypeArray (E->Type) || IsTypeFunc (E->Type)) {
|
||||
if (IsTypeArray (E->Type)) {
|
||||
ED_AddrExpr (E);
|
||||
} else if (IsTypeFunc (E->Type)) {
|
||||
/* In cc65 mode we cannot call or take the address of
|
||||
** main().
|
||||
*/
|
||||
if (IS_Get (&Standard) == STD_CC65 &&
|
||||
strcmp (Sym->Name, "main") == 0) {
|
||||
/* Adjust the error message depending on a call or an
|
||||
** address operation.
|
||||
*/
|
||||
if (CurTok.Tok == TOK_LPAREN) {
|
||||
Error ("'main' must not be called recursively");
|
||||
} else {
|
||||
Error ("The address of 'main' cannot be taken");
|
||||
}
|
||||
}
|
||||
ED_AddrExpr (E);
|
||||
}
|
||||
|
||||
|
@ -646,13 +646,17 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
||||
/* Output the function exit code label */
|
||||
g_defcodelabel (F_GetRetLab (CurrentFunc));
|
||||
|
||||
/* Restore the register variables (not necessary for main function) */
|
||||
if (!F_IsMainFunc (CurrentFunc)) {
|
||||
/* Restore the register variables (not necessary for the main function in
|
||||
** cc65 mode)
|
||||
*/
|
||||
int CleanupOnExit = (IS_Get (&Standard) != STD_CC65) ||
|
||||
!F_IsMainFunc (CurrentFunc);
|
||||
if (CleanupOnExit) {
|
||||
F_RestoreRegVars (CurrentFunc);
|
||||
}
|
||||
|
||||
/* Generate the exit code */
|
||||
g_leave (F_IsMainFunc (CurrentFunc));
|
||||
g_leave (CleanupOnExit);
|
||||
|
||||
/* Emit references to imports/exports */
|
||||
EmitExternals ();
|
||||
|
@ -111,6 +111,13 @@ static void ParseRegisterDecl (Declarator* Decl, int Reg)
|
||||
/* Get the size of the variable */
|
||||
unsigned Size = SizeOf (Decl->Type);
|
||||
|
||||
/* Check if this is the main function and we are in cc65 mode. If so, we
|
||||
** won't save the old contents of the register variables since in cc65
|
||||
** mode main() may not be called recursively.
|
||||
*/
|
||||
int SaveRegVars = (IS_Get (&Standard) != STD_CC65) ||
|
||||
!F_IsMainFunc (CurrentFunc);
|
||||
|
||||
/* Check for an optional initialization */
|
||||
if (CurTok.Tok == TOK_ASSIGN) {
|
||||
|
||||
@ -126,13 +133,13 @@ static void ParseRegisterDecl (Declarator* Decl, int Reg)
|
||||
/* Save the current contents of the register variable on stack. This is
|
||||
** not necessary for the main function.
|
||||
*/
|
||||
if (!F_IsMainFunc (CurrentFunc)) {
|
||||
if (SaveRegVars) {
|
||||
g_save_regvars (Reg, Size);
|
||||
}
|
||||
|
||||
/* Add the symbol to the symbol table. We do that now, because for
|
||||
** register variables the current stack pointer is implicitly used
|
||||
** as location for the save area (unused in case of main()).
|
||||
** as location for the save area (maybe unused in case of main()).
|
||||
*/
|
||||
Sym = AddLocalSym (Decl->Ident, Decl->Type, Decl->StorageClass, Reg);
|
||||
|
||||
@ -187,14 +194,14 @@ static void ParseRegisterDecl (Declarator* Decl, int Reg)
|
||||
/* Save the current contents of the register variable on stack. This is
|
||||
** not necessary for the main function.
|
||||
*/
|
||||
if (!F_IsMainFunc (CurrentFunc)) {
|
||||
if (SaveRegVars) {
|
||||
F_AllocLocalSpace (CurrentFunc);
|
||||
g_save_regvars (Reg, Size);
|
||||
}
|
||||
|
||||
/* Add the symbol to the symbol table. We do that now, because for
|
||||
** register variables the current stack pointer is implicitly used
|
||||
** as location for the save area (unused in case of main()).
|
||||
** as location for the save area (maybe unused in case of main()).
|
||||
*/
|
||||
Sym = AddLocalSym (Decl->Ident, Decl->Type, Decl->StorageClass, Reg);
|
||||
}
|
||||
|
@ -22,6 +22,5 @@ return_t main(int argc, char* argv[])
|
||||
n = 0; /* produce an error */
|
||||
/* produce a warning */
|
||||
}
|
||||
|
||||
int arr[main(0, 0)]; /* produce an error */
|
||||
int b = 0;
|
||||
int arr[b]; /* produce an error */
|
||||
|
@ -28,6 +28,8 @@ struct S {
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
void func() { }
|
||||
|
||||
int main()
|
||||
{
|
||||
int a;
|
||||
@ -60,7 +62,7 @@ int main()
|
||||
TEST_NON_NULL(((struct S*)&a)->a)
|
||||
|
||||
/* Non-null pointer obtained with cast and -> */
|
||||
TEST_NON_NULL(((struct S*)&main)->a)
|
||||
TEST_NON_NULL(((struct S*)&func)->a)
|
||||
|
||||
if (failures != 0)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user