/* $NetBSD: emit.c,v 1.17 2023/05/22 17:53:27 rillig Exp $ */ # 3 "emit.c" /* * Test the symbol information that lint1 writes to a .ln file. Using this * symbol information, lint2 later checks that the symbols are used * consistently across different translation units. */ /* Do not warn about unused parameters or 'extern' declarations. */ /* lint1-extra-flags: -X 231 -X 351 */ /* * Define some derived types. */ struct struct_tag { int member; }; typedef struct { int member; } struct_typedef; union union_tag { int member; }; typedef union { int member; } union_typedef; enum enum_tag { enum_tag_constant }; typedef enum { enum_typedef_constant } enum_typedef; /* * Variable declarations using the basic types (C99 6.2.5p14). * * Last synced with function outtype from emit1.c 1.43. */ extern _Bool extern__Bool; extern float _Complex extern__Complex_float; extern double _Complex extern__Complex_double; extern long double _Complex extern__Complex_long_double; extern char extern_char; extern signed char extern_signed_char; extern unsigned char extern_unsigned_char; extern short extern_short; extern signed short extern_signed_short; extern unsigned short extern_unsigned_short; extern int extern_int; extern signed int extern_signed_int; extern unsigned int extern_unsigned_int; extern long extern_long; extern signed long extern_signed_long; extern unsigned long extern_unsigned_long; extern long long extern_long_long; extern signed long long extern_signed_long_long; extern unsigned long long extern_unsigned_long_long; extern float extern_float; extern double extern_double; extern long double extern_long_double; /* * Variable declarations using derived types (C99 6.2.5p20). */ extern void * extern_pointer_to_void; extern int extern_array_5_of_int[5]; /* * Type tags are written to the .ln file as 'T kind length name', where 'kind' * is either 1, 2 or 3. This is confusing at first since in 'T110struct_tag', * the apparent number 110 is to be read as 'tag kind 1, length 10'. */ extern struct struct_tag extern_struct_tag; extern struct_typedef extern_struct_typedef; extern union union_tag extern_union_tag; extern union_typedef extern_union_typedef; extern enum enum_tag extern_enum_tag; extern enum_typedef extern_enum_typedef; extern struct { int member; } extern_anonymous_struct; extern union { int member; } extern_anonymous_union; extern enum { anonymous_enum_constant } extern_anonymous_enum; /* * Variable definitions. * * Static variables are not recorded in the .ln file. */ extern int declared_int; int defined_int; /* expect+1: warning: static variable 'static_int' unused [226] */ static int static_int; /* * Type qualifiers. */ extern const int extern_const_int; extern volatile int extern_volatile_int; extern const volatile int extern_const_volatile_int; /* * Functions. */ extern void return_void_unknown_parameters(); extern /* implicit int */ return_implicit_int_unknown_parameters(); /* expect-1: error: old-style declaration; add 'int' [1] */ /* For function declarations, the keyword 'extern' is optional. */ extern void extern_return_void_no_parameters(void); /* implicit extern */ void return_void_no_parameters(void); /* expect+1: warning: static function 'static_return_void_no_parameters' declared but not defined [290] */ static void static_return_void_no_parameters(void); void taking_int(int); /* The 'const' parameter does not make a difference. */ void taking_const_int(const int); void taking_int_double_bool(int, double, _Bool); void taking_struct_union_enum_tags(struct struct_tag, union union_tag, enum enum_tag); void taking_struct_union_enum_typedefs(struct_typedef, union_typedef, enum_typedef); void taking_varargs(const char *, ...); /* * This function does not affect anything outside this translation unit. * Naively there is no need to record this function in the .ln file, but it * is nevertheless recorded. There's probably a good reason for recording * it. */ /* expect+1: warning: static function 'static_function' declared but not defined [290] */ static int static_function(void); void my_printf(const char *, ...); void my_scanf(const char *, ...); /* * String literals that occur in function calls are written to the .ln file, * just in case they are related to a printf-like or scanf-like function. * * In this example, the various strings are not format strings, they just * serve to cover the code that escapes character literals (outqchar in * lint1) and reads them back into characters (inpqstrg in lint2). */ void cover_outqchar(void) { my_printf("%s", "%"); my_printf("%s", "%s"); my_printf("%s", "%%"); my_printf("%s", "%\\ %\" %' %\a %\b %\f %\n %\r %\t %\v %\177"); } void cover_outfstrg(void) { my_printf("%s", "%-3d %+3d % d %#x %03d %*.*s %6.2f %hd %ld %Ld %qd"); my_scanf("%s", "%[0-9]s %[^A-Za-z]s %[][A-Za-z0-9]s %[+-]s"); } /* * Calls to GCC builtin functions should not be emitted since GCC already * guarantees a consistent definition of these function and checks the * arguments, so there is nothing left to do for lint. */ void call_gcc_builtins(int x, long *ptr) { long value; __builtin_expect(x > 0, 1); __builtin_bswap32(0x12345678); __atomic_load(ptr, &value, 0); } /* * XXX: It's strange that a function can be annotated with VARARGS even * though it does not take varargs at all. * * This feature is not useful for modern code anyway, it focused on pre-C90 * code that did not have function prototypes. */ /* VARARGS */ void varargs_comment(const char *fmt) { } /* VARARGS 0 */ void varargs_0_comment(const char *fmt) { } /* VARARGS 3 */ void varargs_3_comment(int a, int b, int c, const char *fmt) { } /* PRINTFLIKE */ void printflike_comment(const char *fmt) { } /* PRINTFLIKE 0 */ void printflike_0_comment(const char *fmt) { } /* PRINTFLIKE 3 */ void printflike_3_comment(int a, int b, const char *fmt) { } /* PRINTFLIKE 10 */ void printflike_10_comment(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, const char *fmt) { } /* SCANFLIKE */ void scanflike_comment(const char *fmt) { } /* SCANFLIKE 0 */ void scanflike_0_comment(const char *fmt) { } /* SCANFLIKE 3 */ void scanflike_3_comment(int a, int b, const char *fmt) { } int used_function(void) { return 4; } inline int inline_function(void) { used_function(); (void)used_function(); return used_function(); } extern int declared_used_var; int defined_used_var; /* * When a function is used, that usage is output as a 'c' record. * When a variable is used, that usage is output as a 'u' record. */ void use_vars(void) { declared_used_var++; defined_used_var++; } /* * Since C99, an initializer may contain a compound expression. This allows * to create trees of pointer data structures at compile time. * * The objects that are created for these compound literals are unnamed, * therefore there is no point in exporting them to the .ln file. * * Before emit1.c 1.60 from 2021-11-28, lint exported them. */ struct compound_expression_in_initializer { const char * const *info; }; struct compound_expression_in_initializer compound = { .info = (const char *[16]){ [0] = "zero", }, }; /* * Before decl.c 1.312 and init.c 1.242 from 2023-05-22, the type that ended up * in the .ln file was 'A0cC', which was wrong as it had array size 0 instead * of the correct 8. That type had been taken too early, before looking at the * initializer. */ const char array_of_unknown_size[] = "unknown";