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