In the new implementation, variable arguments are not removed until the end of the function. This allows variable argument processing to be restarted, and it prevents the addresses of local variables from changing in the middle of the function. The requirement to turn off stack repair code around varargs functions is also removed.
This fixes#58.
We previously ignored this, but it is a constraint violation under the C standards, so it should be reported as an error.
GCC and Clang allow this as an extension, as we were effectively doing previously. We will follow the standards for now, but if there was demand for such an extension in ORCA/C, it could be re-introduced subject to a #pragma ignore flag.
This gives a clearer pattern of matching ORCA/C's historical behavior if loose type checks are used, and the documentation is updated accordingly.
It also avoids breaking existing code that may be relying on the old behavior. I am aware of at least one place that does (conflicting declarations of InstallNetDriver in GNO's <gno/gno.h>).
This is a change that was introduced in C17. However, it actually keeps things closer to ORCA/C's historical behavior, which generally ignored qualifiers in return types.
These will check that the prototypes (if present) match in number and types of arguments. This primarily affects operations on function pointers, since similar checks were already done elsewhere on function declarations themselves.
This causes an error to be produced when trying to assign to these fields, which was being allowed before. It is also necessary for correct behavior of _Generic in some cases.
These are needed to correctly distinguish pointer types in _Generic. They should also be used for type compatibility checks in other contexts, but currently are not.
This also fixes a couple small problems related to type qualifiers:
*restrict was not allowed to appear after * in type-names
*volatile status was not properly recorded in sym files
Here is an example of using _Generic to distinguish pointer types based on the qualifiers of the pointed-to type:
#include <stdio.h>
#define f(e) _Generic((e),\
int * restrict *: 1,\
int * volatile const *: 2,\
int **: 3,\
default: 0)
#define g(e) _Generic((e),\
int *: 1,\
const int *: 2,\
volatile int *: 3,\
default: 0)
int main(void) {
int * restrict * p1;
int * volatile const * p2;
int * const * p3;
// should print "1 2 0 1"
printf("%i %i %i %i\n", f(p1), f(p2), f(p3), f((int * restrict *)0));
int *q1;
const int *q2;
volatile int *q3;
const volatile int *q4;
// should print "1 2 3 0"
printf("%i %i %i %i\n", g(q1), g(q2), g(q3), g(q4));
}
Here is an example of a problem resulting from volatile not being recorded in sym files (if a sym file was present, the read of x was lifted out of the loop):
#pragma optimize -1
static volatile int x;
#include <stdio.h>
int main(void) {
int y;
for (unsigned i = 0; i < 100; i++) {
y = x*2 + 7;
}
}
For now, this is only used for _Generic expressions. Eventually, it should probably replace the current CompTypes, but CompTypes currently performs somewhat looser checks that are suitable for some situations, so adjustments would be needed at some call sites.
This gives the name of the current function, as if the following definition appeared at the beginning of the function body:
static const char __func__[] = "function-name";
For now, "long long" is represented with the existing code for the SANE comp format, since their representation is the same except for the comp NaN. This allows existing debuggers that support comp to work with it. The code for "unsigned long long" includes the unsigned flag, so it is unambiguous.
This is contrary to the C standards, but ORCA/C historically permitted it (as do some other compilers), and I think there is a fair amount of existing code that relies on it.
These are initially entered into the symbol table with no known type (itype = nil), so this case should be accounted for in NewSymbol.
This typically would not cause a problem, but might if the zero page contained certain values
const structs are wrapped in definedType. The debugger symbol table code is unaware of this, which results in missing or incomplete entries.
example:
const struct { int a; int b; } cs;
cs: isForwardDeclared = false; class = ident
4 byte constant defined type of
4 byte struct: 223978
const struct { int a; int b; } *pcs;
pcs: isForwardDeclared = false; class = ident
4 byte pointer to
4 byte constant defined type of
4 byte struct: 224145
const struct { const struct { const int a; } a[2]; } csa[5];
csa: isForwardDeclared = false; class = ident
20 byte 5 element array of
4 byte constant defined type of
4 byte struct: 225155
const struct { const struct { const int a; } a[2]; } *cspa[5];
cspa: isForwardDeclared = false; class = ident
20 byte 5 element array of
4 byte pointer to
4 byte constant defined type of
4 byte struct: 224850
This change unwraps the definedType so the underlying type info can be placed in the debugger symbol table.
In the case of structs or unions, an error is now produced. This addresses one of the problems mentioned in issue #53.
In the case of arrays, tentative definitions like "int i[];" are now permitted at file scope. If not completed by a subsequent definition, this winds up producing an array with one element, initialized to 0. See the discussion and example in C99/C11 section 6.9.2 (or C90 section 6.7.2 and example in TC1).
Memory for them is still allocated from the global pool, to ensure they remain available for as long as the function prototype that references them.
This addresses one of the problems mentioned in issue #53.
Previously, when a struct type first appeared in a symbol table nested within another struct type, subsequent references to that type would use the wrong offset and be corrupted. This occurred because the symbol table length had not yet been updated to reflect the size of the entry for the outer structure at the time the inner one was processed.
Fixes#54.
Global structs and unions with the const qualifier were not being generated in object files. This occurred because they were represented as having "defined types" and the code was not handling those types properly.
The following example demonstrated this problem:
const struct x { int i; } X = {9};
int main(void) {
return X.i;
}
This fixes a problem with ORCA/C conformance test C5.6.0.1.CC, which was introduced by commit bf9fa66. A slightly more involved fix was needed to preserve the correct behavior while avoiding the memory trashing fixed by that patch.