It could wind up storing garbage in the upper 8 bits of the destination, because it was not doing a proper 8-bit to 16-bit conversion.
This is an old bug, but the change in commit 95f5182442 caused it to be triggered in more cases, e.g. in the C7.5.1.1.CC test case.
Here is a case that could exhibit the bug even before that:
#pragma optimize 1
#include <stdio.h>
int main(void) {
int k[1];
int i = 0;
unsigned char uch = 'm';
k[i] = uch;
printf("%i\n", k[0]);
}
This applies to octal and hexadecimal sequences with out-of-range values, and also to unrecognized escape characters. The C standards say both of these cases are syntax/constraint violations requiring a diagnostic.
This behavior is specified by the C standards. It can come up when declaring an array using a typedef'd array type and a qualifier.
This is necessary for correct behavior of _Generic, as well as to give an error if code tries to write to const arrays declared in this way.
Here is an example showing these issues:
#define f(e) _Generic((e), int *: 1, const int *:2, default: 0)
int main(void) {
typedef int A[2][3];
const A a = {{4, 5, 6}, {7, 8, 9}};
_Static_assert(f(&a[0][0]) == 2, "qualifier error"); // OK
a[1][1] = 42; // error
}
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;
}
}
This is required by C99 and later, enabled by the availability of __func__.
This requires an updated assertion-printing function in ORCALib. Unfortunately, GNO has the assertion-printing function in its libc rather than in ORCALib, because it calls the GNO implementation of stdio. Therefore, we continue to use the old form under GNO for now, to maintain compatibility with its existing libc.
Previously, they were hard-coded as 60, but the clock tick frequency actually depends on the video mode. They now call a new library function that can detect the video mode and return the proper value.
This also makes CLOCKS_PER_SEC have the type clock_t, as C99 and later require.
These are currently only run by the new DOIT3 test-running script.
Note that these tests are designed to be applicable to most implementations of C95/C99/C11, not just ORCA/C. They do make certain assumptions not guaranteed by the standards (e.g. power of 2 types and some properties of IEEE-like FP), but in general those assumptions should be true for most 'normal' systems.
Enumeration constants must have values representable as an int (i.e. 16-bit signed values, in ORCA/C), but errors were not being reported if code tried to use the values 0xFFFF8000 to 0xFFFFFFFF. This problem could also affect certain larger values of type unsigned long long. The issue stemmed from not properly accounting for whether the constant expression had a signed or unsigned type.
This sample code demonstrated the problem:
enum E {
a = 0xFFFFFFFF,
b = 0xFFFF8000,
y = 0x7FFFFFFFFFFFFFFFull,
z = 0x8000000000000000
};
This should be allowed, but it previously could lead to spurious errors in contexts like argument lists, where a comma would normally be expected to end the expression.
The following example program demonstrated the problem:
#include <stdlib.h>
int main(void) {
return abs(1 ? 2,-3 : 4);
}
The correct values for LDBL_MAX and LDBL_MIN can now be provided, because we support long double constants. The other values are also updated to have more precision, so that they evaluate to bit-correct values in the long double format.
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.
These were previously treated as having type int. This resulted in incorrect results from sizeof, and would also be a problem for _Generic if it was implemented.
Note that this creates a token kind of "charconst", but this is not the kind for character constants in the source code. Those have type int, so their kind is intconst. The new kinds of "tokens" are created only through casts of constant expressions.
Previously, the type was forced to extended in many circumstances. This was visible in that the results of sizeof were incorrect. It would also affect _Generic, if and when that is implemented.
Note that this does not affect the actual format used for computations and storage of intermediates. That is still the extended format.
This could read and write a byte beyond the value being modified. This normally would not matter, but theoretically could in some cases involving concurrency.
The C standards generally allow floating-point operations to be done with extra range and precision, but they require that explicit casts convert to the actual type specified. ORCA/C was not previously doing that.
This patch relies on some new library routines (currently in ORCALib) to do this precision reduction.
This fixes#64.
The FENV_ACCESS pragma is now implemented. It causes floating-point operations to be evaluated at run time to the maximum extent possible, so that they can affect and be affected by the floating-point environment. It also disables optimizations that might evaluate floating-point operations at compile time or move them around calls to the <fenv.h> functions.
The FP_CONTRACT and CX_LIMITED_RANGE pragmas are also recognized, but they have no effect. (FP_CONTRACT relates to "contracting" floating-point expressions in a way that ORCA/C does not do, and CX_LIMITED_RANGE relates to complex arithmetic, which ORCA/C does not support.)
This was already done by the optimizer, but it is simple enough to just do it all the time. This avoids most performance regressions from the previous commit, and also generates more efficient code for long long stores (in the common cases where the value of an assignment expression is not used in any larger expression).
The value of an assignment expression should be exactly what gets written to the destination, without any extra range or precision. Since floating-point expressions generally do have extra precision, we need to load the actual stored value to get rid of it.
This means that floating-point constants can now have the range and precision of the extended type (aka long double), and floating-point constant expressions evaluated within the compiler also have that same range and precision (matching expressions evaluated at run time). This new behavior is intended to match the behavior specified in the C99 and later standards for FLT_EVAL_METHOD 2.
This fixes the previous problem where long double constants and constant expressions of type long double were not represented and evaluated with the full range and precision that they should be. It also gives extra range and precision to constants and constant expressions of type double or float. This may have pluses and minuses, but at any rate it is consistent with the existing behavior for expressions evaluated at run time, and with one of the possible models of floating point evaluation specified in the C standards.