| 1 | // RUN: %clang_cc1 -std=c99 -fsyntax-only -verify %s |
| 2 | // RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify %s |
| 3 | // RUN: %clang_cc1 -std=c99 -fno-signed-char -fsyntax-only -verify %s |
| 4 | |
| 5 | struct A {}; |
| 6 | |
| 7 | typedef struct A *MPI_Datatype; |
| 8 | |
| 9 | int wrong1(void *buf, MPI_Datatype datatype) |
| 10 | __attribute__(( pointer_with_type_tag )); // expected-error {{'pointer_with_type_tag' attribute requires exactly 3 arguments}} |
| 11 | |
| 12 | int wrong2(void *buf, MPI_Datatype datatype) |
| 13 | __attribute__(( pointer_with_type_tag(mpi,0,7) )); // expected-error {{attribute parameter 2 is out of bounds}} |
| 14 | |
| 15 | int wrong3(void *buf, MPI_Datatype datatype) |
| 16 | __attribute__(( pointer_with_type_tag(mpi,3,7) )); // expected-error {{attribute parameter 2 is out of bounds}} |
| 17 | |
| 18 | int wrong4(void *buf, MPI_Datatype datatype) |
| 19 | __attribute__(( pointer_with_type_tag(mpi,1,0) )); // expected-error {{attribute parameter 3 is out of bounds}} |
| 20 | |
| 21 | int wrong5(void *buf, MPI_Datatype datatype) |
| 22 | __attribute__(( pointer_with_type_tag(mpi,1,3) )); // expected-error {{attribute parameter 3 is out of bounds}} |
| 23 | |
| 24 | int wrong6(void *buf, MPI_Datatype datatype) |
| 25 | __attribute__(( pointer_with_type_tag(mpi,0x8000000000000001ULL,1) )); // expected-error {{attribute parameter 2 is out of bounds}} |
| 26 | |
| 27 | extern int x; |
| 28 | |
| 29 | int wrong7(void *buf, MPI_Datatype datatype) |
| 30 | __attribute__(( pointer_with_type_tag(mpi,x,2) )); // expected-error {{attribute requires parameter 2 to be an integer constant}} |
| 31 | |
| 32 | int wrong8(void *buf, MPI_Datatype datatype) |
| 33 | __attribute__(( pointer_with_type_tag(mpi,1,x) )); // expected-error {{attribute requires parameter 3 to be an integer constant}} |
| 34 | |
| 35 | int wrong9 __attribute__(( pointer_with_type_tag(mpi,1,2) )); // expected-error {{'pointer_with_type_tag' attribute only applies to non-K&R-style functions}} |
| 36 | |
| 37 | int wrong10(double buf, MPI_Datatype type) |
| 38 | __attribute__(( pointer_with_type_tag(mpi,1,2) )); // expected-error {{'pointer_with_type_tag' attribute only applies to pointer arguments}} |
| 39 | |
| 40 | int ok11(void *, ...) |
| 41 | __attribute__(( pointer_with_type_tag(mpi,1,2) )); |
| 42 | int wrong11(void *, ...) |
| 43 | __attribute__(( pointer_with_type_tag(mpi,2,3) )); // expected-error {{'pointer_with_type_tag' attribute only applies to pointer arguments}} |
| 44 | |
| 45 | extern struct A datatype_wrong1 |
| 46 | __attribute__(( type_tag_for_datatype )); // expected-error {{'type_tag_for_datatype' attribute requires parameter 1 to be an identifier}} |
| 47 | |
| 48 | extern struct A datatype_wrong2 |
| 49 | __attribute__(( type_tag_for_datatype(mpi,1,2) )); // expected-error {{expected a type}} |
| 50 | |
| 51 | extern struct A datatype_wrong3 |
| 52 | __attribute__(( type_tag_for_datatype(mpi,not_a_type) )); // expected-error {{unknown type name 'not_a_type'}} |
| 53 | |
| 54 | extern struct A datatype_wrong4 |
| 55 | __attribute__(( type_tag_for_datatype(mpi,int,int) )); // expected-error {{expected identifier}} |
| 56 | |
| 57 | extern struct A datatype_wrong5 |
| 58 | __attribute__(( type_tag_for_datatype(mpi,int,not_a_flag) )); // expected-error {{invalid comparison flag 'not_a_flag'}} |
| 59 | |
| 60 | extern struct A datatype_wrong6 |
| 61 | __attribute__(( type_tag_for_datatype(mpi,int,layout_compatible,not_a_flag) )); // expected-error {{invalid comparison flag 'not_a_flag'}} |
| 62 | |
| 63 | |
| 64 | void datatype_wrong7(void) __attribute__((type_tag_for_datatype(datatype_wrong7, int))); // expected-error {{'type_tag_for_datatype' attribute only applies to variables}} |
| 65 | |
| 66 | // Using a tag with kind A in a place where the function requires kind B should |
| 67 | // warn. |
| 68 | |
| 69 | void A_func(void *ptr, void *tag) __attribute__(( pointer_with_type_tag(a,1,2) )); |
| 70 | |
| 71 | extern struct A A_tag __attribute__(( type_tag_for_datatype(a,int) )); |
| 72 | extern struct A B_tag __attribute__(( type_tag_for_datatype(b,int) )); |
| 73 | |
| 74 | void C_func(void *ptr, int tag) __attribute__(( pointer_with_type_tag(c,1,2) )); |
| 75 | |
| 76 | static const int C_tag __attribute__(( type_tag_for_datatype(c,int) )) = 10; |
| 77 | static const int D_tag __attribute__(( type_tag_for_datatype(d,int) )) = 20; |
| 78 | |
| 79 | void test_tag_mismatch(int *ptr) |
| 80 | { |
| 81 | A_func(ptr, &A_tag); // no-warning |
| 82 | A_func(ptr, &B_tag); // expected-warning {{this type tag was not designed to be used with this function}} |
| 83 | C_func(ptr, C_tag); // no-warning |
| 84 | C_func(ptr, D_tag); // expected-warning {{this type tag was not designed to be used with this function}} |
| 85 | C_func(ptr, 10); // no-warning |
| 86 | C_func(ptr, 20); // should warn, but may cause false positives |
| 87 | } |
| 88 | |
| 89 | void test_null_pointer() |
| 90 | { |
| 91 | C_func(0, C_tag); // no-warning |
| 92 | C_func((void *) 0, C_tag); // no-warning |
| 93 | C_func((int *) 0, C_tag); // no-warning |
| 94 | C_func((long *) 0, C_tag); // expected-warning {{argument type 'long *' doesn't match specified 'c' type tag that requires 'int *'}} |
| 95 | } |
| 96 | |
| 97 | // Check that we look through typedefs in the special case of allowing 'char' |
| 98 | // to be matched with 'signed char' or 'unsigned char'. |
| 99 | void E_func(void *ptr, int tag) __attribute__(( pointer_with_type_tag(e,1,2) )); |
| 100 | |
| 101 | typedef char E_char; |
| 102 | typedef char E_char_2; |
| 103 | typedef signed char E_char_signed; |
| 104 | typedef unsigned char E_char_unsigned; |
| 105 | |
| 106 | static const int E_tag __attribute__(( type_tag_for_datatype(e,E_char) )) = 10; |
| 107 | |
| 108 | void test_char_typedef(char *char_buf, |
| 109 | E_char_2 *e_char_buf, |
| 110 | E_char_signed *e_char_signed_buf, |
| 111 | E_char_unsigned *e_char_unsigned_buf) |
| 112 | { |
| 113 | E_func(char_buf, E_tag); |
| 114 | E_func(e_char_buf, E_tag); |
| 115 | #ifdef __CHAR_UNSIGNED__ |
| 116 | E_func(e_char_signed_buf, E_tag); // expected-warning {{argument type 'E_char_signed *' (aka 'signed char *') doesn't match specified 'e' type tag that requires 'E_char *' (aka 'char *')}} |
| 117 | E_func(e_char_unsigned_buf, E_tag); |
| 118 | #else |
| 119 | E_func(e_char_signed_buf, E_tag); |
| 120 | E_func(e_char_unsigned_buf, E_tag); // expected-warning {{argument type 'E_char_unsigned *' (aka 'unsigned char *') doesn't match specified 'e' type tag that requires 'E_char *' (aka 'char *')}} |
| 121 | #endif |
| 122 | } |
| 123 | |
| 124 | // Tests for argument_with_type_tag. |
| 125 | |
| 126 | #define F_DUPFD 10 |
| 127 | #define F_SETLK 20 |
| 128 | |
| 129 | struct flock { }; |
| 130 | |
| 131 | static const int F_DUPFD_tag __attribute__(( type_tag_for_datatype(fcntl,int) )) = F_DUPFD; |
| 132 | static const int F_SETLK_tag __attribute__(( type_tag_for_datatype(fcntl,struct flock *) )) = F_SETLK; |
| 133 | |
| 134 | int fcntl(int fd, int cmd, ...) __attribute__(( argument_with_type_tag(fcntl,3,2) )); |
| 135 | |
| 136 | void test_argument_with_type_tag(struct flock *f) |
| 137 | { |
| 138 | fcntl(0, F_DUPFD, 10); // no-warning |
| 139 | fcntl(0, F_SETLK, f); // no-warning |
| 140 | |
| 141 | fcntl(0, F_SETLK, 10); // expected-warning {{argument type 'int' doesn't match specified 'fcntl' type tag that requires 'struct flock *'}} |
| 142 | fcntl(0, F_DUPFD, f); // expected-warning {{argument type 'struct flock *' doesn't match specified 'fcntl' type tag that requires 'int'}} |
| 143 | } |
| 144 | |
| 145 | void test_tag_expresssion(int b) { |
| 146 | fcntl(0, b ? F_DUPFD : F_SETLK, 10); // no-warning |
| 147 | fcntl(0, b + F_DUPFD, 10); // no-warning |
| 148 | fcntl(0, (b, F_DUPFD), 10); // expected-warning {{expression result unused}} |
| 149 | } |
| 150 | |
| 151 | // Check that using 64-bit magic values as tags works and tag values do not |
| 152 | // overflow internally. |
| 153 | void F_func(void *ptr, unsigned long long tag) __attribute__((pointer_with_type_tag(f,1,2) )); |
| 154 | |
| 155 | static const unsigned long long F_tag1 __attribute__(( type_tag_for_datatype(f,int) )) = 0xFFFFFFFFFFFFFFFFULL; |
| 156 | static const unsigned long long F_tag2 __attribute__(( type_tag_for_datatype(f,float) )) = 0xFFFFFFFFULL; |
| 157 | |
| 158 | void test_64bit_magic(int *int_ptr, float *float_ptr) |
| 159 | { |
| 160 | F_func(int_ptr, 0xFFFFFFFFFFFFFFFFULL); |
| 161 | F_func(int_ptr, 0xFFFFFFFFULL); // expected-warning {{argument type 'int *' doesn't match specified 'f' type tag that requires 'float *'}} |
| 162 | F_func(float_ptr, 0xFFFFFFFFFFFFFFFFULL); // expected-warning {{argument type 'float *' doesn't match specified 'f' type tag that requires 'int *'}} |
| 163 | F_func(float_ptr, 0xFFFFFFFFULL); |
| 164 | } |
| 165 | |