| @@ -1,86 +1,119 @@ | | | @@ -1,86 +1,119 @@ |
1 | /* $NetBSD: gcc_attribute.c,v 1.8 2021/07/06 18:43:27 rillig Exp $ */ | | 1 | /* $NetBSD: gcc_attribute.c,v 1.9 2021/07/09 18:55:28 rillig Exp $ */ |
2 | # 3 "gcc_attribute.c" | | 2 | # 3 "gcc_attribute.c" |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Tests for the various attributes for functions, types, statements that are | | 5 | * Tests for the various attributes for functions, types, statements that are |
6 | * provided by GCC. | | 6 | * provided by GCC. |
7 | * | | 7 | * |
8 | * https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html | | 8 | * https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html |
9 | */ | | 9 | */ |
10 | | | 10 | |
11 | void __attribute__((noinline)) | | 11 | void __attribute__((noinline)) |
12 | do_not_inline(void) | | 12 | do_not_inline(void) |
13 | { | | 13 | { |
14 | } | | 14 | } |
15 | | | 15 | |
16 | /* All pointer arguments must be nonnull. */ | | 16 | /* All pointer arguments must be nonnull. */ |
17 | void __attribute__((nonnull)) | | 17 | void __attribute__((nonnull)) |
18 | function_nonnull(void *, const void *, int); | | 18 | function_nonnull(void *, const void *, int); |
19 | | | 19 | |
20 | /* | | 20 | /* |
21 | * The documentation suggests that the argument list of nonnull be nonempty, | | 21 | * The documentation suggests that the argument list of nonnull be nonempty, |
22 | * but GCC 9.3.0 accepts an empty list as well, treating all parameters as | | 22 | * but GCC 9.3.0 accepts an empty list as well, treating all parameters as |
23 | * nonnull. | | 23 | * nonnull. |
24 | */ | | 24 | */ |
25 | void __attribute__((nonnull())) | | 25 | void __attribute__((nonnull())) |
26 | function_nonnull_list(void *, const void *, int); | | 26 | function_nonnull_list(void *, const void *, int); |
27 | | | 27 | |
28 | /* Arguments 1 and 2 must be nonnull. */ | | 28 | /* Arguments 1 and 2 must be nonnull. */ |
29 | void __attribute__((nonnull(1, 2))) | | 29 | void __attribute__((nonnull(1, 2))) |
30 | function_nonnull_list(void *, const void *, int); | | 30 | function_nonnull_list(void *, const void *, int); |
31 | | | 31 | |
32 | /* expect+1: syntax error 'unknown_attribute' */ | | 32 | /* expect+1: syntax error 'unknown_attribute' */ |
33 | void __attribute__((unknown_attribute)) | | 33 | void __attribute__((unknown_attribute)) |
34 | function_with_unknown_attribute(void); | | 34 | function_with_unknown_attribute(void); |
35 | | | 35 | |
36 | /* | | 36 | /* |
37 | * There is an attribute called 'pcs', but that attribute must not prevent an | | 37 | * There is an attribute called 'pcs', but that attribute must not prevent an |
38 | * ordinary variable from being named the same. Starting with scan.l 1.77 | | 38 | * ordinary variable from being named the same. Starting with scan.l 1.77 |
39 | * from 2017-01-07, that variable name generated a syntax error. Fixed in | | 39 | * from 2017-01-07, that variable name generated a syntax error. Fixed in |
40 | * lex.c 1.33 from 2021-05-03. | | 40 | * lex.c 1.33 from 2021-05-03. |
41 | * | | 41 | * |
42 | * Seen in yds.c, function yds_allocate_slots. | | 42 | * Seen in yds.c, function yds_allocate_slots. |
43 | */ | | 43 | */ |
44 | int | | 44 | int |
45 | local_variable_pcs(void) | | 45 | local_variable_pcs(void) |
46 | { | | 46 | { |
47 | int pcs = 3; | | 47 | int pcs = 3; |
48 | return pcs; | | 48 | return pcs; |
49 | } | | 49 | } |
50 | | | 50 | |
51 | /* | | 51 | /* |
52 | * FIXME: The attributes are handled by different grammar rules even though | | 52 | * FIXME: The attributes are handled by different grammar rules even though |
53 | * they occur in the same syntactical position. | | 53 | * they occur in the same syntactical position. |
54 | * | | 54 | * |
55 | * Grammar rule abstract_decl_param_list handles the first attribute. | | 55 | * Grammar rule abstract_decl_param_list handles the first attribute. |
56 | * | | 56 | * |
57 | * Grammar rule direct_abstract_declarator handles all remaining attributes. | | 57 | * Grammar rule direct_abstract_declarator handles all remaining attributes. |
58 | * | | 58 | * |
59 | * Since abstract_decl_param_list contains type_attribute_opt, this could be | | 59 | * Since abstract_decl_param_list contains type_attribute_opt, this could be |
60 | * the source of the many shift/reduce conflicts in the grammar. | | 60 | * the source of the many shift/reduce conflicts in the grammar. |
61 | */ | | 61 | */ |
62 | int | | 62 | int |
63 | func( | | 63 | func( |
64 | int(int) | | 64 | int(int) |
65 | __attribute__((__noreturn__)) | | 65 | __attribute__((__noreturn__)) |
66 | __attribute__((__noreturn__)) | | 66 | __attribute__((__noreturn__)) |
67 | ); | | 67 | ); |
68 | | | 68 | |
69 | /* | | 69 | /* |
70 | * https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html says that the | | 70 | * https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html says that the |
71 | * attribute-list is a "possibly empty comma-separated sequence of | | 71 | * attribute-list is a "possibly empty comma-separated sequence of |
72 | * attributes". | | 72 | * attributes". |
73 | * | | 73 | * |
74 | * No matter whether this particular example is interpreted as an empty list | | 74 | * No matter whether this particular example is interpreted as an empty list |
75 | * or a list containing a single empty attribute, the result is the same in | | 75 | * or a list containing a single empty attribute, the result is the same in |
76 | * both cases. | | 76 | * both cases. |
77 | */ | | 77 | */ |
78 | void one_empty_attribute(void) | | 78 | void one_empty_attribute(void) |
79 | __attribute__((/* none */)); | | 79 | __attribute__((/* none */)); |
80 | | | 80 | |
81 | /* | | 81 | /* |
82 | * https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html further says that | | 82 | * https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html further says that |
83 | * each individual attribute may be "Empty. Empty attributes are ignored". | | 83 | * each individual attribute may be "Empty. Empty attributes are ignored". |
84 | */ | | 84 | */ |
85 | void two_empty_attributes(void) | | 85 | void two_empty_attributes(void) |
86 | __attribute__((/* none */, /* still none */)); | | 86 | __attribute__((/* none */, /* still none */)); |
| | | 87 | |
| | | 88 | /* |
| | | 89 | * Ensure that __attribute__ can be specified everywhere in a declaration. |
| | | 90 | * This is the simplest possible requirement that covers all valid code. |
| | | 91 | * It accepts invalid code as well, but these cases are covered by GCC and |
| | | 92 | * Clang already. |
| | | 93 | * |
| | | 94 | * Since lint only parses the attributes but doesn't really relate them to |
| | | 95 | * identifiers or other entities, ensuring that valid code can be parsed is |
| | | 96 | * enough for now. |
| | | 97 | * |
| | | 98 | * To really associate __attribute__ with the corresponding entity, the |
| | | 99 | * grammar needs to be rewritten, see the example with __noreturn__ above. |
| | | 100 | */ |
| | | 101 | __attribute__((deprecated("d1"))) |
| | | 102 | const |
| | | 103 | __attribute__((deprecated("d2"))) |
| | | 104 | int |
| | | 105 | __attribute__((deprecated("d3"))) |
| | | 106 | * |
| | | 107 | // The below line would produce a syntax error. |
| | | 108 | // __attribute__((deprecated("d3"))) |
| | | 109 | const |
| | | 110 | __attribute__((deprecated("d4"))) |
| | | 111 | identifier |
| | | 112 | __attribute__((deprecated("d5"))) |
| | | 113 | ( |
| | | 114 | __attribute__((deprecated("d6"))) |
| | | 115 | void |
| | | 116 | __attribute__((deprecated("d7"))) |
| | | 117 | ) |
| | | 118 | __attribute__((deprecated("d8"))) |
| | | 119 | ; |