1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
//! The procedural macro front end for [`cinrs`](https://docs.rs/cinrs).
//!
//! Deliberately a thin shim: everything interesting lives in `cinrs-core`,
//! which is built on `proc-macro2` and can therefore be tested without a
//! procedural macro context.
//!
//! # The `nightly` feature
//!
//! `cinrs-core` never touches `proc_macro`, so the one thing it cannot do by
//! itself is build a span that points *inside* a string literal —
//! `proc_macro::Literal::subspan` is unstable on every channel, and
//! `proc-macro2` does not expose it. With the `nightly` feature this crate
//! turns on `#![feature(proc_macro_span)]` and hands the front end a
//! [`Subspan`] hook that does exactly that, so a `c99! { r#"…"# }` body reports
//! its errors on the offending C token rather than on the whole literal with
//! the position spelled out in the message. Everything else is unchanged, and
//! without the feature — or wherever `subspan` declines to answer, as under
//! `rust-analyzer` — the stable behaviour comes back on its own.
use TokenStream;
use ;
/// Compiles a C89 (C90) translation unit written inside Rust.
///
/// The oldest entry point, and the one written for code that predates the 1999
/// standard: **implicit `int`** (`static x;`, `f() { … }`), **implicit
/// function declarations** (calling `abs` with nothing declaring it declares
/// `extern int abs();` from that point on) and **old-style (K&R) function
/// definitions** all work here, and everything C99 added is a diagnostic that
/// says so:
///
/// ```text
/// error: a '//' comment requires C99 or later (this block is c89!)
/// ```
///
/// What is gated: `//` comments, mixed declarations and code, a declaration in
/// a `for` clause, variable length arrays, `_Bool`, `restrict`, `inline`,
/// `long long`, designated initializers, compound literals, variadic macros,
/// flexible array members, hexadecimal floating constants, `__func__`,
/// `_Pragma`, universal character names, a trailing comma in an enumerator
/// list, `static` and `[*]` in an array parameter declarator, `_Complex` and
/// an imaginary constant (`2.0i`).
/// The *library* additions are not: a bundled header is a set of declarations,
/// and `snprintf` is one of them — with `<complex.h>` the one exception, since
/// every declaration in it names a type C89 does not have.
///
/// `__STDC_VERSION__` is **not defined** — C89 as published had no such macro
/// — while `__STDC__` is `1`, exactly as in `gcc -std=c89`.
/// [`c90!`](macro@c90) is another name for this macro, and
/// [`gnu89!`](macro@gnu89) is the GNU dialect of it.
/// Compiles a C90 translation unit written inside Rust.
///
/// ISO/IEC 9899:1990 is ANSI X3.159-1989 republished with no technical change,
/// so this is [`c89!`](macro@c89) under the other name the language has.
/// Compiles a C99 translation unit written inside Rust.
///
/// The body may be written as raw Rust tokens:
///
/// ```ignore
/// cinrs::c99! {
/// int add(int a, int b) { return a + b; }
/// }
/// ```
///
/// or, for C that the Rust lexer refuses (hex float literals, `L"…"`,
/// multi-character character constants, `\` line continuations, `##`), as a
/// single string literal:
///
/// ```ignore
/// cinrs::c99! { r#"
/// int add(int a, int b) { return a + b; }
/// "# }
/// ```
///
/// The expansion is a private module of its own plus a glob re-export of it,
/// so that two blocks in one Rust module may share a header without their
/// types colliding. Each function becomes a `pub unsafe extern "C" fn` of the
/// same name, taking and returning the [`core::ffi`] types, so the C above is
/// called as `unsafe { add(1, 2) }`; a C `static` function stays private to
/// the module, and a file-scope variable becomes a `static mut` item. A
/// `struct`, `union` or `enum` becomes a `#[repr(C)]` item Rust code can use
/// directly, and a function the unit only declares becomes an `extern "C"`
/// declaration linked against the real symbol.
///
/// The C99 preprocessor runs first — every directive, macros with `#`, `##`
/// and `__VA_ARGS__` included. `#include` finds the headers `cinrs` bundles
/// (`<stdio.h>`, `<string.h>`, `<math.h>` and the rest, written in plain C99
/// rather than read from the platform) and the user's own, in the directory of
/// the invoking `.rs` file and in whatever `#pragma cinrs include_path` adds.
/// Since Rust's lexer refuses `##` in raw-token form, a replacement list may
/// write the pasting operator as `a # # b` instead; see [Input forms] for that,
/// [the preprocessor] for the predefined macros, and [`#include` and `#embed`]
/// for the bundled headers.
///
/// [Input forms]: https://github.com/tanakh/cinrs/blob/master/doc/features.md#input-forms
/// [the preprocessor]: https://github.com/tanakh/cinrs/blob/master/doc/features.md#the-preprocessor
/// [`#include` and `#embed`]: https://github.com/tanakh/cinrs/blob/master/doc/features.md#include-and-embed
///
/// Errors are reported at the exact C token that caused them. In string
/// literal form, stable Rust cannot build a span pointing inside a literal, so
/// the position inside the C source is appended to the message instead — see
/// [the `nightly` feature](self#the-nightly-feature) for the way around that.
///
/// [`c11!`](macro@c11), [`c17!`](macro@c17) and [`c23!`](macro@c23) are the
/// same macro for a later revision of the language.
/// Compiles a C11 translation unit written inside Rust.
///
/// Everything [`c99!`](macro@c99) does, plus what C11 added:
/// `_Static_assert`, `_Alignof`, `_Alignas` (on the members of a `struct` or
/// `union`), `_Generic`, `_Noreturn`, `_Thread_local`, `_Atomic` with
/// `<stdatomic.h>`, anonymous `struct`/`union` members, and
/// the Unicode literals `u8"…"`, `u"…"`, `U"…"`, `u'x'` and `U'x'` with
/// `<uchar.h>`'s `char16_t` and `char32_t`, and the `CMPLX` family in
/// `<complex.h>`. `__STDC_VERSION__` is `201112L`.
///
/// C11's threads are here too, as the platform's own: `<threads.h>` is
/// bundled for the C libraries whose objects it can lay out — glibc and musl,
/// both on Linux — and is an `#error` naming the reason elsewhere, which is
/// where `__STDC_NO_THREADS__` is predefined. An `_Atomic` `struct` is a clear
/// error rather than a silent mistranslation — it would need a lock, and there
/// is nothing in the generated Rust to be one.
/// Compiles a C17 translation unit written inside Rust.
///
/// C17 is C11 with the defect reports applied and no new features, so this is
/// [`c11!`](macro@c11) with `__STDC_VERSION__` set to `201710L`.
/// Compiles a C23 translation unit written inside Rust.
///
/// Everything [`c11!`](macro@c11) does, plus the C23 keywords (`bool`, `true`,
/// `false`, `nullptr`, `static_assert`, `alignof`, `alignas`, `constexpr`,
/// `typeof`), `[[…]]` attributes, `__VA_OPT__`, `#elifdef` / `#elifndef`,
/// binary constants, digit separators, empty initialisers, `auto` type
/// inference, enumerations with a fixed underlying type, improved tag
/// compatibility (a tag defined twice in one scope with the same members is
/// one type), `unreachable()`,
/// `#embed`, `char8_t` and the `u8'x'` character prefix.
/// `__STDC_VERSION__` is `202311L`.
///
/// It is also the one entry point that has **no trigraphs**, which is what
/// C23 removed: `??=` here is two question marks and an `=`.
///
/// A digit separator (`1'000'000`) needs string-literal form: Rust's own lexer
/// reads `1'000` as a literal followed by a lifetime and refuses it.
/// Compiles a C99 translation unit with the GNU extensions switched on.
///
/// Everything [`c99!`](macro@c99) does, plus what GCC's `-std=gnu99` adds over
/// its `-std=c99`: the plain spellings `typeof` and `asm` are keywords, and a
/// construct a later revision introduced — `_Static_assert`, `_Generic`, a
/// `0b` literal — is accepted rather than being told which macro to write.
///
/// The extensions spelled with a leading double underscore — `__typeof__`,
/// `__attribute__`, `__extension__`, `__builtin_*`, `__restrict` — are
/// available in *every* entry point, exactly as they are in GCC's strict
/// modes: the names are reserved, so nothing a program may legally call its
/// own is taken away. `__STRICT_ANSI__` is defined only in the strict entry
/// points; `__GNUC__` is 4 in all of them. A GNU dialect also switches
/// **trigraphs off**, as `gcc -std=gnu99` does, so `"what??!"` there is an
/// exclamation rather than a pipe.
///
/// See [`doc/gnu-extensions.md`](https://github.com/tanakh/cinrs/blob/master/doc/gnu-extensions.md)
/// in the repository for the whole catalogue.
/// Compiles a C89 translation unit with the GNU extensions switched on.
///
/// What `gcc -std=gnu89` is: **everything a later revision added is accepted**
/// — `//` comments, mixed declarations and code, `long long`, designated
/// initializers and the rest, which C89 as an ISO document does not have and
/// GCC has always taken as extensions — *and* the three C89 rules that are not
/// a matter of extension at all, because a later revision deleted them:
/// implicit `int`, implicit function declarations, and old-style (K&R)
/// definitions (which every entry point below `c23!` has).
///
/// So `gnu89!` is [`gnu99!`](macro@gnu99) plus those three, with
/// `__STDC_VERSION__` left undefined; it is the entry point for the C of the
/// 1990s, and the one the GCC torture suite is measured with.
/// Compiles a C11 translation unit with the GNU extensions switched on.
///
/// [`c11!`](macro@c11) plus what [`gnu99!`](macro@gnu99) adds.
/// Compiles a C17 translation unit with the GNU extensions switched on.
///
/// [`c17!`](macro@c17) plus what [`gnu99!`](macro@gnu99) adds.
/// Compiles a C23 translation unit with the GNU extensions switched on.
///
/// [`c23!`](macro@c23) plus what [`gnu99!`](macro@gnu99) adds.
/// Compiles the C89 (C90) file at `path`.
///
/// [`include_c99!`](macro@include_c99) documents the whole family; this is the
/// [`c89!`](macro@c89) entry point of it, so implicit `int`, implicit function
/// declarations and old-style definitions are what the file may use, and
/// everything C99 added is a diagnostic.
/// Compiles the C90 file at `path`; see
/// [`include_c99!`](macro@include_c99) and [`c90!`](macro@c90).
/// Compiles the C99 file at `path` — one translation unit, exactly as if its
/// text had been written inside [`c99!`](macro@c99).
///
/// ```ignore
/// cinrs::include_c99!("vendor/parser.c");
/// ```
///
/// The file is read at expansion time and translated with the same front end:
/// every C construct is accepted (the file is text, so the lexemes Rust's own
/// lexer refuses are no trouble), `#pragma cinrs …` inside it configures the
/// unit, `#include "…"` in it searches the file's own directory first, and the
/// expansion is a module plus a glob re-export like any other invocation's.
/// `__FILE__` and `__LINE__` name the `.c` file and its own lines.
///
/// A **relative path is resolved against the directory of the `.rs` file the
/// macro is written in** — the same rule `#include "…"` follows — and an
/// absolute one is used as it stands. The file is named with `include_str!` in
/// the expansion, so editing it rebuilds the crate.
///
/// **Diagnostics land on the invocation.** There is no C in the `.rs` file for
/// a caret to point at, so a message of this crate's carries the position
/// inside the file — `vendor/parser.c:12:5: unknown type name 'foo'` — and an
/// error `rustc` raises about the generated code is reported at the macro call.
/// Neither `cargo` nor an IDE will jump into the `.c` file; the position is in
/// the text of the message.
///
/// There is one of these per entry point: `include_c89!`, `include_c90!`,
/// `include_c11!`, `include_c17!`, `include_c23!` and the five `include_gnu…!`
/// forms.
/// Compiles the C11 file at `path`; see
/// [`include_c99!`](macro@include_c99) and [`c11!`](macro@c11).
/// Compiles the C17 file at `path`; see
/// [`include_c99!`](macro@include_c99) and [`c17!`](macro@c17).
/// Compiles the C23 file at `path`; see
/// [`include_c99!`](macro@include_c99) and [`c23!`](macro@c23).
/// Compiles the C89 file at `path` with the GNU extensions switched on; see
/// [`include_c99!`](macro@include_c99) and [`gnu89!`](macro@gnu89).
/// Compiles the C99 file at `path` with the GNU extensions switched on; see
/// [`include_c99!`](macro@include_c99) and [`gnu99!`](macro@gnu99).
/// Compiles the C11 file at `path` with the GNU extensions switched on; see
/// [`include_c99!`](macro@include_c99) and [`gnu11!`](macro@gnu11).
/// Compiles the C17 file at `path` with the GNU extensions switched on; see
/// [`include_c99!`](macro@include_c99) and [`gnu17!`](macro@gnu17).
/// Compiles the C23 file at `path` with the GNU extensions switched on; see
/// [`include_c99!`](macro@include_c99) and [`gnu23!`](macro@gnu23).
/// The body every strict entry point shares.
/// The body every GNU entry point shares.
/// The body every `include_…!` entry point shares.
///
/// No [`Subspan`] hook: the C is in a file of its own, and there is nothing in
/// the `.rs` for a span to point into.
/// A hook resolving a byte range of a string-literal body into a span.
///
/// There is one only when the whole input is a single literal, which is what
/// string-literal mode is; everything else already has a span per token.
/// Without the `nightly` feature there is nothing to hook up, and
/// string-literal input keeps reporting positions in the message text.