Commit Graph

71 Commits

Author SHA1 Message Date
Stephen Heumann
bc951b6735 Make lint report some more cases where noreturn functions may return.
This uses a heuristic that may produce both false positives and false negatives, but any false positives should reflect extraneous code at the end of the function that is not actually reachable.
2020-01-30 17:35:15 -06:00
Stephen Heumann
a4abc5e421 Recognize enum type specifiers as such.
They were erroneously triggering the "type specifier missing" lint warning.
2020-01-29 21:15:33 -06:00
Stephen Heumann
80c513bbf2 Add a lint flag for checking if _Noreturn functions may return.
Currently, this only flags return statements, not cases where they may execute to the end of the function. (Whether the function will actually return is not decidable in general, although it may be in special cases).
2020-01-29 19:26:45 -06:00
Stephen Heumann
4fd642abb4 Add lint check for return with no value in a non-void function.
This is disallowed in C99 and later.
2020-01-29 18:50:45 -06:00
Stephen Heumann
a9f5fb13d8 Introduce a new #pragma lint bit for syntax that C99 disallows.
This currently checks for:
*Calls to undefined functions (same as bit 0)
*Parameters not declared in K&R-style function definitions
*Declarations or type names with no type specifiers (includes but is broader than the condition checked by bit 1)
2020-01-29 18:33:19 -06:00
Stephen Heumann
ffe6c4e924 Spellcheck comments throughout the code.
There are no non-comment changes.
2020-01-29 17:09:52 -06:00
Stephen Heumann
a72b611272 Make unnamed bit-fields take up space.
They should take up the same space as a named bit-field of the same width.

This fixes #60.
2020-01-28 22:54:40 -06:00
Stephen Heumann
f5cd1e3e3a Recognize designated initializers enough to give an error and skip them.
Previously, the designated initializer syntax could confuse the parser enough to cause null pointer dereferences. This avoids that, and also gives a more meaningful error message to the user.
2020-01-28 12:48:09 -06:00
Stephen Heumann
9862500dee Give an error if a parameter in a function definition has an incomplete type.
In combination with earlier patches, this fixes #53.

Also, if the lint flag requiring explicit function types is set, then also require that K&R-style parameters be explicitly declared with types, rather than not being declared and defaulting to int. (This is a requirement in C99 and later.)
2020-01-20 12:43:01 -06:00
Stephen Heumann
dd92585116 Give errors for most illegal uses of "restrict". 2020-01-19 17:31:20 -06:00
Stephen Heumann
49dea49cb8 Detect and give errors for various illegal uses of _Alignas. 2020-01-19 17:06:01 -06:00
Stephen Heumann
a130e79929 Prohibit _Noreturn specifier on non-functions. 2020-01-19 14:57:28 -06:00
Stephen Heumann
d10478967f Allow "restrict" in pointer declarators.
Valid uses of "restrict" should now be permitted, but invalid uses do not necessarily give errors (and it is not used for any kind of optimization).
2020-01-19 07:15:35 -06:00
Stephen Heumann
b4232fd4ea Flag more appropriate errors about unexpected tokens in type names.
Previously, these would report "identifier expected"; now they correctly say "')' expected".

This introduces a new UnexpectedTokenError procedure that can be used more generally for cases where the expected token may differ based on context.
2020-01-18 16:43:25 -06:00
Stephen Heumann
dbe330a7b1 Use centrally-defined token sets to recognize the beginning of declarations. 2020-01-18 15:21:27 -06:00
Stephen Heumann
0f3bb11d22 Remove special-case code for declarations with no declaration specifiers.
This can now be folded into the regular code path.
2020-01-18 15:21:24 -06:00
Stephen Heumann
08b4f8da3e Remove some unnecessary parameters and code.
These are not needed after the refactoring of declaration specifier processing.
2020-01-18 15:20:56 -06:00
Stephen Heumann
df029ce06f Handle storage class specifiers in DeclarationSpecifiers.
_Thread_local is recognized but gives a "not supported" error. It could arguably be 'supported' trivially by saying the execution of an ORCA/C program is just one thread and so no special handling is needed, but that likely isn't what someone using it would expect.

There would be a possible issue if a "static" or "typedef" storage class specifier occurred after a type specifier that required memory to be allocated for it, because that memory conceptually might be in the local pool, but static objects are processed at the end of the translation unit, so their types need to stick around. In practice, this should not occur, because the local pool isn't currently used for much (in particular, not for statements or declarations in the body of a function). We give an error in case this somehow might occur.

In combination with preceding commits, this fixes #14. Declaration specifiers can now appear in any order, as required by the C standards.
2020-01-18 14:52:27 -06:00
Stephen Heumann
fbe44e1852 Process function specifiers in DeclarationSpecifiers.
This includes both the standard ones (inline and _Noreturn) and the ORCA/C-specific ones (asm and pascal). They can now be freely mixed with other declaration specifiers.

