parse: fix a fucking awful gen bug holy shit lmfao
parse+test: also run tests with c2y
check tests: improve first struct test
C parsing and checking library for Hare
Send patches to ~sebsite/hare-c@lists.sr.ht (archive)
If you need help or have questions ping me on fedi or IRC or wherever :)
This checklist isn't exhaustive; I'm updating it as I go.
Legend:
🗸 implemented
T properly tested
X currently can't be tested (e.g. runtime behavior)
basics
T🗸 comments
T🗸 block
T🗸 line
T🗸 backslashes at end of line
declarations
T🗸 must declare at least one identifier
specifiers
type specifiers
T🗸 signed, unsigned
T🗸 parse
T🗸 void
T🗸 parse
T🗸 incomplete type; cannot be completed
T🗸 char
T🗸 parse
T🗸 short
T🗸 parse
T🗸 int
T🗸 parse
T🗸 long
T🗸 parse
T🗸 float
T🗸 parse
T🗸 double
T🗸 parse
T🗸 long double
T🗸 parse
struct/union
T🗸 struct
T🗸 declarations
T🗸 named
T🗸 parse
T🗸 check
T🗸 anonymous
T🗸 parse
T🗸 check
T🗸 definitions
T🗸 parse
T🗸 check
T🗸 forward
T🗸 parse
T🗸 check
🗸 union
🗸 declarations
🗸 named
T🗸 parse
🗸 check
🗸 anonymous
T🗸 parse
🗸 check
🗸 definitions
T🗸 parse
🗸 check
🗸 forward
T🗸 parse
🗸 check
bit-fields
T🗸 parse
T🗸 named
T🗸 anonymous
check
can't take address
width requirements
integer constant expression
non-negative
may be zero
less than or equal to width of type
width must be integer constant expression
width must be non-negative
may or may not have declarator if width > 0
zero width
declarator must be absent
causes following bit-fields to not be packed into the previous bit-field's unit
adjacent bit-fields are packed into the same union
true for both structs and unions
int is signed
T🗸 incomplete types disallowed
T🗸 must contain at least one named member
T🗸 variably modified member types disallowed
T🗸 tag inserted into scope immediately after it's declared
tag is always declared when not used as type specifier
T🗸 when used as type specifier, tag is only declared if no other declaration is visible
T🗸 duplicate fields disallowed
T🗸 fields outside of nested structs/unions
T🗸 including fields from nested structs/unions
T🗸 fields may not have function type
tag is inserted into scope immediately after declared
definition for same struct/union can't appear within struct/union definition body
enum
T🗸 declarations
T🗸 named
T🗸 anonymous
T🗸 definitions
T🗸 forward disallowed
T🗸 members inserted into scope
T🗸 parse
T🗸 no linkage
T🗸 can't be redeclared
T🗸 not lvalue
T🗸 can't take address
T🗸 inserted into scope immediately after identifier
T🗸 tag inserted into scope immediately after definition ends
T🗸 compatible type
T🗸 implicit enumerated type
T🗸 type is unsigned int if all members are representable
T🗸 otherwise, type is int
T🗸 enumeration member type is int
T🗸 enum type is compatible with, but not equivalent to, enumerated type
🗸 error if any value would overflow enumeration member type
🗸 with initializer
🗸 without initializer
T🗸 duplicate fields disallowed
T🗸 enum member redeclares existing non-enum declaration
T🗸 enum member redeclares existing different enum declaration
T🗸 enum member redeclares member of same enum
T🗸 enum type is incomplete until definition ends
T🗸 typedefs
T🗸 parse
T🗸 inserted into scope
T🗸 file scope
T🗸 disallowed for variably modified types
T🗸 allowed otherwise
T🗸 block scope
T🗸 variably modified types allowed
T🗸 all other types allowed
T🗸 storage-class specifiers
T🗸 auto
T🗸 parse
T🗸 static
T🗸 parse
T🗸 register
T🗸 parse
T🗸 forbids taking address
T🗸 explicitly
T🗸 implicitly (e.g. array -> pointer conversion)
T🗸 also applies to derivative lvalues
T🗸 extern
T🗸 parse
T🗸 defaults to external linkage
T🗸 uses linkage of identifier visible in scope when it's internal or external
T🗸 typedef
T🗸 parse
T🗸 inserts type into scope
T🗸 can't have initializer
T🗸 at most one storage-class specifier per declaration (sans thread_local)
T🗸 duplicates disallowed
T🗸 duplicate specifiers
T🗸 disallowed for type specifiers
T🗸 allowed for other specifiers
T🗸 disallow incompatible
T🗸 type specifiers
T🗸 other specifiers
T🗸 qualifiers
T🗸 allowed in any order
T🗸 duplicates allowed
declarators
T🗸 pointer
function
parameters
T🗸 named
T🗸 anonymous
X🗸 arrays converted to (qualified) pointers
X🗸 still checked as arrays
X🗸 functions converted to function pointers
T🗸 may not declare more than one (non-tag) identifier
T🗸 may not be initialized
T🗸 without storage-class specifier
T🗸 defaults to implicit auto
T🗸 register storage-class specifier
T🗸 parse
T🗸 declares with register storage
T🗸 ignored for non-definitions
T🗸 may be different in compatible types
T🗸 applies even when other declarations' parameters have different/absent storage-class specifiers
T🗸 all other specifiers disallowed
T🗸 empty parameter list
T🗸 designates unspecified number of parameters
T🗸 isn't compatible with variadic function types
T🗸 treated as unqualified when taking composite type
inserted into scope immediately after declared
can be used in declarators of subsequent parameters
can be used by previous parameters in k&r declarations
T🗸 warn when parameter is void
T🗸 return type requirements
T🗸 may not return array
T🗸 may not return function
T🗸 warn when function returning complete type doesn't have return statement
T🗸 except for main function in hosted environment
T🗸 all other functions
T🗸 storage-class specifier must be static or extern (explicit or otherwise)
T🗸 error out when explicitly given qualifiers (via typedef)
T🗸 implicit const qualifier
T🗸 qualifiers discarded for return type
T🗸 array
T🗸 without qualifiers
T🗸 qualifiers apply to element type
T🗸 don't apply to array itself before c23
T🗸 ...except as inner-most declarator of function parameter
T🗸 different from qualifying an array typedef or typeof
T🗸 qualifiers may only be in square brackets in inner-most declarator of function parameter
T🗸 if present, known size must be greater than zero
T🗸 element type must be complete object type
T🗸 identifier only
T🗸 parenthesized
T🗸 type names
T🗸 with declarator
T🗸 without declarator
T🗸 scopes
T🗸 file
T🗸 parse
T🗸 auto/register specifiers disallowed
T🗸 default storage
T🗸 extern for functions
T🗸 external linkage for objects
T🗸 block
T🗸 parse
T🗸 default storage
T🗸 static for functions (TODO: double check this)
T🗸 auto for objects
T🗸 duplicates
T🗸 file scope
T🗸 allowed for compatible declarations
T🗸 composite type
T🗸 compatible specifiers
T🗸 disallowed for incompatible declarations
T🗸 at most one definition allowed
T🗸 block scope
T🗸 disallowed within same scope
T🗸 shadowing in nested scopes
T🗸 shadowing block scoped declarations
T🗸 shadowing file scoped declarations
T🗸 struct/union/enum tags must always refer to same type
T🗸 unique namespaces
T🗸 identifiers
T🗸 struct/union/enum
T🗸 goto labels
T🗸 function scope
T🗸 internally-linked declarations must be complete by end of translation unit
T🗸 translation unit must not be empty (static assertions and empty declarations are ok)
internally-linked declaration must be initialized if used
except sizeof
except alignof
all other expressions
T🗸 can't declare an object with type void
warnings
internally-linked declaration is never used
internally-linked function is never defined
expressions
🗸 constants and literals
T🗸 numbers
T🗸 preprocessing numbers
T🗸 integer constants
T🗸 bases
T🗸 decimal
T🗸 hex
T🗸 octal
T🗸 suffixes
T🗸 u
T🗸 l
T🗸 parse value
T🗸 floating constants
T🗸 decimal
T🗸 exponent
T🗸 suffixes
T🗸 f
T🗸 l
T🗸 parse value
T🗸 character constants
T🗸 plain
T🗸 L prefix
🗸 string literals
T🗸 plain
T🗸 L prefix
T🗸 string concatenation
T🗸 works for same-prefix strings
T🗸 disallowed for strings with different prefixes
T🗸 trigraph-like character sequences are escaped when unparsed (prior to c23)
🗸 may be invalid utf-8
sizeof
T🗸 parse
T🗸 type
T🗸 expression
T🗸 unambiguous expressions
T🗸 unparenthesized compound literal
X🗸 operand isn't evaluated if not variably modified
X🗸 operand is evaluated if variably modified
operand must not be bit-field
T🗸 operand must be complete object
T🗸 array indexing
T🗸 parse
T🗸 struct/union field accessing
T🗸 forms (parse)
T🗸 a.b
T🗸 a->b
T🗸 check
T🗸 unary
T🗸 postfix
T🗸 parse
T🗸 prefix
T🗸 parse
T🗸 &
T🗸 compile-time
T🗸 runtime
T🗸 operand is lvalue
T🗸 operand is function designator
T🗸 operand is unary *
T🗸 allowed when explicit
T🗸 allowed when implicit from array indexing
X🗸 neither & nor * is evaluated
T🗸 constraints still apply
T🗸 everything else disallowed
T🗸 ++ and --
X🗸 equivalent to += 1
T🗸 ...except operand can't have a complex type
T🗸 binary
T🗸 parse
T🗸 assignment
T🗸 parse
T🗸 simple assignment
T🗸 compound assignment
X🗸 operands are only evaluated once
X🗸 computed value is computed equivalently to binary expression
T🗸 result of binary expression must be assignable to first operand's type
T🗸 second operand can't be a pointer for addition or subtraction
T🗸 everything else is fine
T🗸 first operand must be a mutable lvalue
T🗸 first operand must not be an array
T🗸 parenthesized
T🗸 ternary
T🗸 operator precedence
conversion
T🗸 explicit (cast expressions)
T🗸 parse
T🗸 extends implicit type conversion rules
T🗸 integer -> pointer
T🗸 pointer -> integer
T🗸 pointer -> pointer
T🗸 object -> object
T🗸 function -> function
T🗸 no limitations for qualifiers
T🗸 any -> void
T🗸 everything else disallowed (except object <-> function; see extensions)
implicit
integer promotion
T🗸 non-bit-fields
bit-fields
width taken into account
bit-precise integers don't change, regardless of width
T🗸 lvalue conversion
types
T🗸 integer -> float
T🗸 float -> float
T🗸 integer -> integer
T🗸 float -> integer
T🗸 pointer -> bool
T🗸 array -> pointer
T🗸 function -> pointer
T🗸 pointer -> pointer
T🗸 pointer -> compatible pointer
T🗸 object pointer -> void pointer
T🗸 void pointer -> object pointer
T🗸 can't implicitly convert to any other pointer
T🗸 qualifiers may be added
T🗸 qualifiers may not be removed
struct/union -> same struct/union
T🗸 tagged
untagged
T🗸 integer -> pointer
T🗸 allowed when converting from integer constant 0
T🗸 disallowed otherwise
T🗸 nullptr -> pointer
T🗸 nullptr -> bool
T🗸 nullptr -> nullptr
T🗸 null pointer constant -> pointer
T🗸 null pointer constant -> nullptr
T🗸 everything else disallowed
T🗸 function call
T🗸 parse
T🗸 check
T🗸 arguments must have complete type
constant expressions
T🗸 disallowed (sub-)expressions
T🗸 assignment
T🗸 increment/decrement
T🗸 array indexing
T🗸 arrow expression (->)
T🗸 unary *
T🗸 including as operand of unary &
T🗸 function call
T🗸 comma expression
T🗸 __builtin_va_arg
X🗸 __builtin_va_copy
X🗸 __builtin_va_end
X🗸 __builtin_va_start
must evaluate to value which is representable in its type
struct/union field access
🗸 allowed if constexpr
disallowed if not constexpr
result is also constexpr
result is named constant if struct/union object is named constant
🗸 enum constant
T🗸 pre-defined constant
T🗸 true
T🗸 false
T🗸 nullptr
🗸 constexpr object
integer constant expressions
🗸 top-most expression may be anything not generally disallowed, but see limitations
🗸 result must be integer type
limitations for operands
T🗸 integer constant
🗸 named constant with integer type
constexpr compound literal with integer type
non-constexpr compound literal disallowed
T🗸 character constant
T🗸 translation-time sizeof
T🗸 alignof
T🗸 __builtin_offsetof
cast
additional expressions allowed as immediate operand
🗸 floating-point constant
🗸 named constant with arithmetic type
constexpr compound literal with arithmetic type
non-constexpr compound literal disallowed
everything else disallowed, unless not evaluated (sizeof/alignof)
sizeof on variably modified type disallowed (since it's evaluated)
arithmetic constant expressions
TODO
T🗸 constant expression in initializer
T🗸 null pointer constant
T🗸 integer constant expression which evaluates to zero
T🗸 ...casted to void *
T🗸 unqualified
T🗸 qualified
T🗸 void can't be qualified
T🗸 doesn't otherwise affect type conversion rules
🗸 integer promotion
🗸 unsigned -> unsigned
🗸 unsigned -> signed
🗸 signed -> unsigned
🗸 signed -> signed
🗸 char's signedness is taken into account
T🗸 additional errors
T🗸 don't error when not evaluated
T🗸 including because of short-circuiting
T🗸 expression which isn't evaluated need not be constant
T🗸 division by zero
T🗸 integer division
T🗸 integer modulus division
T🗸 floating-point is ok
T🗸 bit-shift right operand exceeds integer width
T🗸 signed integer overflow
T🗸 addition
T🗸 subtraction
T🗸 multiplication
T🗸 division
T🗸 modulo
T🗸 left shift
T🗸 negation
🗸 TODO: write more shit here i guess
statements
T🗸 goto
T🗸 parse
T🗸 jump to any label within function
T🗸 disallow undefined labels
T🗸 may not jump from outside scope of VMT to inside scope
T🗸 compound
T🗸 parse
labelled
T🗸 goto label
T🗸 parse
T🗸 unique per-function
case
T🗸 parse
T🗸 must evaluate to integer constant
case type is converted to type of controlling expression
warn if constant value is truncated
T🗸 must only appear in switch body
T🗸 direct descendant
T🗸 within another block
T🗸 disallowed everywhere else
T🗸 only visible to inner-most switch body
T🗸 each case in switch body is unique
T🗸 ...but nested switch statements may contain duplicates
T🗸 default
T🗸 parse
T🗸 must only appear in switch body
T🗸 direct descendant
T🗸 within another block
T🗸 disallowed everywhere else
T🗸 only visible to inner-most switch body
T🗸 at most one per switch body
T🗸 ...but nested switch statements may contain their own
T🗸 labelled statements may themselves be labelled
T🗸 empty
T🗸 parse
T🗸 if
T🗸 parse
T🗸 condition must be scalar
T🗸 while
T🗸 parse
T🗸 condition must be scalar
T🗸 do-while
T🗸 parse
T🗸 condition must be scalar
T🗸 for
T🗸 parse
T🗸 condition must be scalar (if present)
T🗸 initializer, condition, and afterthought may all be omitted
switch
T🗸 parse
T🗸 value must be integer
X🗸 value is promoted
T🗸 no VMTs not in scope of switch statement may be in scope of any cases
warnings
T🗸 no cases in body
contains unreachable code
T🗸 break
T🗸 parse
T🗸 allowed in loop
T🗸 allowed in switch statement
T🗸 disallowed everywhere else
X🗸 causes jump to outside whatever it applies to
T🗸 within check
X🗸 for-loop afterthought isn't evaluated
T🗸 continue
T🗸 parse
T🗸 allowed in loop
T🗸 disallowed everywhere else
T🗸 causes jump to end of loop it applies to
T🗸 within check
X🗸 so for-loop afterthought is evaluated, then condition
T🗸 return
T🗸 parse
T🗸 type of return value must be convertible to function return type
T🗸 function with void result type can't return an expression
T🗸 non-void expression
T🗸 void expression
T🗸 returning without expression from function with non-void result type
T🗸 warn before c99
T🗸 error after c99
T🗸 warn when used in noreturn function
T🗸 expression statements
T🗸 parse
T🗸 implicitly convert to void
T🗸 bindings
T🗸 TODO: write more shit here (stuff handled in fromabinding)
T🗸 enters scope before initializer is checked
🗸 initializers
T🗸 parse
T🗸 non-compound
T🗸 without braces
T🗸 may be surrounded by braces
T🗸 when single scalar object
T🗸 when using string literal to initialize array
🗸 compound initializers
T🗸 parse
T🗸 check
T🗸 array literals
T🗸 complete array type
T🗸 incomplete array type
T🗸 set length to length of literal
T🗸 struct literals
T🗸 union literals
T🗸 can be nested
🗸 must always consist of constant expressions prior to c99
🗸 braced scalar initializer need not be constant
T🗸 must be constant expression for objects with non-automatic storage duration
T🗸 may be any expression otherwise (except for compound initializer prior to c99)
T🗸 string literal may initialize array
T🗸 allowed when array length >= sizeof(string) - 1
T🗸 disallowed when array length < sizeof(string) - 1
T🗸 for incomplete array type, length defaults to sizeof(string)
X🗸 excess array elements are initialized to zero (nul)
T🗸 variadic functions
T🗸 function definitions
T🗸 declaration inserted into scope
T🗸 before body is parsed
T🗸 before body is checked
T🗸 declarator must be function
T🗸 non-pointer accepted
T🗸 pointer rejected
T🗸 typedef rejected
T🗸 without arguments (void)
T🗸 with named arguments
T🗸 argument types must be complete (sans (void) case)
T🗸 return type must be either complete type or void (in addition to other requirements)
T🗸 identifiers
T🗸 no such thing as an invalid token
T🗸 type size must be representable as size_t
T🗸 array
T🗸 struct
T🗸 union
main function
🗸 no requirements or restrictions imposed in freestanding environment
hosted environment
🗸 warn; don't error
if __asm__("main") is given, no restrictions on the function's identifier are imposed
TODO: main but with non-main __asm__?
T🗸 must be function
T🗸 must have strictly conforming prototype
T🗸 (void)
T🗸 (int, char **)
T🗸 ...or equivalent, expanding typedefs and performing usual parameter conversions
🗸 all other forms rejected
🗸 must have external linkage
T🗸 checked even if no definition is present
🗸 environ declaration
🗸 no restrictions imposed if not POSIX
🗸 POSIX restrictions
T🗸 warn; don't error
🗸 only apply restrictions when
🗸 declaration has external linkage
T🗸 identifier is environ and __asm__ is absent
🗸 ...or __asm__ is "environ"
🗸 don't apply restrictions otherwise
🗸 unqualified type must be compatible with char **
T🗸 no qualifiers present
🗸 qualifiers present
🗸 typedefs permitted
🗸 by the end of translation, declaration should be extern
🗸 can't have definition
preprocessor
T🗸 macro definitions
T🗸 #define
T🗸 variable-like
T🗸 creates macro definition
T🗸 function-like
T🗸 creates macro definition
T🗸 duplicate parameters disallowed
T🗸 shadowing keywords
T🗸 undef
T🗸 shadowing keywords
T🗸 other identifiers
macro substitution
T🗸 pre-defined macros
T🗸 standard
T🗸 constant
T🗸 __STDC__
T🗸 __STDC_HOSTED__
T🗸 special
T🗸 __FILE__
T🗸 __LINE__
X🗸 __DATE__
X🗸 __TIME__
T🗸 non-standard
T🗸 constant
T🗸 target-independent
T🗸 __HARE_C__
T🗸 __ORDER_LITTLE_ENDIAN__
T🗸 __ORDER_BIG_ENDIAN__
T🗸 __ORDER_PDP_ENDIAN__
T🗸 __STRICT_ANSI__
T🗸 target-dependent
T🗸 __BYTE_ORDER__
T🗸 special
T🗸 __BASE_FILE__
T🗸 __COUNTER__
T🗸 __INCLUDE_LEVEL__
T🗸 __FILE_NAME__
X🗸 __TIMESTAMP__
X🗸 __VERSION__
operators
# (%:)
🗸 without whitespace
whitespace is preserved, but collapsed into a single space
🗸 ## (%:%:)
T🗸 with macro arguments
T🗸 only token closest to ## is concatenated
T🗸 when argument expands to no tokens, replace with placemarker
T🗸 with other tokens
🗸 constructs new token
T🗸 non-preprocessing tokens
🗸 constructed token won't be used for preprocessing (i.e. no # or ##)
🗸 # has higher precedence than ##
T🗸 object-like
function-like
T🗸 works when followed by left paren
T🗸 doesn't work when not followed by left paren
parameters
T🗸 expand non-recursively
T🗸 expands macros
T🗸 everything else
T🗸 don't expand recursively
T🗸 from parameters
T🗸 from macros
warn in c90 when argument expands to no tokens
T🗸 recursive
T🗸 macros being expanded can't be expanded again
T🗸 macro can't expand itself
T🗸 macro can't be expanded from within nested expansion
T🗸 everything else expands
#include
T🗸 system headers
T🗸 non-system headers
T🗸 header exists
T🗸 header doesn't exist; fallback to system header
T🗸 header name doesn't have angle brackets
T🗸 header name has angle brackets
T🗸 macro expansion
T🗸 expands into system header
T🗸 expands into non-system header
T🗸 multiple macros may expand into one resource
T🗸 <this> is lexed as a system header string literal
T🗸 true in #include
T🗸 false everywhere else (prior to c23)
warn if header name contains any of ', \, ", //, or /*
🗸 conditional
T🗸 #if, #endif
T🗸 #else
T🗸 #elif
T🗸 defined
T🗸 non-parenthesized identifier
T🗸 paranthesized identifier
T🗸 error out when neither of the above forms is matched
T🗸 #ifdef
T🗸 #ifndef
🗸 evaluation
T🗸 integer constant expressions
🗸 other expressions disallowed
🗸 keywords are treated as regular identifiers
T🗸 all arithmetic has intmax_t range
T🗸 #error
T🗸 errors out
X🗸 error message uses all tokens
X🗸 macros aren't expanded
#warning
actually warns
🗸 warning message uses all tokens
🗸 macros aren't expanded
🗸 backported to all versions
T🗸 #line
T🗸 only change line number
T🗸 also change filename
T🗸 macros are expanded
T🗸 line number may not exceed 2147483647
legacy (c90)
T🗸 trigraphs
k&r-style functions
🗸 empty parameter list
non-empty parameter list without types
TODO: allowed in c90 when k&r declarations aren't present?
k&r-style parameter declarations
parse
only allowed in definitions
every binding must correspond to a parameter
allowed when parameter list doesn't have types
empty parameter list
non-empty parameter list without types
disallowed when parameter list has types
void
more than zero parameters
TODO: are duplicates allowed?
declarations can reference parameters which come later (TODO: do they need to be declared first?)
function type is unchanged (TODO: allowed when another declaration has types in parameter list?)
parameter bindings are given the appropriate type within the function's scope
warns
implicit int
🗸 implicit function declarations
🗸 extern int ()
🗸 happens when first operand of a call expression is an undeclared identifier
T🗸 unparenthesized
🗸 can't be parenthesized
T🗸 warns
T🗸 inserted into current scope
k&r parameter declarations may be omitted
defaults to int
warns
type defaults to int when no type specifiers are present
locations
🗸 file scope
🗸 declarations
🗸 allowed with other specifiers or type qualifiers
T🗸 disallowed without other specifiers or type qualifiers
T🗸 including for non-definition function declarations
🗸 function definitions
🗸 allowed with other specifiers or type qualifiers
T🗸 allowed without other specifiers or type qualifiers
🗸 block scope
🗸 allowed with other specifiers or type qualifiers
🗸 disallowed without other specifiers or type qualifiers
k&r parameter
allowed with other specifiers or type qualifiers
disallowed without other specifiers or type qualifiers
🗸 function parameter
🗸 allowed with other specifiers or type qualifiers
🗸 disallowed without other specifiers or type qualifiers
🗸 struct/union field
🗸 allowed with type qualifiers
🗸 disallowed without type qualifiers
🗸 without bit-field
🗸 with bit-field
🗸 type name
🗸 allowed with type qualifiers
🗸 disallowed without type qualifiers
T🗸 when ambiguous, identifier which is a typedef is treated as a type specifier
warns
🗸 implicit conversion
🗸 pointer->integer
🗸 integer->pointer
pragma
T🗸 #pragma
T🗸 _Pragma
STDC
T🗸 accept standardized
T🗸 FP_CONTRACT
T🗸 FENV_ACCESS
T🗸 CX_LIMITED_RANGE
X🗸 ignored (except for c23 additions)
T🗸 reject nonstandard
valid locations
file-scope, outside of declaration
🗸 allowed
error if contained within declaration, unless in block scope
in effect until pragma state is changed or EOF
beginning of compound statement, preceding all declarations and statements
🗸 allowed
multiple pragmas allowed; last one is used
disallowed anywhere else in compound statement
in effect for compound statement
when compound statement ends, pragma state is restored to what it was prior to entering compound statement
everywhere else disallowed
T🗸 implementation-defined
T🗸 accepted; ignored
🗸 backported to c90
🗸 standard pragmas still don't work until c99
__has_include
backported to all versions
T🗸 c95
T🗸 digraphs
T🗸 __STDC_VERSION__
c99
VLAs
T🗸 parse
T🗸 initialization
T🗸 can't be initialized by non-empty initializer
T🗸 can be initialized by empty initializer
TODO: [*]
hex floating constants
T🗸 prefix / base
parse value
T🗸 exponent
warn if value can't be losslessly represented in its type
universal character names
T🗸 in character constants and string literals
T🗸 parse
T🗸 in identifiers
T🗸 parse
T🗸 c99: conform to annex D (different from c11 annex D)
T🗸 c11, c17: conform to annex D (different from c99 annex D)
T🗸 c23: follow same rules as regular unicode codepoints in identifiers
T🗸 disallowed: (<0xa0 && !='$' && !='@' && !='`') || (>=0xd800 && <0xe000)
preserved when stringizing
T🗸 initializer designators
T🗸 array
T🗸 struct
declaration as for-loop initializer
T🗸 parse
T🗸 must be auto or register
T🗸 default is auto
must not declare new tag
tag may still be declared within expression
🗸 enter scope immediately after declared
T🗸 specifiers
T🗸 type specifiers
T🗸 _Complex
T🗸 _Imaginary
T🗸 errors out
T🗸 long long
inline
T🗸 parse
T🗸 may appear more than once
T🗸 can't be used outside of function declaration
T🗸 applies to function declaration
T🗸 if inline is used on any declaration, there must be a definition
🗸 internally-linked
🗸 can be used on any declaration; no change in behavior
externally-linked; inline definitions
🗸 function becomes inline definition if all file scope declarations use inline
🗸 ...and none explicitly use extern
🗸 otherwise no change in behavior; function isn't an inline definition
🗸 inline definition doesn't provide external definition
constraints
may not define a modifiable object with static or thread duration
may not use identifier with internal linkage
T🗸 static array qualifier
T🗸 allowed in function parameter
T🗸 disallowed everywhere else
T🗸 length must be provided
T🗸 restrict
T🗸 parse
T🗸 restrictions on use (pun intended i think actually no it wasn't i lied)
T🗸 allowed on pointer to object type
T🗸 allowed on array of allowed type
T🗸 disallowed on non-array non-pointer types
T🗸 disallowed on pointer to function type
T🗸 disallowed on array of disallowed type
T🗸 variadic macros
T🗸 use of ... in definition
T🗸 __VA_ARGS__
T🗸 allowed in variadic macro definition
T🗸 disallowed everywhere else
T🗸 argument list must be preceded by comma
T🗸 intermixing declarations and statements in compound statements
T🗸 ll integer constant suffix
T🗸 __func__
T🗸 parse
T🗸 resolves to name of current function
T🗸 can't be redeclared at top-level
T🗸 has type 'const char []'
🗸 implicit return 0 from main
T🗸 for hosted targets
🗸 not for freestanding targets
incomplete array struct member
T🗸 allowed when it's the final member and other members are present
T🗸 disallowed otherwise
T🗸 not allowed in union
T🗸 struct type is still complete; size is as though incomplete array wasn't present
T🗸 but struct type can't be use in other structs or arrays
T🗸 including if it's (recursively) a member of a union
initialization in struct literal
🗸 can be initialized when object has static storage duration
can't be initialized otherwise
T🗸 pre-defined macros
T🗸 __STDC_ISO_10646__
compound initializers/literals
T🗸 compound literals
T🗸 parse
T🗸 check
T🗸 type can't be VLA
T🗸 designators
T🗸 parse
T🗸 none
T🗸 array
T🗸 struct
T🗸 check
T🗸 none
T🗸 array
T🗸 struct
T🗸 multiple designators per object element may be given
T🗸 designators may be combined
duplicate designators
🗸 final object overwrites all previous objects
warns
warn when multiple designators for the same union are given
excluding embedded structs
c11
specifiers
T🗸 _Thread_local
T🗸 parse
T🗸 may not appear alongside auto or register
T🗸 may not appear in block scope when no storage-class specifiers are present
T🗸 may not be used on function declaration
T🗸 must appear on all declarations of an object
_Noreturn
T🗸 parse
T🗸 may appear more than once
applies to function declaration
T🗸 can't be used outside of function declaration
information persists in check
warnings
T🗸 warn when return type isn't void
warn when called in an expression which isn't a statement
_Alignas
🗸 expression
🗸 type
duplicates permitted; most strict alignment used
invalid uses
alongside typedef/register specifier
on function
on bit-field
must not specify less strict alignment than default
redeclarations
first declaration has alignment specifier
redeclarations may omit alignment specifier
redeclarations with alignment specifier must specify same alignment
error when redeclarations explicitly specify different alignment
even if effective alignment would be the same
first declaration doesn't have alignment specifier
redeclarations must also not have alignment specifier
_Atomic
as specifier
parse
type in parens must not be qualified
type in parens must not be array or function
type in parens must not be atomic
T🗸 as qualifier
T🗸 parse
T🗸 errors out in check
T🗸 _Static_assert
T🗸 parse
T🗸 top-level
T🗸 within function
T🗸 within struct/union
T🗸 eval
T🗸 top-level
T🗸 within function
T🗸 within struct/union
T🗸 errors out when condition is false
T🗸 _Alignof
T🗸 parse
X🗸 operand isn't evaluated, even if variably modified
T🗸 operand must be complete object
🗸 _Generic
T🗸 parse
T🗸 controlling expression conversions
T🗸 lvalue conversion
T🗸 array -> pointer
T🗸 function -> function pointer
T🗸 must match exactly one case
T🗸 at most one compatible case
T🗸 at most one default case allowed
T🗸 if no compatible case, default case must be present
T🗸 each non-default case must specify a non-variably-modified object type
🗸 warnings
🗸 no warnings when operand is type
T🗸 operand is expression
T🗸 case is qualified
T🗸 case is array
T🗸 prefixes
T🗸 character constants
T🗸 u8-
T🗸 u-
T🗸 U-
T🗸 string literals
T🗸 u-
T🗸 U-
T🗸 nested anonymous structs/unions
T🗸 pre-defined macros
T🗸 __STDC_IEC_559__
T🗸 __STDC_UTF_16__
T🗸 __STDC_UTF_32__
c23
T🗸 unicode
T🗸 identifiers (without universal character names)
T🗸 universal character names must be less than U+110000
specifiers
🗸 _BitInt
T🗸 signed
T🗸 parse
T🗸 unsigned
T🗸 parse
T🗸 wb integer constant suffix
T🗸 operand must be integer constant expression
T🗸 signed width must be >= 2
T🗸 unsigned width must be >= 1
T🗸 doesn't undergo integer promotion
🗸 has rank below equivalently sized basic integer type
🗸 otherwise ranked based on width of both types
typeof
T🗸 qualified (typeof)
T🗸 unqualified (typeof_unqual)
T🗸 with expression argument
T🗸 with type name argument
X🗸 operand isn't evaluated if not variably modified
operand is evaluated if variably modified
operand must not be bit-field
T🗸 decimal types
T🗸 _Decimal32
T🗸 type specifier
T🗸 df suffix
T🗸 _Decimal64
T🗸 type specifier
T🗸 dd suffix
T🗸 _Decimal128
T🗸 type specifier
T🗸 dl suffix
constexpr
🗸 parse
check
🗸 type
T🗸 implicitly qualified as const
T🗸 must be object (not function)
T🗸 must not be variably modified
🗸 must not be volatile or restrict qualified
T🗸 constraint applies to type itself
🗸 constraint applies recursively to subtypes
initializer
T🗸 must be provided
T🗸 must be constant expression
constraints
value must be exactly representable in type
T🗸 integer
floating-point type
binary
real
complex
decimal
T🗸 pointer initializer must be null pointer
T🗸 integer initializer must be integer constant expression
🗸 arithmetic initializer must be arithmetic constant expression
T🗸 real float initializer must have integer or real float type
T🗸 decimal float initializer must have decimal float type
constraints apply recursively to subobjects
preprocessor
#embed
system embeds
non-system embeds
embed exists
embed doesn't exist; fallback to system header
embed name doesn't have angle brackets
embed name has angle brackets
parameters
standard
if_empty
limit
prefix
suffix
vendor-specific
gnu::offset
warn for other non-standard parameters
duplicates not permitted
leading+trailing underscores permitted
🗸 macro expansion
🗸 expands into system embed
🗸 expands into non-system embed
🗸 multiple macros may expand into one resource
🗸 only expand if the unexpanded tokens have a syntax error
🗸 <this> is lexed as a system header string literal
`defined` token prohibited
warn if header name contains any of ', \, ", //, or /*
__VA_OPT__
allowed in variadic macro definition
T🗸 disallowed everywhere else
T🗸 comma before variadic macro arguments can be omitted when there's no argument list
T🗸 #elifdef, #elifndef
standard pragmas
FENV_ROUND
🗸 value must be direction
eval
information persists in check
FENV_DEC_ROUND
🗸 value must be dec-direction
eval
information persists in check
T🗸 static_assert without reason
T🗸 type inference with auto
T🗸 parse
T🗸 infers type
T🗸 initializer must be provided
T🗸 compound initializer disallowed
T🗸 array/function initializer is converted to pointer
T🗸 declaration inserted into scope immediately after declared, but can't be used
T🗸 can't be used on function definition
T🗸 must have exactly one declarator
T🗸 must be direct declarator
T🗸 can't be used alongside other storage-class specifiers
X🗸 can't be used alongside __auto_type
T🗸 can be used alongside qualifiers
T🗸 can be followed by attributes
T🗸 only usable on bindings
T🗸 not function parameters
T🗸 not struct/union fields
T🗸 not type names
T🗸 nullptr
T🗸 labels
T🗸 labelled declarations
T🗸 at end of compound statement
T🗸 binary integer constants
T🗸 parse value
T🗸 function declarations
T🗸 variadic function without parameters
T🗸 parameters in function definition need not be named
attributes
locations
T🗸 declaration
T🗸 top-level
T🗸 bindings
T🗸 function definitions
T🗸 as a declaration consisting of only attributes and nothing else
T🗸 within compound body
T🗸 for-loop initializer
T🗸 function parameter
T🗸 struct/union fields
T🗸 attribute declaration
T🗸 attribute list followed by semicolon, as though null statement
T🗸 only allowed where declarations are allowed
T🗸 binding
T🗸 base type
T🗸 declarator
T🗸 array
T🗸 function
T🗸 pointer
T🗸 with identifier
T🗸 without identifier
struct/union/enum declaration
T🗸 parse
allowed when defining struct/union/enum
allowed in tag declaration where struct/union doesn't act as type specifier
doesn't apply to enums since they can't be forward declared
disallowed otherwise
T🗸 enum field
T🗸 statement
T🗸 non-null statements
T🗸 can't be on null statement (that makes it an attribute declaration)
standard
attributes
T🗸 [[noreturn]], [[_Noreturn]]
T🗸 disallow argument
T🗸 applicable to
T🗸 function declaration
T🗸 nothing else
T🗸 behaves equivalently to _Noreturn
[[deprecated]]
may have optional argument
applicable to
struct/union declaration
typedef declaration
object declaration
struct/union member
function declaration
enum
enum member
nothing else
warn when name is used
[[fallthrough]]
T🗸 disallow argument
applicable to
T🗸 attribute declaration
nothing else
T🗸 must only appear in switch body
🗸 next encountered statement must have case or default label
🗸 next encountered statement must appear within same switch body
🗸 if within iteration statement, next statement must also be within said iteration statement
[[maybe_unused]]
disallow argument
applicable to
struct/union declaration
typedef declaration
object declaration
struct/union member
function declaration
enum
enum member
label
nothing else
[[nodiscard]]
may have optional argument
applicable to
function declaration
struct/union definition
enum definition
nothing else
warn when value discarded
[[reproducible]]
disallow argument
applicable to
function declarator
type specifier with function type
warn when returns void
[[unsequenced]]
disallow argument
applicable to
function declarator
type specifier with function type
warn when returns void
T🗸 __has_c_attribute => 202311L
non-standard
warn
T🗸 __has_c_attribute => 0L
T🗸 leading+trailing underscores permitted
T🗸 keywords are treated as identifiers
T🗸 with prefix
T🗸 without prefix
T🗸 without arguments
T🗸 with arguments
T🗸 including balanced tokens
T🗸 multiple attribute lists are combined
T🗸 multiple attributes in [[brackets]]
T🗸 u8- string literals
T🗸 empty initializers
T🗸 parse
T🗸 scalar types
T🗸 array types
T🗸 allowed for complete array types
T🗸 disallowed for incomplete array types
T🗸 as initializer
T🗸 in compound literal
T🗸 struct types
T🗸 union types
T🗸 ' as separator
T🗸 integer constants
T🗸 floating constants
T🗸 empty declarations
pre-defined macros
keyword aliases
🗸 alignas
T🗸 alignof
T🗸 bool
T🗸 true
T🗸 defined
T🗸 expands to _Bool value
T🗸 false
T🗸 defined
T🗸 expands to _Bool value
T🗸 static_assert
T🗸 thread_local
when equivalent keyword is re-defined, alias macro doesn't expand said definition (TODO: maybe just don't bother with this?)
T🗸 __has_c_attribute
__has_embed
T🗸 constants
T🗸 __STDC_EMBED_NOT_FOUND__
T🗸 __STDC_EMBED_FOUND__
T🗸 __STDC_EMBED_EMPTY__
enum
explicit enumerated type
T🗸 parse
check
T🗸 explicitly specified type is used as enumerated type
T🗸 type constraints
T🗸 must be integer type
T🗸 can't be bit-precise
T🗸 can't be enum
T🗸 qualifiers are discarded
T🗸 enum type is completed immediately after explicitly specified type is parsed
T🗸 forward declarations
T🗸 allowed when not used as type specifier (i.e. nothing else is declared)
T🗸 disallowed when used as type specifier
multiple declarations of the same enum tag
explicit enumerated type must be provided by either all declarations or none
explicit enumerated type need not be (and can't be) provided when enum without definition is used as type specifier
T🗸 the enumerated types must all be compatible
T🗸 error if value would be implicitly truncated
T🗸 with initializer
T🗸 without initializer
T🗸 other type additions/changes
T🗸 implicit enumerated type
T🗸 order is (un)signed int, (un)signed long, (un)signed long long
T🗸 enumeration member type
T🗸 with implicit enumerated type
T🗸 within enum definition (each individual member)
T🗸 type is int if representable
T🗸 otherwise, if there's an initializer, type is that of the initializer
T🗸 otherwise, type is basic integer type with the same signedness as the previous member, whose rank is the minimum which isn't smaller than that of the previous member but which can represent the new implicit value
T🗸 error if no suitable type exists
T🗸 after enum is defined (all members collectively)
T🗸 type is int if all representable
T🗸 otherwise, type is the same as the enumerated type
T🗸 with explicit enumerated type
T🗸 type is the same as the enumerated type
T🗸 within enum definition
T🗸 after enum is defined
T🗸 storage-class specifiers in compound literals
T🗸 allowed
T🗸 disallowed for cast expressions
T🗸 treat empty parameter list as identical to (void)
🗸 c2y
🗸 unary increment/decrement operand can have complex type
🗸 _Generic with type operand
T🗸 parse
🗸 doesn't undergo lvalue or pointer conversion
🗸 cases can be function types
🗸 cases can be incomplete
🗸 cases still can't be variably modified
🗸 alignof can take alignment of incomplete array type
🗸 pre-defined macros
🗸 __STDC_IEC_60559_COMPLEX__
T🗸 _Imaginary is no longer a keyword
extensions
preprocessor
redefinition of macros
T🗸 user-defined
T🗸 pre-defined
warns when new definition isn't identical to old
doesn't warn when new definition is identical
X🗸 __DATE__ and __TIME__ use SOURCE_DATE_EPOCH if set
T🗸 __has_attribute
linemarkers
builtin identifiers
T🗸 can't be redeclared at top-level
__builtin_offsetof
T🗸 parse
check
can't be used on bit-fields
T🗸 can be used on non-bit-fields
__builtin_pp_embed
T🗸 parse
check
warnings and errors
error when type isn't a character type
__builtin_unreachable
T🗸 parse
T🗸 persists in check
warnings and errors
warn when used as an expression
T🗸 __builtin_va_arg
T🗸 parse
X🗸 check
T🗸 warnings and errors
T🗸 when type name can't be made a pointer by postfixing it with *
T🗸 warn before c23
T🗸 no diagnostic since c23
T🗸 error when type name is an array type or function type
T🗸 error when type name is an incomplete type
T🗸 error when first argument isn't a va_list
T🗸 __builtin_va_copy
T🗸 parse
X🗸 check
T🗸 warnings and errors
T🗸 error when arguments aren't both va_lists
T🗸 __builtin_va_end
T🗸 parse
X🗸 check
T🗸 warnings and errors
T🗸 error when argument isn't a va_list
T🗸 __builtin_va_list
T🗸 parse
X🗸 check
__builtin_va_start
🗸 parse
🗸 second argument must be identifier before c23
🗸 second argument must be identifier or integer constant 0 after c23
X🗸 check
warnings and errors
T🗸 error when function isn't variadic
T🗸 last named parameter has register storage-class specifier
T🗸 warn before c23
T🗸 no diagnostic since c23
TODO: last named parameter is declared as array type or function type?
T🗸 last named parameter's type is incompatible with type after default argument promotion
T🗸 disallowed types
T🗸 integer type ranked lower than int
T🗸 float
T🗸 warn before c23
T🗸 no diagnostic since c23
optional argument isn't the last named function parameter
error before c23
warn since c23
__asm__
declarations
T🗸 parse
T🗸 disallowed on function definition
T🗸 disallowed for struct/union fields
T🗸 no other restrictions
T🗸 empty string unparses correctly
T🗸 trigraph-like character sequences are escaped when unparsed (prior to c23)
check
T🗸 allowed declarations
T🗸 internal or external linkage
T🗸 register storage-class
T🗸 disallowed otherwise
T🗸 empty symbol disallowed
T🗸 no other restrictions imposed on symbol
T🗸 duplicate declarations must agree on symbol (if present)
TODO: what's the deal with main?
statements
basic
outside function
🗸 parse
check
inside function
🗸 parse
check
🗸 string is interpreted literally, without % escapes
🗸 don't check as format string
extended
🗸 parse
check
🗸 only allowed inside function
🗸 double colons are separated into two single colons
🗸 qualifiers
🗸 goto
🗸 inline (or __inline__)
🗸 volatile
% escapes in format string are checked
%n (n = number)
operands are numbered starting at zero
operands with symbolic names are also numbered
error when no operand corresponds to the given number
%[symbolic_name]
%=
replaced with number unique to __asm__ statement
multiple assembler dialects
{foo|bar|baz}
may supply only one dialect
can't be nested
escapes within braces are recognized
escape special characters
%%
%{
%|
%}
🗸 output operands
🗸 parse
🗸 expression must be a mutable lvalue
🗸 input operands
🗸 parse
🗸 clobbers
🗸 parse
🗸 goto labels
🗸 parse
🗸 all identifiers must be valid goto labels in current function scope
🗸 at least one label must be provided
🗸 labels can't be provided if goto qualifier isn't used
🗸 labels must be provided if goto qualifier is used
🗸 no two operands can share a symbolic name
check constraint syntax
T🗸 casting between object pointer and function pointer
T🗸 errors
T🗸 when POSIX_C isn't used
T🗸 no diagnostic otherwise
X🗸 does the Right Thing
__attribute__
🗸 locations
🗸 within specifier/qualifier list
🗸 declaration
T🗸 parse
T🗸 binding
T🗸 file scope
T🗸 block scope
T🗸 function parameter
T🗸 struct/union field
T🗸 disallowed for static_assert
T🗸 file scope
T🗸 block scope
T🗸 allowed for [[attribute]] declaration
T🗸 file scope
T🗸 block scope
🗸 always applies only here when ambiguous
T🗸 disallowed without other specifiers
T🗸 even prior to c99
T🗸 type name
T🗸 parse
T🗸 without other specifiers
T🗸 prior to c99
T🗸 allowed outside of function parameters
T🗸 disallowed for function parameters
T🗸 disallowed since c99
🗸 binding
🗸 before declarator
T🗸 disallowed on first declarator
🗸 allowed for subsequent declarators
T🗸 after declarator
T🗸 parse
T🗸 must go after __asm__ if present
T🗸 disallowed in function definition
T🗸 struct/union/enum
T🗸 parse
T🗸 after struct/union/enum token
T🗸 after closing brace
T🗸 always applies only here when ambiguous
T🗸 enum field
T🗸 null statement
T🗸 parse
T🗸 only if not labelled
T🗸 must precede any standard attributes
T🗸 standard attributes only allowed where declaration would be allowed
T🗸 label
T🗸 parse
T🗸 disallowed with case and default
T🗸 always applies only here when ambiguous
T🗸 declarator
T🗸 locations within declarator
T🗸 after *
T🗸 parenthesized, before nested declarator
T🗸 parse
T🗸 `(__attribute__` always begins function declarator, not nested declarator
T🗸 even if it would parse if interpreted as nested declarator, still error out
T🗸 alongside qualifiers within array brackets
T🗸 application
T🗸 to declarator
T🗸 to base type
T🗸 parse
warn for unrecognized attributes
supported attributes
T🗸 noreturn, _Noreturn
T🗸 behaves equivalently to [[noreturn]]
alias
aligned
always_inline
error when argument used
applicable to
function declaration
nothing else
must be used alongside inline specifier
information persists in check
const
behaves equivalently to [[unsequenced]]
...but also applicable to function declaration
deprecated
behaves equivalently to [[deprecated]]
🗸 fallthrough
🗸 behaves equivalently to [[fallthrough]]
🗸 applicable to null statement
format
arguments
must be exactly three
archetype
must be one of printf, scanf, strftime, or strfmon
string-index
must be integer constant (TODO?)
must refer to `const char *` parameter (1-indexed) (TODO: unqualified `char *`?)
first-to-check
must be integer constant (TODO?)
allowed values
index of valid (possibly variadic) parameter (1-indexed)
0
arguments aren't available to check
other values disallowed
warnings
invalid format string
printf
scanf
strftime
strfmon
invalid arguments
gnu_inline
error when argument used
applicable to
function declaration
nothing else
must be used alongside inline specifier
must appear in all declarations of same function
causes behavior for no storage-class specifier / extern to be flipped
INLINE if extern everywhere, otherwise STATIC_EXTERNAL_DEFN
noinline
error when argument used
applicable to
function declaration
nothing else
error when used with inline specifier
in same declaration
in other redeclaration
information persists in check
noipa
error when argument used
applicable to
function declaration
nothing else
error when used with inline specifier
in same declaration
in other redeclaration
information persists in check
nonnull
packed
error when argument used
applicable to
T🗸 struct
struct field
union
union field
nothing else
T🗸 check
T🗸 TODO: write shit here
pure
behaves equivalently to [[reproducible]]
...but also applicable to function declaration
returns_nonnull
error when argument used
applicable to
function declaration
nothing else
function must return pointer type
warn if return statement in function returns null pointer constant or constant expression with value null
section
unavailable
may have optional argument
applicable to
declaration
nothing else
error whenever the declaration is used
don't error when redeclared
don't emit(?)
unused
behaves equivalently to [[maybe_unused]]
used
error when argument used
applicable to
declaration
nothing else
persists in check
silences unused declaration warning
visibility
weak
T🗸 attributes may also be used as c23 attributes with gnu:: prefix
T🗸 leading+trailing underscores permitted
T🗸 __inline__
T🗸 equivalent to inline, except allowed in all versions
T🗸 __typeof__
T🗸 equivalent to typeof, except allowed in all versions
T🗸 __typeof_unqual__
T🗸 equivalent to typeof_unqual, except allowed in all versions
T🗸 imaginary constants
T🗸 have complex type
T🗸 suffixes
T🗸 i
T🗸 j
T🗸 supported after c99
T🗸 not supported before c99
T🗸 __auto_type
T🗸 parse
T🗸 same semantics as c23 type inference in check, except allowed in all versions
T🗸 duplicate __auto_type specifiers disallowed
additional warnings
SOURCE_DATE_EPOCH is invalid
unused internally-linked objects and functions
statement follows statement which manipulates control flow or won't return
statement being followed
T🗸 break
T🗸 continue
T🗸 goto
T🗸 return
noreturn function call
T🗸 __builtin_unreachable()
T🗸 potentially labelled
T🗸 compound whose last non-unlabelled-null statement is any of these
T🗸 nothing else
following statement
T🗸 warn if
T🗸 statement which isn't included in "don't warn if" below
T🗸 bindings or tag declaration
fallthrough attribute declaration
T🗸 [[fallthrough]]
__attribute__((fallthrough))
don't warn if
T🗸 null statement
T🗸 warn for following statements which fit the requirements
T🗸 labelled statement
T🗸 don't warn for following statements
T🗸 __builtin_unreachable() expression
T🗸 continue to warn for following statements which fit the requirements
T🗸 static assertion
T🗸 warn for following statements which fit the requirements
nonstandard (non-fallthrough) attribute declaration
T🗸 standard attributes
gnu-style attributes
T🗸 don't warn for following statements