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