Home | History | Annotate | Line # | Download | only in lint1
      1 /*	$NetBSD: emit.c,v 1.18 2024/06/09 16:49:40 rillig Exp $	*/
      2 # 3 "emit.c"
      3 
      4 /*
      5  * Test the symbol information that lint1 writes to a .ln file.  Using this
      6  * symbol information, lint2 later checks that the symbols are used
      7  * consistently across different translation units.
      8  */
      9 
     10 /* Do not warn about unused parameters or 'extern' declarations. */
     11 /* lint1-extra-flags: -X 231 -X 351 */
     12 
     13 /*
     14  * Define some derived types.
     15  */
     16 
     17 struct struct_tag {
     18 	int member;
     19 };
     20 
     21 typedef struct {
     22 	int member;
     23 } struct_typedef;
     24 
     25 union union_tag {
     26 	int member;
     27 };
     28 
     29 typedef union {
     30 	int member;
     31 } union_typedef;
     32 
     33 enum enum_tag {
     34 	enum_tag_constant
     35 };
     36 
     37 typedef enum {
     38 	enum_typedef_constant
     39 } enum_typedef;
     40 
     41 /*
     42  * Variable declarations using the basic types (C99 6.2.5p14).
     43  *
     44  * Last synced with function outtype from emit1.c 1.43.
     45  */
     46 
     47 extern _Bool			extern__Bool;
     48 extern float _Complex		extern__Complex_float;
     49 extern double _Complex		extern__Complex_double;
     50 extern long double _Complex	extern__Complex_long_double;
     51 extern char			extern_char;
     52 extern signed char		extern_signed_char;
     53 extern unsigned char		extern_unsigned_char;
     54 extern short			extern_short;
     55 extern signed short		extern_signed_short;
     56 extern unsigned short		extern_unsigned_short;
     57 extern int			extern_int;
     58 extern signed int		extern_signed_int;
     59 extern unsigned int		extern_unsigned_int;
     60 extern long			extern_long;
     61 extern signed long		extern_signed_long;
     62 extern unsigned long		extern_unsigned_long;
     63 extern long long		extern_long_long;
     64 extern signed long long		extern_signed_long_long;
     65 extern unsigned long long	extern_unsigned_long_long;
     66 extern float			extern_float;
     67 extern double			extern_double;
     68 extern long double		extern_long_double;
     69 
     70 /*
     71  * Variable declarations using derived types (C99 6.2.5p20).
     72  */
     73 
     74 extern void *			extern_pointer_to_void;
     75 extern int			extern_array_5_of_int[5];
     76 
     77 /*
     78  * Type tags are written to the .ln file as 'T kind length name', where 'kind'
     79  * is either 1, 2 or 3.  This is confusing at first since in 'T110struct_tag',
     80  * the apparent number 110 is to be read as 'tag kind 1, length 10'.
     81  */
     82 extern struct struct_tag	extern_struct_tag;
     83 extern struct_typedef		extern_struct_typedef;
     84 extern union union_tag		extern_union_tag;
     85 extern union_typedef		extern_union_typedef;
     86 extern enum enum_tag		extern_enum_tag;
     87 extern enum_typedef		extern_enum_typedef;
     88 
     89 extern struct {
     90 	int member;
     91 }				extern_anonymous_struct;
     92 extern union {
     93 	int member;
     94 }				extern_anonymous_union;
     95 extern enum {
     96 	anonymous_enum_constant
     97 }				extern_anonymous_enum;
     98 
     99 /*
    100  * Variable definitions.
    101  *
    102  * Static variables are not recorded in the .ln file.
    103  */
    104 
    105 extern int			declared_int;
    106 int				defined_int;
    107 /* expect+1: warning: static variable 'static_int' unused [226] */
    108 static int			static_int;
    109 
    110 /*
    111  * Type qualifiers.
    112  */
    113 
    114 extern const int		extern_const_int;
    115 extern volatile int		extern_volatile_int;
    116 extern const volatile int	extern_const_volatile_int;
    117 
    118 /*
    119  * Functions.
    120  */
    121 
    122 extern void return_void_unknown_parameters();
    123 extern /* implicit int */ return_implicit_int_unknown_parameters();
    124 /* expect-1: error: old-style declaration; add 'int' [1] */
    125 /* For function declarations, the keyword 'extern' is optional. */
    126 extern void extern_return_void_no_parameters(void);
    127 /* implicit extern */ void return_void_no_parameters(void);
    128 /* expect+1: warning: static function 'static_return_void_no_parameters' declared but not defined [290] */
    129 static void static_return_void_no_parameters(void);
    130 
    131 void taking_int(int);
    132 /* The 'const' parameter does not make a difference. */
    133 void taking_const_int(const int);
    134 void taking_int_double_bool(int, double, _Bool);
    135 void taking_struct_union_enum_tags(struct struct_tag, union union_tag,
    136     enum enum_tag);
    137 void taking_struct_union_enum_typedefs(struct_typedef, union_typedef,
    138     enum_typedef);
    139 
    140 void taking_varargs(const char *, ...);
    141 
    142 /*
    143  * This function does not affect anything outside this translation unit.
    144  * Naively there is no need to record this function in the .ln file, but it
    145  * is nevertheless recorded.  There's probably a good reason for recording
    146  * it.
    147  */
    148 /* expect+1: warning: static function 'static_function' declared but not defined [290] */
    149 static int static_function(void);
    150 
    151 void my_printf(const char *, ...);
    152 void my_scanf(const char *, ...);
    153 
    154 /*
    155  * String literals that occur in function calls are written to the .ln file,
    156  * just in case they are related to a printf-like or scanf-like function.
    157  *
    158  * In this example, the various strings are not format strings, they just
    159  * serve to cover the code that escapes character literals (outqchar in
    160  * lint1) and reads them back into characters (inpqstrg in lint2).
    161  */
    162 void
    163 cover_outqchar(void)
    164 {
    165 	my_printf("%s", "%");
    166 	my_printf("%s", "%s");
    167 	my_printf("%s", "%%");
    168 	my_printf("%s", "%\\ %\" %' %\a %\b %\f %\n %\r %\t %\v %\177");
    169 }
    170 
    171 void
    172 cover_outfstrg(void)
    173 {
    174 	my_printf("%s", "%-3d %+3d % d %#x %03d %*.*s %6.2f %hd %ld %Ld %qd");
    175 	my_scanf("%s", "%[0-9]s %[^A-Za-z]s %[][A-Za-z0-9]s %[+-]s");
    176 }
    177 
    178 /*
    179  * Calls to GCC builtin functions should not be emitted since GCC already
    180  * guarantees a consistent definition of these function and checks the
    181  * arguments, so there is nothing left to do for lint.
    182  */
    183 void
    184 call_gcc_builtins(int x, long *ptr)
    185 {
    186 	long value;
    187 
    188 	__builtin_expect(x > 0, 1);
    189 	__builtin_bswap32(0x12345678);
    190 
    191 	__atomic_load(ptr, &value, 0);
    192 }
    193 
    194 /*
    195  * XXX: It's strange that a function can be annotated with VARARGS even
    196  * though it does not take varargs at all.
    197  *
    198  * This feature is not useful for modern code anyway, it focused on pre-C90
    199  * code that did not have function prototypes.
    200  */
    201 
    202 /* VARARGS */
    203 void
    204 varargs_comment(const char *fmt)
    205 {
    206 }
    207 
    208 /* VARARGS 0 */
    209 void
    210 varargs_0_comment(const char *fmt)
    211 {
    212 }
    213 
    214 /* VARARGS 3 */
    215 void
    216 varargs_3_comment(int a, int b, int c, const char *fmt)
    217 {
    218 }
    219 
    220 /* PRINTFLIKE */
    221 void
    222 printflike_comment(const char *fmt)
    223 {
    224 }
    225 
    226 /* PRINTFLIKE 0 */
    227 void
    228 printflike_0_comment(const char *fmt)
    229 {
    230 }
    231 
    232 /* PRINTFLIKE 3 */
    233 void
    234 printflike_3_comment(int a, int b, const char *fmt)
    235 {
    236 }
    237 
    238 /* PRINTFLIKE 10 */
    239 void
    240 printflike_10_comment(int a1, int a2, int a3, int a4, int a5,
    241 		      int a6, int a7, int a8, int a9,
    242 		      const char *fmt)
    243 {
    244 }
    245 
    246 /* SCANFLIKE */
    247 void
    248 scanflike_comment(const char *fmt)
    249 {
    250 }
    251 
    252 /* SCANFLIKE 0 */
    253 void
    254 scanflike_0_comment(const char *fmt)
    255 {
    256 }
    257 
    258 /* SCANFLIKE 3 */
    259 void
    260 scanflike_3_comment(int a, int b, const char *fmt)
    261 {
    262 }
    263 
    264 int
    265 used_function(void)
    266 {
    267 	return 4;
    268 }
    269 
    270 inline int
    271 inline_function(void)
    272 {
    273 	used_function();
    274 	(void)used_function();
    275 	return used_function();
    276 }
    277 
    278 extern int declared_used_var;
    279 int defined_used_var;
    280 
    281 /*
    282  * When a function is used, that usage is output as a 'c' record.
    283  * When a variable is used, that usage is output as a 'u' record.
    284  */
    285 void
    286 use_vars(void)
    287 {
    288 	declared_used_var++;
    289 	defined_used_var++;
    290 }
    291 
    292 /*
    293  * Since C99, an initializer may contain a compound expression. This allows
    294  * to create trees of pointer data structures at compile time.
    295  *
    296  * The objects that are created for these compound literals are unnamed,
    297  * therefore there is no point in exporting them to the .ln file.
    298  *
    299  * Before emit1.c 1.60 from 2021-11-28, lint exported them.
    300  */
    301 struct compound_expression_in_initializer {
    302 	const char * const *info;
    303 };
    304 
    305 struct compound_expression_in_initializer compound = {
    306 	.info = (const char *[16]){
    307 		[0] = "zero",
    308 	},
    309 };
    310 
    311 /*
    312  * Before decl.c 1.312 and init.c 1.242 from 2023-05-22, the type that ended up
    313  * in the .ln file was 'A0cC', which was wrong as it had array size 0 instead
    314  * of the correct 8.  That type had been taken too early, before looking at the
    315  * initializer.
    316  */
    317 const char array_of_unknown_size[] = "unknown";
    318 
    319 int used_and_using(int);
    320 int only_used(void);
    321 
    322 int
    323 only_using(void)
    324 {
    325 	return used_and_using(only_used());
    326 }
    327