Some errors related to function specifiers are not yet detected.
2020-01-15 07:28:44 -06:00
Stephen Heumann
84767f3340 Prevent output values of DeclarationSpecifiers from being corrupted by a recursive call to it.
This could happen in a declaration like "char _Alignas(long) c;", where typeSpec wound up specifying long rather than char.

Also, tweak error checks for _Alignas and _Atomic.
2020-01-12 17:15:25 -06:00
Stephen Heumann
8341f71ffc Initial phase of support for new C99/C11 type syntax.
_Bool, _Complex, _Imaginary, _Atomic, restrict, and _Alignas are now recognized in types, but all except restrict and _Alignas will give an error saying they are not supported.

This also introduces uniform definitions of the syntactic classes of tokens that can be used in declaration specifiers and related constructs (currently used in some places but not yet in others).
2020-01-12 15:43:30 -06:00
Stephen Heumann
3ce2be9f74 Simplify handling of const and volatile type qualifiers.
These qualifiers were previously sometimes accepted between the name and left brace of struct and enum type specifiers. This was non-standard and is no longer allowed.
2020-01-08 13:06:49 -06:00
Stephen Heumann
428c991895 Rewrite type specifier parsing.
Type specifiers and type qualifiers can now appear in any order, as specified by the C standards. However, storage class specifiers and function specifiers still cannot be freely mixed with them.
2020-01-07 20:26:56 -06:00
Stephen Heumann
06a027b237 Rename TypeSpecifier to DeclarationSpecifiers, consistent with C standard terminology.
Also remove its first argument, which was unused. There is no functional change yet.
2020-01-06 20:18:58 -06:00
Stephen Heumann
a9fb1ba482 Move TypeName to be a top-level method in Parser.pas.
As of C11, type names are now used as part of the declaration syntax (in _Alignas and _Atomic specifiers), in addition to their uses in expressions. Moving the TypeName method will allow it to be called when processing declarations.
2020-01-06 20:18:58 -06:00
Stephen Heumann
6f2eb301e5 Implement C11 _Static_assert mechanism.
This allows code to contain static assertions (checked at compile time).
2020-01-04 18:16:29 -06:00
Stephen Heumann
9030052616 When initializing bitfields of type long, do not treat their values as pointer constants.
This was inappropriate and would lead to memory trashing.

Fixes case 3 in issue #59.
2019-12-24 18:52:25 -06:00
Stephen Heumann
4db26d14bd Skip initializer processing for flexible array members.
This could result in null pointer dereferences.
2019-12-23 21:33:27 -06:00
Stephen Heumann
b0b2b3fa91 Do not attempt to generate code for malformed initializers with no usable initializer expression.
This would lead to null pointer dereferences, and could possibly cause unpredictable behavior based on the values read.
2019-12-23 14:09:08 -06:00
Stephen Heumann
b88dc5b39c Eliminate a null pointer dereference when processing prototyped function declarators.
This should normally have been harmless, but might possibly give an error in obscure circumstances.
2019-12-22 22:16:03 -06:00
Stephen Heumann
095060ca70 Avoid null pointer dereferences when generating code for initializers.
These should have been harmless under ORCA/Pascal on the IIgs, assuming the code is otherwise functioning properly.
2019-12-22 19:12:05 -06:00
Stephen Heumann
cfa3e4e02d Allow prototyped function parameter types to begin with "volatile".
Prototypes with such parameter types were incorrectly being rejected, e.g. in the following example:

void foo(volatile int *p);
2018-12-03 18:19:28 -06:00
Stephen Heumann
62757acdb1 Fix bug that could cause generation of invalid sym files.
When these invalid sym files were used during subsequent compiles, certain type pointers (for what should be const-qualified struct or union types) could be left uninitialized, or possibly initialized pointing to different types. This could result in spurious errors or potentially in other problems.
2018-09-15 00:11:36 -05:00
Stephen Heumann
fedd275395 Fix issues where static initialization may generate the wrong number of bytes.
This relates to unions or structs that are "filled" with zeros because the initializer does not include explicit terms for them, and that contain bit-fields or (for unions) do not start with the longest member.

The following program is an example that was miscompiled:

#include <stdio.h>

struct BF {
        int i:3;
        int j:4;
};

union U {
        int i;
        long l;
};

struct Outer1 {
        int n;
        struct BF bf[7];
        union U u[5];
};

struct Outer2 {
        long p;
        struct Outer1 o1;
        long q;
};

int main(void) {
        static struct Outer2 s = {1,{0},212};
        printf("%li %li\n", s.p, s.q);
}
2018-09-14 19:02:21 -05:00
Stephen Heumann
4d10fbae01 Fix several initialization issues.
This fixes case 1 (dealing with run-time initialization of structures containing bit-fields) and case 2 (dealing with initialization of structs where initializer values are not provided for all elements) from issue #59. It also fixes cases that could result in invalid initialization of unions if their first element was not the longest, as in the following example:

