aboutsummaryrefslogtreecommitdiff
path: root/test/Sema/warn-type-safety.c
blob: dfab8f8c818b778d7f661ba7af9faafd36fe245e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// RUN: %clang_cc1 -std=c99 -fsyntax-only -verify %s
// RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify %s
// RUN: %clang_cc1 -std=c99 -fno-signed-char -fsyntax-only -verify %s

struct A {};

typedef struct A *MPI_Datatype;

int wrong1(void *buf, MPI_Datatype datatype)
    __attribute__(( pointer_with_type_tag )); // expected-error {{'pointer_with_type_tag' attribute requires parameter 1 to be an identifier}}

int wrong2(void *buf, MPI_Datatype datatype)
    __attribute__(( pointer_with_type_tag(mpi,0,7) )); // expected-error {{attribute parameter 2 is out of bounds}}

int wrong3(void *buf, MPI_Datatype datatype)
    __attribute__(( pointer_with_type_tag(mpi,3,7) )); // expected-error {{attribute parameter 2 is out of bounds}}

int wrong4(void *buf, MPI_Datatype datatype)
    __attribute__(( pointer_with_type_tag(mpi,1,0) )); // expected-error {{attribute parameter 3 is out of bounds}}

int wrong5(void *buf, MPI_Datatype datatype)
    __attribute__(( pointer_with_type_tag(mpi,1,3) )); // expected-error {{attribute parameter 3 is out of bounds}}

int wrong6(void *buf, MPI_Datatype datatype)
    __attribute__(( pointer_with_type_tag(mpi,0x8000000000000001ULL,1) )); // expected-error {{attribute parameter 2 is out of bounds}}

extern int x;

int wrong7(void *buf, MPI_Datatype datatype)
    __attribute__(( pointer_with_type_tag(mpi,x,2) )); // expected-error {{attribute requires parameter 2 to be an integer constant}}

int wrong8(void *buf, MPI_Datatype datatype)
    __attribute__(( pointer_with_type_tag(mpi,1,x) )); // expected-error {{attribute requires parameter 3 to be an integer constant}}

int wrong9 __attribute__(( pointer_with_type_tag(mpi,1,2) )); // expected-error {{attribute only applies to functions and methods}}

int wrong10(double buf, MPI_Datatype type)
    __attribute__(( pointer_with_type_tag(mpi,1,2) )); // expected-error {{'pointer_with_type_tag' attribute only applies to pointer arguments}}


extern struct A datatype_wrong1
    __attribute__(( type_tag_for_datatype )); // expected-error {{'type_tag_for_datatype' attribute requires parameter 1 to be an identifier}}

extern struct A datatype_wrong2
    __attribute__(( type_tag_for_datatype(mpi,1,2) )); // expected-error {{expected a type}}

extern struct A datatype_wrong3
    __attribute__(( type_tag_for_datatype(mpi,not_a_type) )); // expected-error {{unknown type name 'not_a_type'}}

extern struct A datatype_wrong4
    __attribute__(( type_tag_for_datatype(mpi,int,int) )); // expected-error {{expected identifier}}

extern struct A datatype_wrong5
    __attribute__(( type_tag_for_datatype(mpi,int,not_a_flag) )); // expected-error {{invalid comparison flag 'not_a_flag'}}

extern struct A datatype_wrong6
    __attribute__(( type_tag_for_datatype(mpi,int,layout_compatible,not_a_flag) )); // expected-error {{invalid comparison flag 'not_a_flag'}}


// Using a tag with kind A in a place where the function requires kind B should
// warn.

void A_func(void *ptr, void *tag) __attribute__(( pointer_with_type_tag(a,1,2) ));

extern struct A A_tag __attribute__(( type_tag_for_datatype(a,int) ));
extern struct A B_tag __attribute__(( type_tag_for_datatype(b,int) ));

void C_func(void *ptr, int tag) __attribute__(( pointer_with_type_tag(c,1,2) ));

static const int C_tag __attribute__(( type_tag_for_datatype(c,int) )) = 10;
static const int D_tag __attribute__(( type_tag_for_datatype(d,int) )) = 20;

