Commit Graph

80 Commits

Author SHA1 Message Date
Stephen Heumann
afe3e9586b Fix bad code generation in some cases where compound assignment operators are used to update a value through a pointer.
This could occur because a temporary location might be used both in the l-value and r-value computations, but the final assignment code assumed it still had the value from the l-value computation.

The following function demonstrates this problem (*ip is not updated, and *p is trashed):

int badinc(char **p, int *ip)
{
    *ip += *(*p)++;
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
4cff395745 Move some code from the blank segment to named load segments.
This frees up some space in the blank segment for more static data.
2017-10-21 20:36:21 -05:00
Stephen Heumann
280f67e846 Make || and && operators in constant expressions yield results of type int.
Previously the result type was based on the operand types (using the arithmetic conversions), which is incorrect. The following program illustrates the issue:

#include <stdio.h>
int main(void)
{
    /* should print "1 0 2 2" */
    printf("%i %i %lu %lu\n", 0L || 2, 0.0 && 2,
           sizeof(1L || 5), sizeof(1.0 && 2.5));
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
40bed0a93e Allow application of the unary ! operator to floating constants.
The following is an example of a program that requires this:

#include <stdio.h>
int main(void)
{
    int true = !0.0;
    int false = !1.1;
    printf("%i %i\n", true, false);
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
cd9a424499 Remove bogus code for applying unary &, ++, and -- operators to integer constants.
This is already precluded from executing by an earlier test, so there is no functional change.
2017-10-21 20:36:21 -05:00
Stephen Heumann
7ab1875b54 Evaluate preprocessor expressions using 32-bit long/unsigned long types.
This is as required by C90. C99 and later require (u)intmax_t, which must be 64-bit or greater.

The following example shows problems with the previous behavior:

#if (30000 + 30000 == 60000) && (1 << 16 == 0x10000)
int main(void) {}
#else
#error "preprocessor error"
#endif
2017-10-21 20:36:21 -05:00
Stephen Heumann
60df52c268 Disallow the application of the unary * operator to integer constants.
It must only be applied to pointer types.
2017-10-21 20:36:21 -05:00
Stephen Heumann
7fa74d1183 Allow floating literals that are immediately cast to integer types to appear in integer constant expressions.
The C standards say these should be permitted. The following declaration shows an example:

int a[(int)5.5];
2017-10-21 20:36:21 -05:00
Stephen Heumann
018f5a7548 Fix bug where constant expressions involving unsigned int and signed long operands would be evaluated as unsigned long.
The following example demonstrates the problem:

#include <stdio.h>
int main (void)
{
	printf("%i\n", -5L < 10U); /* should print "1" */
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
b6b2121a9e Allow unsigned long values greater than 2^31 to be used as the second operand to % in constant expressions.
The following is an example that would give a compile error before this patch:

int main(void)
{
    unsigned long i = 1 % 3000000000;
}

The remainder operation still does not work properly for signed types when either operand is negative. It gives either errors or incorrect values in various cases, both when evaluated at compile time and run time. Fully addressing this (including the run-time cases) would require library updates.
2017-10-21 20:36:21 -05:00
Stephen Heumann
f099222af6 Don't give an error when calling functions with const-qualified parameter types or returning from functions with const-qualified return type.
This fixes the compco12.c test case.
2017-10-21 20:36:21 -05:00
Stephen Heumann
49ddf5abf1 Allow type qualifiers for pointer types to be used in type names (in casts and sizeof expressions).
This fixes the compco09.c test case.

This implementation permits duplicate copies of type qualifiers to appear. This is technically illegal in C90, but it’s legal in C99 and later, and ORCA/C already allows this in other contexts.
2017-10-21 20:36:21 -05:00
Stephen Heumann
896c60d18c Determine the type to use for computing a >>= or <<= operation based only on the left operand.
Also, fix a case where an uninitialized value could be used, potentially resulting in errors not being reported (although I haven’t seen that in practice).

This fixes problems where >>= operations might not use an arithmetic shift in certain cases where they should, as in the below program:

#include <stdio.h>
int main (void)
{
    int i;
    unsigned u;
    long l;
    unsigned long ul;

    i = -1;
    u = 1;
    i >>= u;
    printf("%i\n", i); /* should be -1 */

    l = -1;
    ul = 3;
    l >>= ul;
    printf("%li\n", l); /* should be -1 */
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
67a29304a7 Fix to consistently update expressionType to reflect the application of usual unary conversions (promotions).
This is necessary so that subsequent processing sees the correct expression type and proceeds accordingly. In particular, without this patch, the casts in the below program were erroneously ignored:

#include <stdio.h>
int main(void)
{
    unsigned int u;
    unsigned char c;

    c = 0;
    u = (unsigned char)~c;
    printf("%u\n", u);

    c = 200;
    printf("%i\n", (unsigned char)(c+c));
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
af48935d43 Fix so the type of shift expressions depends only on the (promoted) type of their left operand.
This is as required by the C standards: the type of the right operand should not affect the result type.

The following program demonstrates problems with the old behavior:

#include <stdio.h>

int main(void)
{
    unsigned long ul;
    long l;
    unsigned u;
    int i;

    ul = 0x8000 << 1L; /* should be 0 */
    printf("%lx\n", ul);

    l = -1 >> 1U; /* should be -1 */
    printf("%ld\n", l);

    u = 0xFF10;
    l = 8;
    ul = u << l; /* should be 0x1000 */
    printf("%lx\n", ul);

    l = -4;
    ul = 1;
    l = l >> ul; /* should be -2 */
    printf("%ld\n", l);
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
8b4c83f527 Give an error when trying to use sizeof on incomplete struct or union types.
The following demonstrates cases that would erroneously be allowed (and misleadingly give a size of 0) before:

#include <stdio.h>
struct s *S;
int main(void)
{
        printf("%lu %lu\n", sizeof(struct s), sizeof *S);
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
5950002d03 Fix so the result of sizeof has type unsigned long (i.e. size_t), not signed long.
The following test case demonstrates the problem:

#include <stdio.h>

int main (void)
{
        if (sizeof(int) - 5 < 0) puts("error 1");
        if (sizeof &main - 9 < 0) puts("error 2");
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
26a800e667 Fix bug where certain integer constant expressions would have type signed long when they should have type unsigned long.
This affected binary or unary expressions with constant operands, at least one of which was of type unsigned long.

The following test case demonstrates the problem:

#include <stdio.h>
int main (void)
{
        if (0 + 0x80000000ul < 0) puts("error 1");
        if (~0ul < 0) puts("error 2");
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
fa5974199d Don't allow the unary * operator to be applied to structs and unions. 2017-10-21 20:36:20 -05:00
Stephen Heumann
f7c3c26794 Report an error when trying to cast a void expression to a non-void type. 2017-10-21 20:36:20 -05:00
Stephen Heumann
89f1dbce9b Report an error when void values are used in binary expressions.
These would previously be allowed, with the void value treated as if it was unsigned long.

Void values are still allowed for the second and third operands of the ?: operator, but only if they are both void. This is as required by the C standard.
2017-10-21 20:36:20 -05:00
Stephen Heumann
b83ed7b17b Do not erroneously treat integer constant expressions of type unsigned int as signed in certain contexts.
Unsigned constants in the range 0x8000-0xFFFF were erroneously being treated like negative signed values in some contexts, including in array declarators and in the case labels of switch statements where the expression switched over has type long or unsigned long.

This could lead to bogus compile errors for array declarations and typedefs such as the following:

typedef char foo[0x8000];

It could also lead to cases in switch statements not being properly matched, as in the following program:

#include <stdio.h>
int main(void)
{
    long i = 0xFF00;
    switch (i) {
        case 0xFF00:
            puts("good");
            break;
        default:
            puts("bad");
    }
}
2017-10-21 20:36:20 -05:00
Stephen Heumann
ab51fc228d Allow string and double constants to appear within the operands of sizeof in a constant expression.
This fixes one of the problems in the compca08.c test case.
2017-10-21 20:36:20 -05:00
Stephen Heumann
3b9101ea30 Support += and -= operators on function parameters declared using array syntax (which are adjusted to have pointer type).
This fixes the compca25.c test case.
2017-10-21 20:36:20 -05:00
Stephen Heumann
78493936bc When a bit-field is used within an lvalue expression but isn't what's being assigned to, don't erroneously assign to the bit-field instead.
This fixes the compca04.c test case.
2017-10-21 20:36:20 -05:00
Stephen Heumann
c788052b99 Allow dereferencing pointers to const struct or const union types.
This fixes the bug in the compca03.c test case.
2017-10-21 20:36:20 -05:00
Stephen Heumann
c4360c70a1 Allow arrays to be used (implicitly converted to pointers) as operands of && and ||, and the first operand of the ? : operator.
This fixes the bug in the compca02.c test case.
2017-10-21 20:36:20 -05:00
Stephen Heumann
a39c06d268 Usual unary conversions (promotions) should promote unsigned char to int, not unsigned int.
This fixes the compca13.c test case.
2017-10-21 20:36:20 -05:00
Stephen Heumann
46b6aa389f Change all text/source files to LF line endings. 2017-10-21 18:40:19 -05:00
mikew50
e72177985e ORCA/C 2.1.0 source from the Opus ][ CD 2017-10-01 17:47:47 -06:00