Home | History | Annotate | Line # | Download | only in lint1
      1 /*	$NetBSD: c23.c,v 1.18 2025/09/18 18:22:18 rillig Exp $	*/
      2 # 3 "c23.c"
      3 
      4 // Tests for the option -Ac23, which allows features from C23 and all earlier
      5 // ISO standards, but none of the GNU extensions.
      6 //
      7 // See also:
      8 //	c11.c
      9 //	msg_353.c		for empty initializer braces
     10 
     11 /* lint1-flags: -Ac23 -hw -X 351 */
     12 
     13 
     14 int
     15 bool_is_predefined_in_c23(void)
     16 {
     17 	bool t = true;
     18 	bool f = false;
     19 	return (t == true ? 20 : 0) + (f == false ? 3 : 0);
     20 }
     21 
     22 int
     23 c99_bool_is_still_valid_in_c23(void)
     24 {
     25 	_Bool t = 1;
     26 	_Bool f = 0;
     27 	return (t == 1 ? 20 : 0) + (f == 0 ? 3 : 0);
     28 }
     29 
     30 
     31 bool
     32 null_pointer_constant(const char *p, double dbl)
     33 {
     34 	/* expect+1: error: operands of '!=' have incompatible types 'double' and 'pointer to void' [107] */
     35 	if (dbl != nullptr)
     36 		p++;
     37 	if (dbl > 0.0)
     38 		p++;
     39 	if (*p == '\0')
     40 		p = nullptr;
     41 	return p == nullptr;
     42 }
     43 
     44 
     45 void *
     46 storage_class_in_compound_literal(void)
     47 {
     48 	typedef struct node node;
     49 	struct node {
     50 		node *left;
     51 		int value;
     52 		node *right;
     53 	};
     54 
     55 	node *tree;
     56 	tree = &(static node){
     57 	    &(static node){
     58 		nullptr,
     59 		3,
     60 		nullptr,
     61 	    },
     62 	    5,
     63 	    nullptr,
     64 	};
     65 	return tree->left;
     66 }
     67 
     68 int
     69 empty_initializer_braces(void)
     70 {
     71 	struct s {
     72 		int member;
     73 	} s;
     74 
     75 	// Empty initializer braces were introduced in C23.
     76 	s = (struct s){};
     77 	s = (struct s){s.member};
     78 	return s.member;
     79 }
     80 
     81 
     82 _Static_assert(1 > 0, "string");
     83 _Static_assert(1 > 0);
     84 
     85 
     86 // The keyword 'thread_local' was introduced in C23.
     87 thread_local int globally_visible;
     88 
     89 // Thread-local functions don't make sense; lint allows them, though.
     90 thread_local void
     91 thread_local_function(void)
     92 {
     93 }
     94 
     95 void
     96 function(void)
     97 {
     98 	// Not sure whether it makes sense to have a function-scoped
     99 	// thread-local variable.  Don't warn for now, let the compilers handle
    100 	// this case.
    101 	thread_local int function_scoped_thread_local;
    102 }
    103 
    104 // 'thread_local' can be combined with 'extern' and 'static', but with no other
    105 // storage classes.  The other storage classes cannot be combined.
    106 extern thread_local int extern_thread_local_1;
    107 thread_local extern int extern_thread_local_2;
    108 /* expect+1: warning: static variable 'static_thread_local_1' unused [226] */
    109 static thread_local int static_thread_local_1;
    110 /* expect+1: warning: static variable 'static_thread_local_2' unused [226] */
    111 thread_local static int static_thread_local_2;
    112 
    113 
    114 int
    115 attributes(int i)
    116 {
    117 	// An attribute specifier list may be empty.
    118 	[[]]i++;
    119 
    120 	// There may be leading or trailing commas.
    121 	[[,]]i++;
    122 
    123 	// There may be arbitrary commas around or between the attributes.
    124 	[[,,,,,]]i++;
    125 
    126 	// An attribute may be a plain identifier without arguments.
    127 	[[identifier]]i++;
    128 
    129 	// The identifier may be prefixed with one additional identifier.
    130 	[[prefix::identifier]]i++;
    131 
    132 	// An attribute may have empty arguments.
    133 	[[identifier()]]i++;
    134 
    135 	// The arguments of an attribute may be arbitrary tokens.
    136 	[[identifier([])]]i++;
    137 
    138 	// The commas in this "argument list" are ordinary punctuator tokens,
    139 	// they do not separate any arguments.
    140 	// The structure of the attribute argument is:
    141 	//	1. empty balanced token sequence between '[' and ']'
    142 	//	2. token ','
    143 	//	3. empty balanced token sequence between '{' and '}'
    144 	//	4. token ','
    145 	//	5. empty balanced token sequence between '(' and ')'
    146 	[[identifier([], {}, ())]]i++;
    147 
    148 	// Inside an argument, parentheses may be nested.
    149 	[[identifier(((((())))))]]i++;
    150 	// Inside an argument, brackets may be nested.
    151 	[[identifier([[[[[]]]]])]]i++;
    152 	// Inside an argument, braces may be nested.
    153 	[[identifier({{{{{}}}}})]]i++;
    154 
    155 	// An attribute argument may contain arbitrary punctuation.
    156 	[[identifier(++++ ? ? ? : : :: )]]i++;
    157 
    158 	// An attribute argument may contain constants and string literals.
    159 	[[identifier(0, 0.0, "hello" " " "world")]]i++;
    160 
    161 	// There may be multiple attribute specifier sequences in a row.
    162 	[[]][[]][[]]i++;
    163 
    164 	// An attribute may occur more than once.
    165 	[[
    166 		maybe_unused, maybe_unused, maybe_unused, maybe_unused,
    167 		maybe_unused, maybe_unused, maybe_unused, maybe_unused,
    168 		maybe_unused, maybe_unused, maybe_unused, maybe_unused,
    169 		maybe_unused, maybe_unused, maybe_unused, maybe_unused,
    170 		maybe_unused, maybe_unused, maybe_unused, maybe_unused,
    171 	]]i++;
    172 
    173 	return i;
    174 }
    175 
    176 typedef int number;
    177 
    178 void
    179 attributes_in_parameter_declaration(
    180     [[maybe_unused]] int int_param,
    181     [[maybe_unused]] const int const_int_param,
    182     [[maybe_unused]] number typedef_param,
    183     [[maybe_unused]] const number const_typedef_param)
    184 {
    185 }
    186 
    187 int
    188 attribute_in_switch_statement(int n)
    189 {
    190 	switch (n) {
    191 	case 1:
    192 		n++;
    193 	/* expect+1: warning: fallthrough on case statement [220] */
    194 	case 2:
    195 		n++;
    196 		[[fallthrough]];
    197 	case 3:
    198 		n++;
    199 		[[fallthrough]];
    200 	default:
    201 		n++;
    202 	}
    203 	return n;
    204 }
    205 
    206 // C23 6.7.7.4p13 says that "()" is equivalent to "(void)".
    207 void function_without_parameters();
    208