1 /*
2 **      cdecl -- C gibberish translator
3 **      src/c_type.c
4 **
5 **      Copyright (C) 2017-2021  Paul J. Lucas
6 **
7 **      This program is free software: you can redistribute it and/or modify
8 **      it under the terms of the GNU General Public License as published by
9 **      the Free Software Foundation, either version 3 of the License, or
10 **      (at your option) any later version.
11 **
12 **      This program is distributed in the hope that it will be useful,
13 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
14 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 **      GNU General Public License for more details.
16 **
17 **      You should have received a copy of the GNU General Public License
18 **      along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 /**
22  * @file
23  * Defines functions for C/C++ types.
24  */
25 
26 // local
27 #include "pjl_config.h"                 /* must go first */
28 /// @cond DOXYGEN_IGNORE
29 #define C_TYPE_INLINE _GL_EXTERN_INLINE
30 /// @endcond
31 #include "c_type.h"
32 #include "c_lang.h"
33 #include "cdecl.h"
34 #include "gibberish.h"
35 #include "literals.h"
36 #include "options.h"
37 #include "print.h"
38 #include "strbuf.h"
39 #include "util.h"
40 
41 /// @cond DOXYGEN_IGNORE
42 
43 // standard
44 #include <assert.h>
45 #include <stdlib.h>
46 #include <string.h>
47 
48 #define C_TYPE_CHECK(...) BLOCK(            \
49   c_lang_id_t const lang_ids = __VA_ARGS__; \
50   if ( lang_ids != LANG_ANY )               \
51     return lang_ids; )
52 
53 #define C_TID_CHECK_COMBO(TID,TINFO,OK_TYPE_LANGS) C_TYPE_CHECK( \
54   c_tid_check_combo( (TID), (TINFO), ARRAY_SIZE(TINFO), (OK_TYPE_LANGS) ) )
55 
56 #define C_TID_CHECK_LEGAL(TID,TINFO) C_TYPE_CHECK( \
57   c_tid_check_legal( (TID), (TINFO), ARRAY_SIZE(TINFO) ) )
58 
59 #define C_TID_NAME_CAT(SBUF,TIDS,TIDS_SET,IN_ENGLISH,SEP,PSEP)      \
60   c_tid_name_cat( (SBUF), (TIDS), (TIDS_SET), ARRAY_SIZE(TIDS_SET), \
61                   (IN_ENGLISH), (SEP), (PSEP) )
62 
63 /// @endcond
64 
65 c_type_t const T_NONE             = { TB_NONE,      TS_NONE,    TA_NONE };
66 c_type_t const T_ANY              = { TB_ANY,       TS_ANY,     TA_ANY  };
67 c_type_t const T_ANY_CONST_CLASS  = { TB_ANY_CLASS, TS_CONST,   TA_NONE };
68 c_type_t const T_TS_TYPEDEF       = { TB_NONE,      TS_TYPEDEF, TA_NONE };
69 
70 ///////////////////////////////////////////////////////////////////////////////
71 
72 /**
73  * Mapping between C type bits, valid language(s), and literals.
74  */
75 struct c_type_info {
76   c_tid_t             tid;              ///< The type.
77   c_lang_id_t         lang_ids;         ///< Language(s) OK in.
78   char const         *english_lit;      ///< English version (if not NULL).
79 
80   /**
81    * Array of language(s)/literal pair(s).  The array is terminated by an
82    * element that has #LANG_ANY for lang_ids; hence subset(s) of language(s)
83    * cases come first and, failing to match opt_lang against any of those,
84    * matches the last (default) element.
85    */
86   c_lang_lit_t const *lang_lit;
87 };
88 typedef struct c_type_info c_type_info_t;
89 
90 // local functions
91 PJL_WARN_UNUSED_RESULT
92 static char const*  c_type_literal( c_type_info_t const*, bool );
93 
94 ///////////////////////////////////////////////////////////////////////////////
95 
96 /**
97  * As part of the special case for `long long`, its literal is only `long`
98  * because its type, #TB_LONG_LONG, is always combined with #TB_LONG, i.e., two
99  * bits are set.  Therefore, when printed, it prints one `long` for #TB_LONG
100  * and another `long` for #TB_LONG_LONG (this literal).  That explains why this
101  * literal is only one `long`.
102  */
103 static char const L_LONG_LONG[] = "long";
104 
105 /**
106  * For convenience, this is just a concatenation of `L_RVALUE` and
107  * `L_REFERENCE`.
108  */
109 static char const L_RVALUE_REFERENCE[] = "rvalue reference";
110 
111 /**
112  * #TB_TYPEDEF exists only so there can be a row/column for it in the \ref
113  * OK_TYPE_LANGS table to make things like `signed size_t` illegal.
114  *
115  * #TB_TYPEDEF doesn't have any printable representation (only the name of the
116  * type is printed); therefore, its literal is the empty string.
117  */
118 static char const L_TYPEDEF_TYPE[] = "";
119 
120 /**
121  * Type mapping for attributes.
122  */
123 static c_type_info_t const C_ATTRIBUTE_INFO[] = {
124   { TA_CARRIES_DEPENDENCY, LANG_CPP_MIN(11), "carries dependency",
125     C_LANG_LIT( { LANG_ANY, L_CARRIES_DEPENDENCY } ) },
126 
127   { TA_DEPRECATED, LANG_C_CPP_MIN(2X,11), NULL,
128     C_LANG_LIT( { LANG_ANY, L_DEPRECATED } ) },
129 
130   { TA_MAYBE_UNUSED, LANG_C_CPP_MIN(2X,17), "maybe unused",
131     C_LANG_LIT( { LANG_ANY, L_MAYBE_UNUSED } ) },
132 
133   { TA_NODISCARD, LANG_C_CPP_MIN(2X,17), H_NON_DISCARDABLE,
134     C_LANG_LIT( { LANG_ANY, L_NODISCARD } ) },
135 
136   { TA_NORETURN, LANG_C_CPP_MIN(11,11), H_NON_RETURNING,
137     C_LANG_LIT( { LANG_C_ANY, L__NORETURN },
138                 { LANG_ANY,   L_NORETURN  } ) },
139 
140   { TA_NO_UNIQUE_ADDRESS, LANG_CPP_MIN(20), H_NON_UNIQUE_ADDRESS,
141     C_LANG_LIT( { LANG_ANY, L_NO_UNIQUE_ADDRESS } ) },
142 
143   // Microsoft extensions
144   { TA_MSC_CDECL, LANG_MIN(C_89), L_MSC_CDECL,
145     C_LANG_LIT( { LANG_ANY, L_MSC___CDECL } ) },
146 
147   { TA_MSC_CLRCALL, LANG_MIN(C_89), L_MSC_CLRCALL,
148     C_LANG_LIT( { LANG_ANY, L_MSC___CLRCALL } ) },
149 
150   { TA_MSC_FASTCALL, LANG_MIN(C_89), L_MSC_FASTCALL,
151     C_LANG_LIT( { LANG_ANY, L_MSC___FASTCALL } ) },
152 
153   { TA_MSC_STDCALL, LANG_MIN(C_89), L_MSC_STDCALL,
154     C_LANG_LIT( { LANG_ANY, L_MSC___STDCALL } ) },
155 
156   { TA_MSC_THISCALL, LANG_MIN(C_89), L_MSC_THISCALL,
157     C_LANG_LIT( { LANG_ANY, L_MSC___THISCALL } ) },
158 
159   { TA_MSC_VECTORCALL, LANG_MIN(C_89), L_MSC_VECTORCALL,
160     C_LANG_LIT( { LANG_ANY, L_MSC___VECTORCALL } ) },
161 };
162 
163 /**
164  * Type mapping for qualifiers.
165  *
166  * @note
167  * This array _must_ have the same size and order as OK_QUALIFIER_LANGS.
168  */
169 static c_type_info_t const C_QUALIFIER_INFO[] = {
170   { TS_ATOMIC, LANG_C_CPP_MIN(11,23), L_ATOMIC,
171     C_LANG_LIT( { LANG_ANY, L__ATOMIC } ) },
172 
173   { TS_CONST, LANG_ANY, L_CONSTANT,
174     C_LANG_LIT( { LANG_C_KNR, L_GNU___CONST },
175                 { LANG_ANY,   L_CONST       } ) },
176 
177   { TS_REFERENCE, LANG_CPP_MIN(11), NULL,
178     C_LANG_LIT( { LANG_ANY, L_REFERENCE } ) },
179 
180   { TS_RVALUE_REFERENCE, LANG_CPP_MIN(11), NULL,
181     C_LANG_LIT( { LANG_ANY, L_RVALUE_REFERENCE } ) },
182 
183   { TS_RESTRICT, LANG_ANY, L_RESTRICTED,
184     C_LANG_LIT( { LANG_C_MAX(95) | LANG_CPP_ANY, L_GNU___RESTRICT },
185                 { LANG_ANY,                      L_RESTRICT       } ) },
186 
187   { TS_VOLATILE, LANG_ANY, NULL,
188     C_LANG_LIT( { LANG_C_KNR, L_GNU___VOLATILE },
189                 { LANG_ANY,   L_VOLATILE       } ) },
190 
191   // Unified Parallel C extensions
192   { TS_UPC_RELAXED, LANG_C_99, NULL,
193     C_LANG_LIT( { LANG_ANY, L_UPC_RELAXED } ) },
194 
195   { TS_UPC_SHARED, LANG_C_99, NULL,
196     C_LANG_LIT( { LANG_ANY, L_UPC_SHARED } ) },
197 
198   { TS_UPC_STRICT, LANG_C_99, NULL,
199     C_LANG_LIT( { LANG_ANY, L_UPC_STRICT } ) },
200 };
201 
202 /**
203  * Type mapping for storage classes (or storage-class-like).
204  *
205  * @note
206  * This array _must_ have the same size and order as OK_STORAGE_LANGS.
207  */
208 static c_type_info_t const C_STORAGE_INFO[] = {
209   // storage classes
210   { TS_AUTO, LANG_MAX(CPP_03), L_AUTOMATIC,
211     C_LANG_LIT( { LANG_ANY, L_AUTO } ) },
212 
213   { TS_APPLE_BLOCK, LANG_ANY, NULL,
214     C_LANG_LIT( { LANG_ANY, L_APPLE___BLOCK } ) },
215 
216   { TS_EXTERN, LANG_ANY, L_EXTERNAL,
217     C_LANG_LIT( { LANG_ANY, L_EXTERN } ) },
218 
219   { TS_EXTERN_C, LANG_CPP_ANY, "external \"C\" linkage",
220     C_LANG_LIT( { LANG_ANY, "extern \"C\"" } ) },
221 
222   { TS_REGISTER, LANG_MAX(CPP_14), NULL,
223     C_LANG_LIT( { LANG_ANY, L_REGISTER } ) },
224 
225   { TS_STATIC, LANG_ANY, NULL,
226     C_LANG_LIT( { LANG_ANY, L_STATIC } ) },
227 
228   { TS_THREAD_LOCAL, LANG_ANY, "thread local",
229     C_LANG_LIT( { LANG_C_MAX(99) | LANG_CPP_MAX(03),  L_GNU___THREAD  },
230                 { LANG_C_MIN(11),                     L__THREAD_LOCAL },
231                 { LANG_ANY,                           L_THREAD_LOCAL  } ) },
232 
233   { TS_TYPEDEF, LANG_ANY, L_TYPE,
234     C_LANG_LIT( { LANG_ANY, L_TYPEDEF } ) },
235 
236   // storage-class-like
237   { TS_CONSTEVAL, LANG_CPP_MIN(20), "constant evaluation",
238     C_LANG_LIT( { LANG_ANY, L_CONSTEVAL } ) },
239 
240   { TS_CONSTEXPR, LANG_CPP_MIN(11), "constant expression",
241     C_LANG_LIT( { LANG_ANY, L_CONSTEXPR } ) },
242 
243   { TS_CONSTINIT, LANG_CPP_MIN(20), "constant initialization",
244     C_LANG_LIT( { LANG_ANY, L_CONSTINIT } ) },
245 
246   { TS_DEFAULT, LANG_CPP_MIN(11), NULL,
247     C_LANG_LIT( { LANG_ANY, L_DEFAULT } ) },
248 
249   { TS_DELETE, LANG_CPP_MIN(11), L_DELETED,
250     C_LANG_LIT( { LANG_ANY, L_DELETE } ) },
251 
252   { TS_EXPLICIT, LANG_CPP_ANY, NULL,
253     C_LANG_LIT( { LANG_ANY, L_EXPLICIT } ) },
254 
255   { TS_EXPORT, LANG_CPP_MIN(20), L_EXPORTED,
256     C_LANG_LIT( { LANG_ANY, L_EXPORT } ) },
257 
258   { TS_FINAL, LANG_CPP_MIN(11), NULL,
259     C_LANG_LIT( { LANG_ANY, L_FINAL } ) },
260 
261   { TS_FRIEND, LANG_CPP_ANY, NULL,
262     C_LANG_LIT( { LANG_ANY, L_FRIEND } ) },
263 
264   { TS_INLINE, LANG_ANY, NULL,
265     C_LANG_LIT( { LANG_C_KNR, L_GNU___INLINE },
266                 { LANG_ANY,   L_INLINE       } ) },
267 
268   { TS_MUTABLE, LANG_CPP_ANY, NULL,
269     C_LANG_LIT( { LANG_ANY, L_MUTABLE } ) },
270 
271   { TS_NOEXCEPT, LANG_CPP_MIN(11), H_NO_EXCEPTION,
272     C_LANG_LIT( { LANG_ANY, L_NOEXCEPT } ) },
273 
274   { TS_OVERRIDE, LANG_CPP_MIN(11), L_OVERRIDDEN,
275     C_LANG_LIT( { LANG_ANY, L_OVERRIDE } ) },
276 
277   { TS_THROW, LANG_CPP_ANY, H_NON_THROWING,
278     C_LANG_LIT( { LANG_ANY, L_THROW } ) },
279 
280   { TS_VIRTUAL, LANG_CPP_ANY, NULL,
281     C_LANG_LIT( { LANG_ANY, L_VIRTUAL } ) },
282 
283   { TS_PURE_VIRTUAL, LANG_CPP_ANY, NULL,
284     C_LANG_LIT( { LANG_ANY, L_PURE } ) },
285 };
286 
287 /**
288  * Type mapping for simpler types.
289  *
290  * @note
291  * This array _must_ have the same size and order as OK_TYPE_LANGS.
292  */
293 static c_type_info_t const C_TYPE_INFO[] = {
294   { TB_VOID, LANG_MIN(C_89), NULL,
295     C_LANG_LIT( { LANG_ANY, L_VOID } ) },
296 
297   { TB_AUTO, LANG_MIN(C_89), L_AUTOMATIC,
298     C_LANG_LIT( { LANG_MAX(CPP_03), L_GNU___AUTO_TYPE },
299                 { LANG_ANY,         L_AUTO            } ) },
300 
301   { TB_BOOL, LANG_MIN(C_99), NULL,
302     C_LANG_LIT( { LANG_C_ANY, L__BOOL },
303                 { LANG_ANY,   L_BOOL  } ) },
304 
305   { TB_CHAR, LANG_ANY, NULL,
306     C_LANG_LIT( { LANG_ANY, L_CHAR } ) },
307 
308   { TB_CHAR8_T, LANG_C_CPP_MIN(2X,20), NULL,
309     C_LANG_LIT( { LANG_ANY, L_CHAR8_T } ) },
310 
311   { TB_CHAR16_T, LANG_C_CPP_MIN(11,11), NULL,
312     C_LANG_LIT( { LANG_ANY, L_CHAR16_T } ) },
313 
314   { TB_CHAR32_T, LANG_C_CPP_MIN(11,11), NULL,
315     C_LANG_LIT( { LANG_ANY, L_CHAR32_T } ) },
316 
317   { TB_WCHAR_T, LANG_MIN(C_95), NULL,
318     C_LANG_LIT( { LANG_ANY, L_WCHAR_T } ) },
319 
320   { TB_SHORT, LANG_ANY, NULL,
321     C_LANG_LIT( { LANG_ANY, L_SHORT } ) },
322 
323   { TB_INT, LANG_ANY, NULL,
324     C_LANG_LIT( { LANG_ANY, L_INT } ) },
325 
326   { TB_LONG, LANG_ANY, NULL,
327     C_LANG_LIT( { LANG_ANY, L_LONG } ) },
328 
329   { TB_LONG_LONG, LANG_MIN(C_99), NULL,
330     C_LANG_LIT( { LANG_ANY, L_LONG_LONG } ) },
331 
332   { TB_SIGNED, LANG_ANY, NULL,
333     C_LANG_LIT( { LANG_C_KNR, L_GNU___SIGNED },
334                 { LANG_ANY,   L_SIGNED       } ) },
335 
336   { TB_UNSIGNED, LANG_ANY, NULL,
337     C_LANG_LIT( { LANG_ANY, L_UNSIGNED } ) },
338 
339   { TB_FLOAT, LANG_ANY, NULL,
340     C_LANG_LIT( { LANG_ANY, L_FLOAT } ) },
341 
342   { TB_DOUBLE, LANG_ANY, NULL,
343     C_LANG_LIT( { LANG_ANY, L_DOUBLE } ) },
344 
345   { TB_COMPLEX, LANG_C_ANY, L_COMPLEX,
346     C_LANG_LIT( { LANG_C_MAX(95), L_GNU___COMPLEX },
347                 { LANG_ANY,       L__COMPLEX      } ) },
348 
349   { TB_IMAGINARY, LANG_C_MIN(99), L_IMAGINARY,
350     C_LANG_LIT( { LANG_ANY, L__IMAGINARY } ) },
351 
352   { TB_ENUM, LANG_MIN(C_89), L_ENUMERATION,
353     C_LANG_LIT( { LANG_ANY, L_ENUM } ) },
354 
355   { TB_STRUCT, LANG_ANY, L_STRUCTURE,
356     C_LANG_LIT( { LANG_ANY, L_STRUCT } ) },
357 
358   { TB_UNION, LANG_ANY, NULL,
359     C_LANG_LIT( { LANG_ANY, L_UNION } ) },
360 
361   { TB_CLASS, LANG_CPP_ANY, NULL,
362     C_LANG_LIT( { LANG_ANY, L_CLASS } ) },
363 
364   { TB_TYPEDEF, LANG_ANY, NULL,
365     C_LANG_LIT( { LANG_ANY, L_TYPEDEF_TYPE } ) },
366 
367   // Embedded C extensions
368   { TB_EMC_ACCUM, LANG_C_99, L_EMC_ACCUM,
369     C_LANG_LIT( { LANG_ANY, L_EMC__ACCUM } ) },
370 
371   { TB_EMC_FRACT, LANG_C_99, L_EMC_FRACT,
372     C_LANG_LIT( { LANG_ANY, L_EMC__FRACT } ) },
373 
374   { TB_EMC_SAT, LANG_C_99, L_EMC_SATURATED,
375     C_LANG_LIT( { LANG_ANY, L_EMC__SAT } ) },
376 };
377 
378 /// @cond DOXYGEN_IGNORE
379 
380 //      shorthand   legal in ...
381 #define __          LANG_ANY
382 #define XX          LANG_NONE
383 #define KR          LANG_C_KNR
384 #define C8          LANG_MIN(C_89)
385 #define C5          LANG_MIN(C_95)
386 #define c9          LANG_C_99
387 #define C9          LANG_MIN(C_99)
388 #define C1          LANG_MIN(C_11)
389 #define PP          LANG_CPP_ANY
390 #define P3          LANG_CPP_MIN(03)
391 #define P1          LANG_CPP_MIN(11)
392 #define P2          LANG_CPP_MIN(20)
393 #define E1          LANG_C_CPP_MIN(11,11)
394 #define E2          LANG_C_CPP_MIN(2X,20)
395 #define E3          LANG_C_CPP_MIN(11,23)
396 
397 /// @endcond
398 
399 // There is no OK_ATTRIBUTE_LANGS because all combinations of attributes are
400 // legal.
401 
402 /**
403  * Legal combinations of qualifiers in languages.
404  *
405  * @note
406  * This array _must_ have the same size and order as C_QUALIFIER_INFO.
407  */
408 static c_lang_id_t const OK_QUALIFIER_LANGS[][ ARRAY_SIZE( C_QUALIFIER_INFO ) ] = {
409 // Only the lower triangle is used.
410 //  a  c  r  rr re v    rx sh st
411   { E3,__,__,__,__,__,  __,__,__ }, // atomic
412   { E1,__,__,__,__,__,  __,__,__ }, // const
413   { XX,PP,PP,__,__,__,  __,__,__ }, // reference
414   { XX,P1,XX,P1,__,__,  __,__,__ }, // rvalue reference
415   { XX,__,PP,P1,__,__,  __,__,__ }, // restrict
416   { E1,__,PP,P1,__,__,  __,__,__ }, // volatile
417 
418   // Unified Parallel C extensions
419   { XX,c9,XX,XX,c9,c9,  c9,__,__ }, // relaxed
420   { XX,c9,XX,XX,c9,c9,  c9,c9,__ }, // shared
421   { XX,c9,XX,XX,c9,c9,  XX,c9,c9 }, // strict
422 };
423 
424 /**
425  * Legal combinations of storage classes in languages.
426  *
427  * @note
428  * This array _must_ have the same size and order as C_STORAGE_INFO.
429  */
430 static c_lang_id_t const OK_STORAGE_LANGS[][ ARRAY_SIZE( C_STORAGE_INFO ) ] = {
431 // Only the lower triangle is used.
432 //  a  b  e  ec,r  s  th td   cv cx ci df de ex ep fi fr in mu ne o  t  v  pv
433   { __,__,__,__,__,__,__,__,  __,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// auto
434   { __,__,__,__,__,__,__,__,  __,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// block
435   { XX,__,__,__,__,__,__,__,  __,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// extern
436   { XX,__,__,PP,__,__,__,__,  __,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// extern C
437   { XX,__,XX,XX,__,__,__,__,  __,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// register
438   { XX,XX,XX,XX,XX,__,__,__,  __,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// static
439   { XX,__,__,P1,XX,__,__,__,  __,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// thread
440   { XX,__,XX,PP,XX,XX,XX,__,  __,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// typedef
441 
442   { P1,P1,P1,P2,XX,P1,XX,XX,  P2,P1,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// c'eval
443   { P1,P1,P1,P1,XX,P1,XX,XX,  XX,P1,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// c'expr
444   { XX,XX,P2,P2,XX,P2,P2,XX,  XX,XX,P2,__,__,__,__,__,__,__,__,__,__,__,__,__ },// c'init
445   { XX,XX,XX,XX,XX,XX,XX,XX,  P1,P1,XX,P1,__,__,__,__,__,__,__,__,__,__,__,__ },// default
446   { XX,XX,XX,XX,XX,XX,XX,XX,  P1,P1,XX,XX,P1,__,__,__,__,__,__,__,__,__,__,__ },// delete
447   { XX,XX,XX,XX,XX,XX,XX,XX,  XX,P1,XX,P1,P1,PP,__,__,__,__,__,__,__,__,__,__ },// explicit
448   { XX,XX,P2,XX,XX,XX,XX,XX,  XX,P2,P2,XX,XX,XX,P2,__,__,__,__,__,__,__,__,__ },// export
449   { XX,XX,XX,XX,XX,XX,XX,XX,  XX,P1,XX,XX,XX,XX,XX,P1,__,__,__,__,__,__,__,__ },// final
450   { XX,XX,XX,XX,XX,XX,XX,XX,  P2,P1,XX,P2,XX,XX,XX,XX,PP,__,__,__,__,__,__,__ },// friend
451   { XX,XX,__,PP,XX,__,XX,XX,  P2,P1,P2,P1,P1,PP,P2,P1,PP,C9,__,__,__,__,__,__ },// inline
452   { XX,XX,XX,XX,XX,XX,XX,XX,  XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,P3,__,__,__,__,__ },// mutable
453   { XX,XX,P1,PP,XX,P1,XX,P1,  P2,P1,XX,P1,P1,PP,P2,P1,P1,P1,XX,P1,__,__,__,__ },// noexcept
454   { XX,XX,XX,XX,XX,XX,XX,XX,  XX,P1,XX,XX,XX,XX,XX,P1,XX,C1,XX,C1,P1,__,__,__ },// override
455   { XX,XX,PP,PP,XX,PP,XX,PP,  P2,P1,XX,P1,P1,PP,XX,PP,XX,PP,XX,XX,PP,PP,__,__ },// throw
456   { XX,XX,XX,XX,XX,XX,XX,XX,  XX,P2,XX,XX,XX,XX,XX,P1,XX,PP,XX,C1,P1,PP,PP,__ },// virtual
457   { XX,XX,XX,XX,XX,XX,XX,XX,  XX,P2,XX,XX,XX,XX,XX,XX,XX,PP,XX,C1,P1,PP,PP,PP },// pure
458 };
459 
460 /**
461  * Legal combinations of types in languages.
462  *
463  * @note
464  * This array _must_ have the same size and order as C_TYPE_INFO.
465  */
466 static c_lang_id_t const OK_TYPE_LANGS[][ ARRAY_SIZE( C_TYPE_INFO ) ] = {
467 // Only the lower triangle is used.
468 //  v  a1 b  c  8  16 32 wc s  i  l  ll s  u  f  d  co im e  st un cl t  ac fr sa
469   { C8,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// void
470   { XX,C8,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// auto
471   { XX,XX,C9,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// bool
472   { XX,XX,XX,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// char
473   { XX,XX,XX,XX,E2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// char8_t
474   { XX,XX,XX,XX,XX,E1,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// char16_t
475   { XX,XX,XX,XX,XX,XX,E1,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// char32_t
476   { XX,XX,XX,XX,XX,XX,XX,C5,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// wchar_t
477   { XX,XX,XX,XX,XX,XX,XX,XX,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// short
478   { XX,XX,XX,XX,XX,XX,XX,XX,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// int
479   { XX,XX,XX,XX,XX,XX,XX,XX,XX,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// long
480   { XX,XX,XX,XX,XX,XX,XX,XX,XX,C9,__,C9,__,__,__,__,__,__,__,__,__,__,__,__,__,__ },// long long
481   { XX,XX,XX,C8,XX,XX,XX,XX,C8,C8,C8,C8,C8,__,__,__,__,__,__,__,__,__,__,__,__,__ },// signed
482   { XX,XX,XX,__,XX,XX,XX,XX,__,__,__,C8,XX,__,__,__,__,__,__,__,__,__,__,__,__,__ },// unsigned
483   { XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,KR,XX,XX,XX,__,__,__,__,__,__,__,__,__,__,__,__ },// float
484   { XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,C8,XX,XX,XX,XX,__,__,__,__,__,__,__,__,__,__,__ },// double
485   { XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,C9,C9,C9,__,__,__,__,__,__,__,__,__ },// complex
486   { XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,C9,C9,XX,C9,__,__,__,__,__,__,__,__ },// imaginary
487   { XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,C8,__,__,__,__,__,__,__ },// enum
488   { XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,P1,__,__,__,__,__,__,__ },// struct
489   { XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,__,__,__,__,__,__ },// union
490   { XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,P1,XX,XX,PP,__,__,__,__ },// class
491   { XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,__,__,__,__ },// typedef
492   { XX,XX,XX,XX,XX,XX,XX,XX,C9,XX,C9,XX,C9,C9,XX,XX,XX,XX,XX,XX,XX,XX,XX,C9,__,__ },// _Accum
493   { XX,XX,XX,XX,XX,XX,XX,XX,C9,XX,C9,XX,C9,C9,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,C9,__ },// _Fract
494   { XX,XX,XX,XX,XX,XX,XX,XX,C9,XX,C9,XX,C9,C9,XX,XX,XX,XX,XX,XX,XX,XX,XX,C9,C9,C9 },// _Sat
495 };
496 
497 ////////// inline functions ///////////////////////////////////////////////////
498 
499 /**
500  * Checks whether \a tids is some form of `long int` only, and _not_ one of
501  * `long float` (K&R), `long double` (C89), or either `long _Accum` or `long
502  * _Fract` (Embedded C).
503  *
504  * @param tids The \ref c_tid_t to check.
505  * @return Returns `true` only if \a tids is some form of `long int`.
506  */
507 PJL_WARN_UNUSED_RESULT
c_tid_is_long_int(c_tid_t tids)508 static inline bool c_tid_is_long_int( c_tid_t tids ) {
509   return  c_tid_tpid( tids ) == C_TPID_BASE &&
510           c_tid_is_except( tids, TB_LONG, TB_ANY_FLOAT | TB_ANY_EMC );
511 }
512 
513 ////////// local functions ////////////////////////////////////////////////////
514 
515 /**
516  * Checks that the type combination is legal in the current language.
517  *
518  * @param tids The \ref c_tid_t to check.
519  * @param type_infos The array of \ref c_type_info to check against.
520  * @param type_infos_size The size of \a type_infos.
521  * @param type_langs The type/languages array to check against.
522  * @return Returns the bitwise-or of the language(s) \a tids is legal in.
523  */
524 PJL_WARN_UNUSED_RESULT
525 static c_lang_id_t
c_tid_check_combo(c_tid_t tids,c_type_info_t const type_infos[],size_t type_infos_size,c_lang_id_t const type_langs[][type_infos_size])526 c_tid_check_combo( c_tid_t tids, c_type_info_t const type_infos[],
527                    size_t type_infos_size,
528                    c_lang_id_t const type_langs[][type_infos_size] ) {
529   for ( size_t row = 0; row < type_infos_size; ++row ) {
530     if ( !c_tid_is_none( tids & type_infos[ row ].tid ) ) {
531       for ( size_t col = 0; col <= row; ++col ) {
532         c_lang_id_t const lang_ids = type_langs[ row ][ col ];
533         if ( !c_tid_is_none( tids & type_infos[ col ].tid ) &&
534              !opt_lang_is_any( lang_ids ) ) {
535           return lang_ids;
536         }
537       } // for
538     }
539   } // for
540   return LANG_ANY;
541 }
542 
543 /**
544  * Checks that \a tids is legal in the current language.
545  *
546  * @param tids The \ref c_tid_t to check.
547  * @param type_infos The array of \ref c_type_info to check against.
548  * @param type_infos_size The size of \a type_infos.
549  * @return Returns the bitwise-or of the language(s) \a tids is legal in.
550  */
551 PJL_WARN_UNUSED_RESULT
552 static c_lang_id_t
c_tid_check_legal(c_tid_t tids,c_type_info_t const type_infos[],size_t type_infos_size)553 c_tid_check_legal( c_tid_t tids, c_type_info_t const type_infos[],
554                    size_t type_infos_size ) {
555   for ( size_t row = 0; row < type_infos_size; ++row ) {
556     c_type_info_t const *const ti = &type_infos[ row ];
557     if ( !c_tid_is_none( tids & ti->tid ) && !opt_lang_is_any( ti->lang_ids ) )
558       return ti->lang_ids;
559   } // for
560   return LANG_ANY;
561 }
562 
563 /**
564  * Gets the name of an individual type.
565  *
566  * @param tid The \ref c_tid_t to get the name for; \a tid _must_ have _exactly
567  * one_ bit set.
568  * @param in_english If `true`, return the pseudo-English literal if one
569  * exists.
570  * @return Returns said name.
571  */
572 PJL_WARN_UNUSED_RESULT
c_tid_name_1(c_tid_t tid,bool in_english)573 static char const* c_tid_name_1( c_tid_t tid, bool in_english ) {
574   assert( exactly_one_bit_set( c_tid_no_tpid( tid ) ) );
575 
576   switch ( c_tid_tpid( tid ) ) {
577     case C_TPID_NONE:
578       break;                            // LCOV_EXCL_LINE
579 
580     case C_TPID_BASE:
581       for ( size_t i = 0; i < ARRAY_SIZE( C_TYPE_INFO ); ++i ) {
582         c_type_info_t const *const ti = &C_TYPE_INFO[i];
583         if ( tid == ti->tid )
584           return c_type_literal( ti, in_english );
585       } // for
586       break;                            // LCOV_EXCL_LINE
587 
588     case C_TPID_STORE:
589       for ( size_t i = 0; i < ARRAY_SIZE( C_QUALIFIER_INFO ); ++i ) {
590         c_type_info_t const *const ti = &C_QUALIFIER_INFO[i];
591         if ( tid == ti->tid )
592           return c_type_literal( ti, in_english );
593       } // for
594 
595       for ( size_t i = 0; i < ARRAY_SIZE( C_STORAGE_INFO ); ++i ) {
596         c_type_info_t const *const ti = &C_STORAGE_INFO[i];
597         if ( tid == ti->tid )
598           return c_type_literal( ti, in_english );
599       } // for
600       break;                            // LCOV_EXCL_LINE
601 
602     case C_TPID_ATTR:
603       for ( size_t i = 0; i < ARRAY_SIZE( C_ATTRIBUTE_INFO ); ++i ) {
604         c_type_info_t const *const ti = &C_ATTRIBUTE_INFO[i];
605         if ( tid == ti->tid )
606           return c_type_literal( ti, in_english );
607       } // for
608       break;                            // LCOV_EXCL_LINE
609   } // switch
610 
611   UNEXPECTED_INT_VALUE( tid );
612 }
613 
614 /**
615  * Concatenates the partial type name onto the full type name being made.
616  *
617  * @param sbuf A pointer to the buffer to concatenate the name to.
618  * @param tids The \ref c_tid_t to concatenate the name of.
619  * @param tids_set The array of types to use.
620  * @param tids_set_size The size of \a tids_set.
621  * @param in_english If `true`, return the pseudo-English literal if one
622  * exists.
623  * @param sep The separator character.
624  * @param sep_flag A pointer to a variable to keep track of whether \a sep has
625  * been concatenated.
626  */
c_tid_name_cat(strbuf_t * sbuf,c_tid_t tids,c_tid_t const tids_set[],size_t tids_set_size,bool in_english,char sep,bool * sep_flag)627 static void c_tid_name_cat( strbuf_t *sbuf, c_tid_t tids,
628                             c_tid_t const tids_set[], size_t tids_set_size,
629                             bool in_english, char sep, bool *sep_flag ) {
630   for ( size_t i = 0; i < tids_set_size; ++i ) {
631     if ( !c_tid_is_none( tids & tids_set[i] ) ) {
632       char const *const name = c_tid_name_1( tids_set[i], in_english );
633       strbuf_sepc_puts( sbuf, sep, sep_flag, name );
634     }
635   } // for
636 }
637 
638 /**
639  * "Simplifies" a base \ref c_tid_t.  Specifically:
640  *
641  * + If \a btids is #TB_SIGNED and not #TB_CHAR, remove #TB_SIGNED.
642  * + If \a btids becomes #TB_NONE, make it #TB_INT.
643  *
644  * @param btids The \ref c_tid_t to simplify.
645  * @return Returns the simplified \ref c_tid_t.
646  */
647 PJL_WARN_UNUSED_RESULT
c_tid_simplify(c_tid_t btids)648 static c_tid_t c_tid_simplify( c_tid_t btids ) {
649   assert( c_tid_tpid( btids ) == C_TPID_BASE );
650   if ( c_tid_is_except( btids, TB_SIGNED, TB_CHAR ) ) {
651     btids &= c_tid_compl( TB_SIGNED );
652     if ( btids == TB_NONE )
653       btids = TB_INT;
654   }
655   return btids;
656 }
657 
658 /**
659  * Gets the literal of a given \ref c_type_info, either gibberish or, if
660  * appropriate and available, pseudo-English.
661  *
662  * @param ti The \ref c_type_info to get the literal of.
663  * @param in_english If `true`, return the pseudo-English literal if one
664  * exists.
665  * @return Returns said literal.
666  */
667 PJL_WARN_UNUSED_RESULT
c_type_literal(c_type_info_t const * ti,bool in_english)668 static char const* c_type_literal( c_type_info_t const *ti, bool in_english ) {
669   return in_english && ti->english_lit != NULL ?
670     ti->english_lit : c_lang_literal( ti->lang_lit );
671 }
672 
673 /**
674  * Gets the name of \a type.
675  *
676  * @param type The type to get the name for.
677  * @param apply_explicit_ecsu If `true`, apply \ref opt_explicit_ecsu.
678  * @param in_english If `true`, return the pseudo-English name if possible.
679  * @param is_error If `true`, the name is intended for use in an error message.
680  * Specifically, c_tid_normalize() is _not_ called.
681  * @return Returns said name.
682  *
683  * @warning The pointer returned is to a small number of static buffers, so you
684  * can't do something like call this more than twice in the same `printf()`
685  * statement.
686  *
687  * @sa c_tid_normalize()
688  * @sa c_type_name_c()
689  * @sa c_type_name_ecsu()
690  * @sa c_type_name_english()
691  * @sa c_type_name_error()
692  */
693 PJL_WARN_UNUSED_RESULT
c_type_name_impl(c_type_t const * type,bool apply_explicit_ecsu,bool in_english,bool is_error)694 static char const* c_type_name_impl( c_type_t const *type,
695                                      bool apply_explicit_ecsu, bool in_english,
696                                      bool is_error ) {
697   static strbuf_t sbufs[ 2 ];
698   static unsigned buf_index;
699 
700   strbuf_t *const sbuf = &sbufs[ buf_index++ % ARRAY_SIZE( sbufs ) ];
701   strbuf_reset( sbuf );
702   bool space = false;
703 
704   c_tid_t btids = is_error ? type->btids : c_tid_simplify( type->btids );
705   c_tid_t stids = type->stids;
706   c_tid_t atids = type->atids;
707 
708   if ( OPT_LANG_IS(C_ANY) && c_tid_is_any( atids, TA_NORETURN ) ) {
709     //
710     // Special case: we store _Noreturn as an attribute, but in C, it's a
711     // distinct keyword and printed as such instead being printed between
712     // brackets [[like this]].
713     //
714     static c_tid_t const ATIDS[] = { TA_NORETURN };
715     C_TID_NAME_CAT( sbuf, TA_NORETURN, ATIDS, in_english, ' ', &space );
716     //
717     // Now that we've handled _Noreturn for C, remove its bit and fall through
718     // to the regular attribute-printing code.
719     //
720     atids &= c_tid_compl( TA_NORETURN );
721   }
722 
723   if ( c_tid_is_any( atids, c_tid_compl( TA_ANY_MSC_CALL ) ) ) {
724     static c_tid_t const ATIDS[] = {
725       TA_CARRIES_DEPENDENCY,
726       TA_DEPRECATED,
727       TA_MAYBE_UNUSED,
728       TA_NODISCARD,
729       TA_NORETURN,                      // still here for C++'s [[noreturn]]
730       TA_NO_UNIQUE_ADDRESS,
731     };
732     // Microsoft calling conventions must be handled later -- see below.
733 
734     bool const print_brackets =
735       OPT_LANG_IS(MIN(C_2X)) &&
736       cdecl_mode == CDECL_ENGLISH_TO_GIBBERISH && !in_english;
737 
738     bool comma = false;
739     char const sep = print_brackets ? ',' : ' ';
740     bool *const sep_cat = print_brackets ? &comma : &space;
741 
742     if ( print_brackets )
743       strbuf_sepc_puts( sbuf, ' ', &space, graph_token_c( "[[" ) );
744     C_TID_NAME_CAT( sbuf, atids, ATIDS, in_english, sep, sep_cat );
745     if ( print_brackets )
746       strbuf_puts( sbuf, graph_token_c( "]]" ) );
747     space = true;
748   }
749 
750   // Special cases.
751   if ( in_english ) {
752     if ( c_tid_is_any( btids, TB_ANY_MODIFIER ) &&
753         !c_tid_is_any( btids, c_tid_compl( TB_ANY_MODIFIER ) ) ) {
754       // In English, be explicit about "int".
755       btids |= TB_INT;
756     }
757     if ( c_tid_is_any( stids, TS_FINAL | TS_OVERRIDE ) ) {
758       // In English, either "final" or "overrride" implies "virtual".
759       stids |= TS_VIRTUAL;
760     }
761   }
762   else /* !in_english */ {
763     //
764     // In C++, at most one of "virtual", "override", or "final" should be
765     // printed.  The type is massaged in g_print_ast() since "virtual" prints
766     // before the function signature and either "override" or "final" prints
767     // after.  Hence, by the time we get here, at most one bit should be set.
768     //
769     assert(
770       at_most_one_bit_set(
771         c_tid_no_tpid( stids & (TS_VIRTUAL | TS_OVERRIDE | TS_FINAL) )
772       )
773     );
774 
775     if ( is_explicit_int( btids ) ) {
776       btids |= TB_INT;
777     } else if ( c_tid_is_any( btids, TB_ANY_MODIFIER ) ) {
778       // In C/C++, explicit "int" isn't needed when at least one int modifier
779       // is present.
780       btids &= c_tid_compl( TB_INT );
781     }
782   }
783 
784   // Types here MUST have a corresponding row AND column in OK_STORAGE_LANGS.
785   static c_tid_t const STIDS[] = {
786 
787     // These are first so we get names like "deleted constructor".
788     TS_DEFAULT,
789     TS_DELETE,
790     TS_EXTERN_C,
791 
792     // This is next so "typedef" comes before (almost) everything else.
793     TS_TYPEDEF,
794 
795     // These are next so we get names like "static int".
796     TS_AUTO,
797     TS_APPLE_BLOCK,
798     TS_EXPORT,
799     TS_EXTERN,
800     TS_FRIEND,
801     TS_REGISTER,
802     TS_MUTABLE,
803     TS_STATIC,
804     TS_THREAD_LOCAL,
805 
806     // These are next so we get names like "static inline".
807     TS_EXPLICIT,
808     TS_INLINE,
809 
810     // These are next so we get names like "static inline final".
811     TS_OVERRIDE,
812     TS_FINAL,
813 
814     // These are next so we get names like "overridden virtual".
815     TS_PURE_VIRTUAL,
816     TS_VIRTUAL,
817     TS_NOEXCEPT,
818     TS_THROW,
819 
820     // These are next so we get names like "static inline constexpr".
821     TS_CONSTEVAL,
822     TS_CONSTEXPR,
823     TS_CONSTINIT,
824   };
825   C_TID_NAME_CAT( sbuf, stids, STIDS, in_english, ' ', &space );
826 
827   c_tid_t east_stids = TS_NONE;
828   if ( opt_east_const && !in_english ) {
829     east_stids = stids & TS_CV;
830     stids &= c_tid_compl( TS_CV );
831   }
832 
833   static c_tid_t const QUAL_STIDS[] = {
834     // These are before "shared" so we get names like "strict shared".
835     TS_UPC_RELAXED,
836     TS_UPC_STRICT,
837 
838     TS_UPC_SHARED,
839 
840     TS_CONST,
841     TS_RESTRICT,
842     TS_VOLATILE,
843 
844     // These are next so we get names like "const reference".
845     TS_REFERENCE,
846     TS_RVALUE_REFERENCE,
847 
848     // This is last so we get names like "const _Atomic".
849     TS_ATOMIC,
850   };
851   C_TID_NAME_CAT( sbuf, stids, QUAL_STIDS, in_english, ' ', &space );
852 
853   if ( OPT_LANG_IS(CPP_ANY) && apply_explicit_ecsu &&
854        !in_english && !is_error && c_tid_is_any( btids, TB_ANY_CLASS ) ) {
855     btids &= opt_explicit_ecsu;
856   }
857 
858   //
859   // Special case: C++23 adds an _Atomic(T) macro for compatibility with C11,
860   // but while _Atomic can be printed without () in C, they're required in C++:
861   //
862   //      _Atomic int x;                // C11 only
863   //      _Atomic(int) y;               // C11 or C++23
864   //
865   // Note that this handles printing () only for non-typedef types; for typedef
866   // types, see the similar special case for K_TYPEDEF in g_ast_print().
867   //
868   bool const print_parens_for_cpp23_Atomic =
869     OPT_LANG_IS(CPP_MIN(23)) && !in_english &&
870     c_tid_is_any( stids, TS_ATOMIC ) && !c_tid_is_any( btids, TB_TYPEDEF );
871 
872   if ( print_parens_for_cpp23_Atomic ) {
873     strbuf_putc( sbuf, '(' );
874     space = false;
875   }
876 
877   static c_tid_t const BTIDS[] = {
878     // These are first so we get names like "unsigned int".
879     TB_SIGNED,
880     TB_UNSIGNED,
881 
882     // These are next so we get names like "unsigned long int".
883     TB_SHORT,
884     TB_LONG,
885     TB_LONG_LONG,
886 
887     TB_VOID,
888     TB_AUTO,
889     TB_BOOL,
890     TB_CHAR,
891     TB_CHAR8_T,
892     TB_CHAR16_T,
893     TB_CHAR32_T,
894     TB_WCHAR_T,
895     TB_INT,
896     TB_COMPLEX,
897     TB_IMAGINARY,
898     TB_FLOAT,
899     TB_DOUBLE,
900     TB_ENUM,
901     TB_STRUCT,
902     TB_UNION,
903     TB_CLASS,
904 
905     // This is next so we get names like "unsigned long _Sat _Fract".
906     TB_EMC_SAT,
907 
908     TB_EMC_ACCUM,
909     TB_EMC_FRACT,
910   };
911   C_TID_NAME_CAT( sbuf, btids, BTIDS, in_english, ' ', &space );
912 
913   if ( print_parens_for_cpp23_Atomic )
914     strbuf_putc( sbuf, ')' );
915 
916   // Microsoft calling conventions must be handled here.
917   static c_tid_t const MSC_CALL_ATIDS[] = {
918     TA_MSC_CDECL,
919     TA_MSC_CLRCALL,
920     TA_MSC_FASTCALL,
921     TA_MSC_STDCALL,
922     TA_MSC_THISCALL,
923     TA_MSC_VECTORCALL,
924   };
925   C_TID_NAME_CAT( sbuf, atids, MSC_CALL_ATIDS, in_english, ' ', &space );
926 
927   if ( east_stids != TS_NONE )
928     C_TID_NAME_CAT( sbuf, east_stids, QUAL_STIDS, in_english, ' ', &space );
929 
930   // Really special cases.
931   if ( c_tid_is_any( btids, TB_NAMESPACE ) )
932     strbuf_sepc_puts( sbuf, ' ', &space, L_NAMESPACE );
933   else if ( c_tid_is_any( btids, TB_SCOPE ) )
934     strbuf_sepc_puts( sbuf, ' ', &space, L_SCOPE );
935 
936   return sbuf->str != NULL ? sbuf->str : "";
937 }
938 
939 ////////// extern functions ///////////////////////////////////////////////////
940 
c_type_add(c_type_t * dst_type,c_type_t const * new_type,c_loc_t const * new_loc)941 bool c_type_add( c_type_t *dst_type, c_type_t const *new_type,
942                  c_loc_t const *new_loc ) {
943   assert( dst_type != NULL );
944   assert( new_type != NULL );
945 
946   return  c_tid_add( &dst_type->btids, new_type->btids, new_loc ) &&
947           c_tid_add( &dst_type->stids, new_type->stids, new_loc ) &&
948           c_tid_add( &dst_type->atids, new_type->atids, new_loc );
949 }
950 
c_type_add_tid(c_type_t * dst_type,c_tid_t new_tids,c_loc_t const * new_loc)951 bool c_type_add_tid( c_type_t *dst_type, c_tid_t new_tids,
952                      c_loc_t const *new_loc ) {
953   c_tid_t *const dst_tids = c_type_get_tid_ptr( dst_type, new_tids );
954   return c_tid_add( dst_tids, new_tids, new_loc );
955 }
956 
c_type_and(c_type_t const * i_type,c_type_t const * j_type)957 c_type_t c_type_and( c_type_t const *i_type, c_type_t const *j_type ) {
958   assert( i_type != NULL );
959   assert( j_type != NULL );
960 
961   return C_TYPE_LIT(
962     i_type->btids & j_type->btids,
963     i_type->stids & j_type->stids,
964     i_type->atids & j_type->atids
965   );
966 }
967 
c_type_and_eq_compl(c_type_t * dst_type,c_type_t const * rm_type)968 void c_type_and_eq_compl( c_type_t *dst_type, c_type_t const *rm_type ) {
969   assert( dst_type != NULL );
970   assert( rm_type != NULL );
971 
972   dst_type->btids &= c_tid_compl( rm_type->btids );
973   dst_type->stids &= c_tid_compl( rm_type->stids );
974   dst_type->atids &= c_tid_compl( rm_type->atids );
975 }
976 
c_type_check(c_type_t const * type)977 c_lang_id_t c_type_check( c_type_t const *type ) {
978   // Check that the attribute(s) are legal in the current language.
979   C_TID_CHECK_LEGAL( type->atids, C_ATTRIBUTE_INFO );
980 
981   // Check that the storage class is legal in the current language.
982   C_TID_CHECK_LEGAL( type->stids, C_STORAGE_INFO );
983 
984   // Check that the type is legal in the current language.
985   C_TID_CHECK_LEGAL( type->btids, C_TYPE_INFO );
986 
987   // Check that the qualifier(s) are legal in the current language.
988   C_TID_CHECK_LEGAL( type->stids, C_QUALIFIER_INFO );
989 
990   // Check that the storage class combination is legal in the current language.
991   C_TID_CHECK_COMBO( type->stids, C_STORAGE_INFO, OK_STORAGE_LANGS );
992 
993   // Check that the type combination is legal in the current language.
994   C_TID_CHECK_COMBO( type->btids, C_TYPE_INFO, OK_TYPE_LANGS );
995 
996   // Check that the qualifier combination is legal in the current language.
997   C_TID_CHECK_COMBO( type->stids, C_QUALIFIER_INFO, OK_QUALIFIER_LANGS );
998 
999   return LANG_ANY;
1000 }
1001 
c_type_equal(c_type_t const * i_type,c_type_t const * j_type)1002 bool c_type_equal( c_type_t const *i_type, c_type_t const *j_type ) {
1003   assert( i_type != NULL );
1004   assert( j_type != NULL );
1005 
1006   if ( i_type->stids != j_type->stids || i_type->atids != j_type->atids )
1007     return false;
1008   c_tid_t const i_btids = c_tid_normalize( i_type->btids );
1009   c_tid_t const j_btids = c_tid_normalize( j_type->btids );
1010   return i_btids == j_btids;
1011 }
1012 
c_type_from_tid(c_tid_t tids)1013 c_type_t c_type_from_tid( c_tid_t tids ) {
1014   switch ( c_tid_tpid( tids ) ) {
1015     case C_TPID_NONE:
1016       break;                            // LCOV_EXCL_LINE
1017     case C_TPID_BASE:
1018       return C_TYPE_LIT_B( tids );
1019     case C_TPID_STORE:
1020       return C_TYPE_LIT_S( tids );
1021     case C_TPID_ATTR:
1022       return C_TYPE_LIT_A( tids );
1023   } // switch
1024 
1025   UNEXPECTED_INT_VALUE( tids );
1026 }
1027 
c_type_get_tid(c_type_t const * type,c_tid_t tids)1028 c_tid_t c_type_get_tid( c_type_t const *type, c_tid_t tids ) {
1029   assert( type != NULL );
1030 
1031   switch ( c_tid_tpid( tids ) ) {
1032     case C_TPID_NONE:
1033       break;                            // LCOV_EXCL_LINE
1034     case C_TPID_BASE:
1035       return type->btids;
1036     case C_TPID_STORE:
1037       return type->stids;
1038     case C_TPID_ATTR:
1039       return type->atids;
1040   } // switch
1041 
1042   UNEXPECTED_INT_VALUE( tids );
1043 }
1044 
c_type_get_tid_ptr(c_type_t * type,c_tid_t tids)1045 c_tid_t* c_type_get_tid_ptr( c_type_t *type, c_tid_t tids ) {
1046   assert( type != NULL );
1047 
1048   switch ( c_tid_tpid( tids ) ) {
1049     case C_TPID_NONE:
1050       break;                            // LCOV_EXCL_LINE
1051     case C_TPID_BASE:
1052       return &type->btids;
1053     case C_TPID_STORE:
1054       return &type->stids;
1055     case C_TPID_ATTR:
1056       return &type->atids;
1057   } // switch
1058 
1059   UNEXPECTED_INT_VALUE( tids );
1060 }
1061 
c_tid_add(c_tid_t * dst_tids,c_tid_t new_tids,c_loc_t const * new_loc)1062 bool c_tid_add( c_tid_t *dst_tids, c_tid_t new_tids, c_loc_t const *new_loc ) {
1063   assert( dst_tids != NULL );
1064   assert( new_loc != NULL );
1065   assert( c_tid_tpid( *dst_tids ) == c_tid_tpid( new_tids ) );
1066 
1067   if ( c_tid_is_long_int( *dst_tids ) && c_tid_is_long_int( new_tids ) ) {
1068     //
1069     // Special case: if the existing type is "long" and the new type is "long",
1070     // turn the new type into "long long".
1071     //
1072     new_tids = TB_LONG_LONG;
1073   }
1074 
1075   if ( !c_tid_is_none( *dst_tids & new_tids ) ) {
1076     print_error( new_loc,
1077       "\"%s\" can not be combined with \"%s\"\n",
1078        c_tid_name_error( new_tids ), c_tid_name_error( *dst_tids )
1079     );
1080     return false;
1081   }
1082 
1083   *dst_tids |= new_tids;
1084   return true;
1085 }
1086 
c_tid_name_c(c_tid_t tids)1087 char const* c_tid_name_c( c_tid_t tids ) {
1088   c_type_t const type = c_type_from_tid( tids );
1089   return c_type_name_impl( &type,
1090     /*apply_explicit_ecsu=*/false,
1091     /*in_english=*/false,
1092     /*is_error=*/false
1093   );
1094 }
1095 
c_tid_name_english(c_tid_t tids)1096 char const* c_tid_name_english( c_tid_t tids ) {
1097   c_type_t const type = c_type_from_tid( tids );
1098   return c_type_name_impl( &type,
1099     /*apply_explicit_ecsu=*/false,
1100     /*in_english=*/true,
1101     /*is_error=*/false
1102   );
1103 }
1104 
1105 
c_tid_name_error(c_tid_t tids)1106 char const* c_tid_name_error( c_tid_t tids ) {
1107   c_type_t const type = c_type_from_tid( tids );
1108   // When giving an error message, return the type name in pseudo-English if
1109   // we're parsing pseudo-English or in C/C++ if we're parsing C/C++.
1110   return c_type_name_impl( &type,
1111     /*apply_explicit_ecsu=*/false,
1112     /*in_english=*/cdecl_mode == CDECL_ENGLISH_TO_GIBBERISH,
1113     /*is_error=*/true
1114   );
1115 }
1116 
c_tid_normalize(c_tid_t tids)1117 c_tid_t c_tid_normalize( c_tid_t tids ) {
1118   switch ( c_tid_tpid( tids ) ) {
1119     case C_TPID_BASE:
1120       tids = c_tid_simplify( tids );
1121       // If the type is only implicitly int, make it explicitly int.
1122       if ( c_tid_is_except( tids, TB_SHORT, TB_ANY_EMC ) ||
1123            c_tid_is_except( tids, TB_LONG, TB_ANY_FLOAT | TB_ANY_EMC ) ||
1124            c_tid_is_except( tids, TB_UNSIGNED, TB_CHAR | TB_ANY_EMC ) ) {
1125         tids |= TB_INT;
1126       }
1127       break;
1128     default:
1129       /* suppress warning */;
1130   } // switch
1131   return tids;
1132 }
1133 
c_tid_scope_order(c_tid_t btids)1134 unsigned c_tid_scope_order( c_tid_t btids ) {
1135   assert( (btids & TX_MASK_TPID) == C_TPID_BASE );
1136   switch ( btids & (TB_ANY_SCOPE | TB_ENUM) ) {
1137     case TB_NONE:
1138     case TB_SCOPE:
1139       return 0;
1140     case TB_NAMESPACE:
1141       return 1;
1142     case TB_STRUCT:
1143     case TB_UNION:
1144     case TB_CLASS:
1145       return 2;
1146     case TB_ENUM:
1147     case TB_ENUM | TB_CLASS:
1148       return 3;
1149   } // switch
1150 
1151   UNEXPECTED_INT_VALUE( btids );
1152 }
1153 
c_tid_tpid(c_tid_t tids)1154 c_tpid_t c_tid_tpid( c_tid_t tids ) {
1155   //
1156   // If tids has been complemented, e.g., ~TS_REGISTER to denote "all but
1157   // register," then we have to complement tids back first.
1158   //
1159   if ( c_tid_is_compl( tids ) )
1160     tids = ~tids;
1161   tids &= TX_MASK_TPID;
1162   assert( tids <= C_TPID_ATTR );
1163   return STATIC_CAST( c_tpid_t, tids );
1164 }
1165 
c_type_is_any(c_type_t const * i_type,c_type_t const * j_type)1166 bool c_type_is_any( c_type_t const *i_type, c_type_t const *j_type ) {
1167   assert( i_type != NULL );
1168   assert( j_type != NULL );
1169 
1170   if ( (j_type->stids != TS_NONE &&
1171           (i_type->stids & j_type->stids) == TS_NONE) ||
1172        (j_type->atids != TA_NONE &&
1173           (i_type->atids & j_type->atids) == TA_NONE) ) {
1174     return false;
1175   }
1176 
1177   if ( j_type->btids == TB_NONE )
1178     return true;
1179   c_tid_t const i_btids = c_tid_normalize( i_type->btids );
1180   c_tid_t const j_btids = c_tid_normalize( j_type->btids );
1181   return (i_btids & j_btids) != TB_NONE;
1182 }
1183 
c_type_name_c(c_type_t const * type)1184 char const* c_type_name_c( c_type_t const *type ) {
1185   return c_type_name_impl( type,
1186     /*apply_explicit_ecsu=*/false,
1187     /*in_english=*/false,
1188     /*is_error=*/false
1189   );
1190 }
1191 
c_type_name_ecsu(c_type_t const * type)1192 char const* c_type_name_ecsu( c_type_t const *type ) {
1193   return c_type_name_impl( type,
1194     /*apply_explicit_ecsu=*/true,
1195     /*in_english=*/false,
1196     /*is_error=*/false
1197   );
1198 }
1199 
c_type_name_english(c_type_t const * type)1200 char const* c_type_name_english( c_type_t const *type ) {
1201   return c_type_name_impl( type,
1202     /*apply_explicit_ecsu=*/false,
1203     /*in_english=*/true,
1204     /*is_error=*/false
1205   );
1206 }
1207 
c_type_name_error(c_type_t const * type)1208 char const* c_type_name_error( c_type_t const *type ) {
1209   // See comment in c_tid_name_error().
1210   return c_type_name_impl(
1211     type,
1212     /*apply_explicit_ecsu=*/false,
1213     /*in_english=*/cdecl_mode == CDECL_ENGLISH_TO_GIBBERISH,
1214     /*is_error=*/true
1215   );
1216 }
1217 
c_type_or(c_type_t const * i_type,c_type_t const * j_type)1218 c_type_t c_type_or( c_type_t const *i_type, c_type_t const *j_type ) {
1219   assert( i_type != NULL );
1220   assert( j_type != NULL );
1221 
1222   return C_TYPE_LIT(
1223     i_type->btids | j_type->btids,
1224     i_type->stids | j_type->stids,
1225     i_type->atids | j_type->atids
1226   );
1227 }
1228 
c_type_or_eq(c_type_t * dst_type,c_type_t const * add_type)1229 void c_type_or_eq( c_type_t *dst_type, c_type_t const *add_type ) {
1230   assert( dst_type != NULL );
1231   assert( add_type != NULL );
1232 
1233   dst_type->btids |= add_type->btids;
1234   dst_type->stids |= add_type->stids;
1235   dst_type->atids |= add_type->atids;
1236 }
1237 
1238 ///////////////////////////////////////////////////////////////////////////////
1239 /* vim:set et sw=2 ts=2: */
1240