Home | History | Annotate | Line # | Download | only in lint1
README.md revision 1.2
      1  1.2  rillig [//]: # ($NetBSD: README.md,v 1.2 2022/04/13 22:58:18 rillig Exp $)
      2  1.1  rillig 
      3  1.1  rillig # Introduction
      4  1.1  rillig 
      5  1.2  rillig To learn how a specific message is triggered, read the corresponding unit
      6  1.1  rillig test in `tests/usr.bin/xlint/lint1/msg_???.c`.
      7  1.1  rillig 
      8  1.1  rillig # Features
      9  1.1  rillig 
     10  1.1  rillig ## Type checking
     11  1.1  rillig 
     12  1.1  rillig Lint has stricter type checking than most C compilers.
     13  1.1  rillig It warns about type conversions that may result in alignment problems,
     14  1.1  rillig see the test `msg_135.c` for examples.
     15  1.1  rillig 
     16  1.1  rillig ## Control flow analysis
     17  1.1  rillig 
     18  1.1  rillig Lint roughly tracks the control flow inside a single function.
     19  1.1  rillig It doesn't follow `goto` statements though.
     20  1.1  rillig See the test `msg_193.c` for examples.
     21  1.1  rillig 
     22  1.1  rillig ## Error handling
     23  1.1  rillig 
     24  1.1  rillig Lint tries to continue parsing and checking even after seeing errors.
     25  1.1  rillig This part of lint is not robust though, so expect some crashes here,
     26  1.1  rillig as variables may not be properly initialized or be null pointers.
     27  1.1  rillig 
     28  1.1  rillig # Fundamental types
     29  1.1  rillig 
     30  1.1  rillig Lint mainly analyzes expressions (`tnode_t`), which are formed from operators
     31  1.1  rillig (`op_t`) and their operands (`tnode_t`).
     32  1.1  rillig Each node has a type (`type_t`) and a few other properties.
     33  1.1  rillig 
     34  1.1  rillig ## type_t
     35  1.1  rillig 
     36  1.1  rillig The basic types are `int`, `_Bool`, `unsigned long`, and so on.
     37  1.1  rillig A basic type is created by `gettyp(INT)`.
     38  1.1  rillig Derived types are created by `block_derive_pointer`,
     39  1.2  rillig `block_derive_array` and `block_derive_function`.
     40  1.1  rillig (See [below](#memory-management) for the meaning of the prefix `block_`.)
     41  1.1  rillig 
     42  1.1  rillig After a type has been created, it should not be modified anymore.
     43  1.1  rillig Ideally all references to types would be `const`, but that's a lot of work.
     44  1.1  rillig Until that is implemented, before modifying a type,
     45  1.1  rillig it needs to be copied using `block_dup_type` or `expr_dup_type`.
     46  1.1  rillig 
     47  1.1  rillig ## tnode_t
     48  1.1  rillig 
     49  1.2  rillig When lint parses an expressions,
     50  1.1  rillig it builds a tree of nodes representing the AST.
     51  1.1  rillig Each node has an operator, which defines which other members may be accessed.
     52  1.1  rillig The operators and their properties are defined in `ops.def`.
     53  1.1  rillig Some examples for operators:
     54  1.1  rillig 
     55  1.1  rillig | Operator | Meaning                                                 |
     56  1.1  rillig |----------|---------------------------------------------------------|
     57  1.1  rillig | CON      | compile-time constant in `tn_val`                       |
     58  1.1  rillig | NAME     | references the identifier in `tn_sym`                   |
     59  1.1  rillig | UPLUS    | the unary operator `+tn_left`                           |
     60  1.1  rillig | PLUS     | the binary operator `tn_left + tn_right`                |
     61  1.1  rillig | CALL     | a function call, typically CALL(LOAD(NAME("function"))) |
     62  1.1  rillig | CVT      | an implicit conversion or an explicit cast              |
     63  1.1  rillig 
     64  1.1  rillig ## sym_t
     65  1.1  rillig 
     66  1.1  rillig There is a single symbol table (`symtab`) for the whole translation unit.
     67  1.1  rillig This means that the same identifier may appear multiple times.
     68  1.1  rillig To distinguish the identifiers, each symbol has a block level.
     69  1.1  rillig Symbols from inner scopes are added to the beginning of the table,
     70  1.1  rillig so they are found first when looking for the identifier.
     71  1.1  rillig 
     72  1.1  rillig # Memory management
     73  1.1  rillig 
     74  1.1  rillig ## Block scope
     75  1.1  rillig 
     76  1.1  rillig The memory that is allocated by the `block_*_alloc` functions is freed at the
     77  1.1  rillig end of analyzing the block, that is, after the closing `}`.
     78  1.1  rillig See `compound_statement_rbrace:` in `cgram.y`.
     79  1.1  rillig 
     80  1.1  rillig ## Expression scope
     81  1.1  rillig 
     82  1.1  rillig The memory that is allocated by the `expr_*_alloc` functions is freed at the
     83  1.1  rillig end of analyzing the expression.
     84  1.1  rillig See `expr_free_all`.
     85  1.1  rillig 
     86  1.1  rillig # Null pointers
     87  1.1  rillig 
     88  1.1  rillig * Expressions can be null.
     89  1.2  rillig     * This typically happens in case of syntax errors or other errors.
     90  1.1  rillig * The subtype of a pointer, array or function is never null.
     91  1.1  rillig 
     92  1.1  rillig # Common variable names
     93  1.1  rillig 
     94  1.1  rillig | Name | Type      | Meaning                                              |
     95  1.1  rillig |------|-----------|------------------------------------------------------|
     96  1.1  rillig | t    | `tspec_t` | a simple type such as `INT`, `FUNC`, `PTR`           |
     97  1.1  rillig | tp   | `type_t`  | a complete type such as `pointer to array[3] of int` |
     98  1.1  rillig | stp  | `type_t`  | the subtype of a pointer, array or function          |
     99  1.1  rillig | tn   | `tnode_t` | a tree node, mostly used for expressions             |
    100  1.1  rillig | op   | `op_t`    | an operator used in an expression                    |
    101  1.1  rillig | ln   | `tnode_t` | the left-hand side operand of a binary operator      |
    102  1.1  rillig | rn   | `tnode_t` | the right-hand side operand of a binary operator     |
    103  1.1  rillig | sym  | `sym_t`   | a symbol from the symbol table                       |
    104  1.1  rillig 
    105  1.1  rillig # Abbreviations
    106  1.1  rillig 
    107  1.1  rillig | Abbr | Expanded |
    108  1.1  rillig |------|----------|
    109  1.1  rillig | l    | left     |
    110  1.1  rillig | r    | right    |
    111  1.1  rillig | st   | subtype  |
    112  1.1  rillig | op   | operator |
    113  1.1  rillig 
    114  1.2  rillig # Debugging
    115  1.2  rillig 
    116  1.2  rillig Useful breakpoints are:
    117  1.2  rillig 
    118  1.2  rillig | Location                      | Remarks                                              |
    119  1.2  rillig |-------------------------------|------------------------------------------------------|
    120  1.2  rillig | build_binary in tree.c        | Creates an expression for a unary or binary operator |
    121  1.2  rillig | initialization_expr in init.c | Checks a single initializer                          |
    122  1.2  rillig | expr in tree.c                | Checks a full expression                             |
    123  1.2  rillig | typeok in tree.c              | Checks two types for compatibility                   |
    124  1.2  rillig | vwarning_at in err.c          | Prints a warning                                     |
    125  1.2  rillig | verror_at in err.c            | Prints an error                                      |
    126  1.2  rillig | assert_failed in err.c        | Prints the location of a failed assertion            |
    127  1.2  rillig 
    128  1.1  rillig # Tests
    129  1.1  rillig 
    130  1.1  rillig The tests are in `tests/usr.bin/xlint`.
    131  1.2  rillig By default, each test is run with the lint flags `-g` for GNU mode,
    132  1.1  rillig `-S` for C99 mode and `-w` to report warnings as errors.
    133  1.1  rillig 
    134  1.1  rillig Each test can override the lint flags using comments of the following forms:
    135  1.2  rillig 
    136  1.1  rillig * `/* lint1-flags: -tw */` replaces the default flags.
    137  1.1  rillig * `/* lint1-extra-flags: -p */` adds to the default flags.
    138  1.1  rillig 
    139  1.1  rillig Most tests check the diagnostics that lint generates.
    140  1.1  rillig They do this by placing `expect` comments near the location of the diagnostic.
    141  1.1  rillig The comment `/* expect+1: ... */` expects a diagnostic to be generated for the
    142  1.1  rillig code 1 line below, `/* expect-5: ... */` expects a diagnostic to be generated
    143  1.1  rillig for the code 5 lines above.
    144  1.1  rillig Each `expect` comment must be in a single line.
    145  1.1  rillig There may be other code or comments in the same line.
    146  1.1  rillig 
    147  1.1  rillig Each diagnostic has its own test `msg_???.c` that triggers the corresponding
    148  1.1  rillig diagnostic.
    149  1.1  rillig Most other tests focus on a single feature.
    150  1.1  rillig 
    151  1.1  rillig ## Adding a new test
    152  1.1  rillig 
    153  1.1  rillig 1. Run `make -C tests/usr.bin/xlint/lint1 add-test NAME=test_name`.
    154  1.1  rillig 2. Run `cvs commit distrib/sets/lists/tests/mi tests/usr.bin/xlint`.
    155