#include <stdio.h>
union U {
        int i;
        long l;
};
int main(void) {
        union U a[5] = {1,2,3,4};
        printf("a[0].i=%i, a[1].i=%i, a[2].i=%i, a[3].i=%i, a[4].i=%i\n",
                a[0].i, a[1].i, a[2].i, a[3].i, a[4].i);
}
2018-09-14 18:13:33 -05:00
Stephen Heumann
4de0035d77 Remove support for the non-standard "long float" type.
This was an alias for double, but it's non-standard and undocumented. Apparently it existed in some other pre-standard compilers, but it's not in any version of standard C, and I can't find any evidence of it being used. Considering the possibility for confusion, I think it's best to remove it.
2018-09-08 18:12:48 -05:00
Stephen Heumann
0e341e1153 Record line numbers for certain auto variable declarations with initializers.
This allows debuggers to stop on the declaration lines, and also provides trace-back information for them if that feature is enabled.

Currently, this applies only to declarations that occur after the first statement in the block. As such, it doesn't change the handling of traditional pre-C99-style declarations at the beginning of a block.
2018-09-02 15:22:58 -05:00
Stephen Heumann
0b8d4ce3e4 Fix invalid static initialization of bitfields occupying three bytes.
An extra, fourth byte was being generated for the bitfield(s). This would cause all subsequent members of the struct and any enclosing object not to be initialized at the proper locations, which would generally corrupt their values.

The following program illustrates the issue:

#include <stdio.h>

struct X {
    int a:9;
    int b:9;
    int c;
} x = {123,234,12345};

int main(void) {
    printf("x.a = %i, x.b = %i, x.b = %i\n", x.a, x.b, x.c);
}
2018-04-11 23:42:04 -05:00
Stephen Heumann
0cfed00b52 Fix problem with static initialization of bitfields followed by non-bitfield members.
The initialized bytes for the bitfield(s) could wind up improperly being placed after those for the non-bitfield, generally corrupting both values.

The following program illustrates the problem:

#include <stdio.h>

struct X {
    int a:9;
    int b;
} x = {42,123};

int main(void) {
    printf("x.a = %i, x.b = %i\n", x.a, x.b);
}
2018-04-11 23:30:48 -05:00
Stephen Heumann
caabb5addf Allow declarations in first clause of for loop (C99). 2018-04-01 16:48:11 -05:00
Stephen Heumann
275e1f080b Add a new flag to control whether mixed declarations are allowed and C99 scope rules are used.
#pragma ignore bit 4 (a value of 16) now controls these. It is on by default (allowing them), but turning it off will restore the C89 rules.
2018-04-01 14:14:18 -05:00
Stephen Heumann
2be0ef0de5 Allow initialization of static/global variables with the address of members of const structs.
Note that this code currently permits discarding the const qualifier via such an initialization. That should give a diagnostic, but currently it doesn't in this or various other cases.

The following code (derived from a csmith-generated test case) illustrates the problem:

struct S0 {
   const long  f4;
};
const struct S0 g_149;
const long *g_311 = &g_149.f4;
2018-03-31 21:40:43 -05:00
Stephen Heumann
4746d9ff60 Allow initialization of local vars with const-qualified struct or union type.
Here's an example that shows the problem (derived from a csmith-generated test case):

void f(void)
{
    const struct S {int i;} s = {1};
}
2018-03-25 18:22:37 -05:00
Stephen Heumann
237af41e90 Fix issue where a label with the same name as a typedef name was parsed as the beginning of a declaration.
This would lead to errors in programs like the following:

int main(void) {
        typedef int x;
x: ;
}

Even before support for mixed statements and declarations was introduced, this error could happen if the labeled statement was the first statement after the declarations in a block (as in the above example). Adding that support also allowed this error to happen with later statements in a block. The C4.2.4.1.CC test case was affected by this.
2018-03-25 18:22:37 -05:00
Stephen Heumann
d6502c0719 Implement C99 scope rules for selection and iteration statements.
Under these rules, if, switch, for, while, and do statements each have their own block scopes separate from the enclosing scope, and their substatements also have their own block scopes.

This patch always applies the C99 scope rules, but a flag can be changed to disable them or make them conditional on a configuration setting.
2018-03-25 18:22:37 -05:00
Stephen Heumann
14adcd6a80 Allow mixed declarations and statements (C99). 2018-03-25 18:22:37 -05:00
Stephen Heumann
324c979f3b Correctly handle tentative struct/union and array definitions that are not completed.
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).
2018-03-06 22:53:52 -06:00
Stephen Heumann
c55acd1150 Give an error if the element type of an array type is an incomplete or function type. 2018-03-06 22:46:23 -06:00
Stephen Heumann
4a7644e0b5 Don't allocate stack space for varargs stack repair unless it's needed.
If there are no varargs calls (and nothing else that saves stack positions), then space doesn't need to be allocated for the saved stack position. This can also lead to more efficient prolog/epilog code for small functions.
2018-01-13 20:02:43 -06:00
Stephen Heumann
c588eda94e Allow a typedef'd version of "void" to be used in the parameter list of a function taking no arguments.
For example, the following is now allowed:
typedef void v;
void foo(v) {}

This appears to be permitted under at least C99 and C11 (the C89 wording is less clear), and is accepted by other modern compilers.
2017-10-21 20:36:21 -05:00