void test_tag_mismatch(int *ptr)
{
  A_func(ptr, &A_tag); // no-warning
  A_func(ptr, &B_tag); // expected-warning {{this type tag was not designed to be used with this function}}
  C_func(ptr, C_tag); // no-warning
  C_func(ptr, D_tag); // expected-warning {{this type tag was not designed to be used with this function}}
  C_func(ptr, 10); // no-warning
  C_func(ptr, 20); // should warn, but may cause false positives
}

void test_null_pointer()
{
  C_func(0, C_tag); // no-warning
  C_func((void *) 0, C_tag); // no-warning
  C_func((int *) 0, C_tag); // no-warning
  C_func((long *) 0, C_tag); // expected-warning {{argument type 'long *' doesn't match specified 'c' type tag that requires 'int *'}}
}

// Check that we look through typedefs in the special case of allowing 'char'
// to be matched with 'signed char' or 'unsigned char'.
void E_func(void *ptr, int tag) __attribute__(( pointer_with_type_tag(e,1,2) ));

typedef char E_char;
typedef char E_char_2;
typedef signed char E_char_signed;
typedef unsigned char E_char_unsigned;

static const int E_tag __attribute__(( type_tag_for_datatype(e,E_char) )) = 10;

void test_char_typedef(char *char_buf,
                       E_char_2 *e_char_buf,
                       E_char_signed *e_char_signed_buf,
                       E_char_unsigned *e_char_unsigned_buf)
{
  E_func(char_buf, E_tag);
  E_func(e_char_buf, E_tag);
#ifdef __CHAR_UNSIGNED__
  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 *')}}
  E_func(e_char_unsigned_buf, E_tag);
#else
  E_func(e_char_signed_buf, E_tag);
  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 *')}}
#endif
}

// Tests for argument_with_type_tag.

#define F_DUPFD 10
#define F_SETLK 20

struct flock { };

static const int F_DUPFD_tag __attribute__(( type_tag_for_datatype(fcntl,int) )) = F_DUPFD;
static const int F_SETLK_tag __attribute__(( type_tag_for_datatype(fcntl,struct flock *) )) = F_SETLK;

int fcntl(int fd, int cmd, ...) __attribute__(( argument_with_type_tag(fcntl,3,2) ));

void test_argument_with_type_tag(struct flock *f)
{
  fcntl(0, F_DUPFD, 10); // no-warning
  fcntl(0, F_SETLK, f);  // no-warning

  fcntl(0, F_SETLK, 10); // expected-warning {{argument type 'int' doesn't match specified 'fcntl' type tag that requires 'struct flock *'}}
  fcntl(0, F_DUPFD, f);  // expected-warning {{argument type 'struct flock *' doesn't match specified 'fcntl' type tag that requires 'int'}}
}

void test_tag_expresssion(int b) {
  fcntl(0, b ? F_DUPFD : F_SETLK, 10); // no-warning
  fcntl(0, b + F_DUPFD, 10); // no-warning
  fcntl(0, (b, F_DUPFD), 10); // expected-warning {{expression result unused}}
}

// Check that using 64-bit magic values as tags works and tag values do not
// overflow internally.
void F_func(void *ptr, unsigned long long tag) __attribute__((pointer_with_type_tag(f,1,2) ));

static const unsigned long long F_tag1 __attribute__(( type_tag_for_datatype(f,int) )) = 0xFFFFFFFFFFFFFFFFULL;
static const unsigned long long F_tag2 __attribute__(( type_tag_for_datatype(f,float) )) = 0xFFFFFFFFULL;

void test_64bit_magic(int *int_ptr, float *float_ptr)
{
  F_func(int_ptr,   0xFFFFFFFFFFFFFFFFULL);
  F_func(int_ptr,   0xFFFFFFFFULL);         // expected-warning {{argument type 'int *' doesn't match specified 'f' type tag that requires 'float *'}}
  F_func(float_ptr, 0xFFFFFFFFFFFFFFFFULL); // expected-warning {{argument type 'float *' doesn't match specified 'f' type tag that requires 'int *'}}
  F_func(float_ptr, 0xFFFFFFFFULL);
}