aboutsummaryrefslogtreecommitdiff
path: root/clang/test/Sema/format-fixed-point.c
blob: 47b22f1a7a5f30343d19e60184015ad758970483 (plain)
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
// RUN: %clang_cc1 -ffixed-point -fsyntax-only -verify -Wformat -isystem %S/Inputs %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wformat -isystem %S/Inputs %s -DWITHOUT_FIXED_POINT

int printf(const char *restrict, ...);

short s;
unsigned short us;
int i;
unsigned int ui;
long l;
unsigned long ul;
float fl;
double d;
char c;
unsigned char uc;

#ifndef WITHOUT_FIXED_POINT
short _Fract sf;
_Fract f;
long _Fract lf;
unsigned short _Fract usf;
unsigned _Fract uf;
unsigned long _Fract ulf;
short _Accum sa;
_Accum a;
long _Accum la;
unsigned short _Accum usa;
unsigned _Accum ua;
unsigned long _Accum ula;
_Sat short _Fract sat_sf;
_Sat _Fract sat_f;
_Sat long _Fract sat_lf;
_Sat unsigned short _Fract sat_usf;
_Sat unsigned _Fract sat_uf;
_Sat unsigned long _Fract sat_ulf;
_Sat short _Accum sat_sa;
_Sat _Accum sat_a;
_Sat long _Accum sat_la;
_Sat unsigned short _Accum sat_usa;
_Sat unsigned _Accum sat_ua;
_Sat unsigned long _Accum sat_ula;

void test_invalid_args(void) {
  /// None of these should match against a fixed point type.
  printf("%r", s);   // expected-warning{{format specifies type '_Fract' but the argument has type 'short'}}
  printf("%r", us);  // expected-warning{{format specifies type '_Fract' but the argument has type 'unsigned short'}}
  printf("%r", i);   // expected-warning{{format specifies type '_Fract' but the argument has type 'int'}}
  printf("%r", ui);  // expected-warning{{format specifies type '_Fract' but the argument has type 'unsigned int'}}
  printf("%r", l);   // expected-warning{{format specifies type '_Fract' but the argument has type 'long'}}
  printf("%r", ul);  // expected-warning{{format specifies type '_Fract' but the argument has type 'unsigned long'}}
  printf("%r", fl);  // expected-warning{{format specifies type '_Fract' but the argument has type 'float'}}
  printf("%r", d);   // expected-warning{{format specifies type '_Fract' but the argument has type 'double'}}
  printf("%r", c);   // expected-warning{{format specifies type '_Fract' but the argument has type 'char'}}
  printf("%r", uc);  // expected-warning{{format specifies type '_Fract' but the argument has type 'unsigned char'}}
}

void test_fixed_point_specifiers(void) {
  printf("%r", f);
  printf("%R", uf);
  printf("%k", a);
  printf("%K", ua);

  /// Test different sizes.
  printf("%r", sf);   // expected-warning{{format specifies type '_Fract' but the argument has type 'short _Fract'}}
  printf("%r", lf);   // expected-warning{{format specifies type '_Fract' but the argument has type 'long _Fract'}}
  printf("%R", usf);  // expected-warning{{format specifies type 'unsigned _Fract' but the argument has type 'unsigned short _Fract'}}
  printf("%R", ulf);  // expected-warning{{format specifies type 'unsigned _Fract' but the argument has type 'unsigned long _Fract'}}
  printf("%k", sa);   // expected-warning{{format specifies type '_Accum' but the argument has type 'short _Accum'}}
  printf("%k", la);   // expected-warning{{format specifies type '_Accum' but the argument has type 'long _Accum'}}
  printf("%K", usa);  // expected-warning{{format specifies type 'unsigned _Accum' but the argument has type 'unsigned short _Accum'}}
  printf("%K", ula);  // expected-warning{{format specifies type 'unsigned _Accum' but the argument has type 'unsigned long _Accum'}}

  /// Test signs.
  printf("%r", uf);  // expected-warning{{format specifies type '_Fract' but the argument has type 'unsigned _Fract'}}
  printf("%R", f);   // expected-warning{{format specifies type 'unsigned _Fract' but the argument has type '_Fract'}}
  printf("%k", ua);  // expected-warning{{format specifies type '_Accum' but the argument has type 'unsigned _Accum'}}
  printf("%K", a);   // expected-warning{{format specifies type 'unsigned _Accum' but the argument has type '_Accum'}}

  /// Test between types.
  printf("%r", a);   // expected-warning{{format specifies type '_Fract' but the argument has type '_Accum'}}
  printf("%R", ua);  // expected-warning{{format specifies type 'unsigned _Fract' but the argument has type 'unsigned _Accum'}}
  printf("%k", f);   // expected-warning{{format specifies type '_Accum' but the argument has type '_Fract'}}
  printf("%K", uf);  // expected-warning{{format specifies type 'unsigned _Accum' but the argument has type 'unsigned _Fract'}}

  /// Test saturated types.
  printf("%r", sat_f);
  printf("%R", sat_uf);
  printf("%k", sat_a);
  printf("%K", sat_ua);
}

void test_length_modifiers_and_flags(void) {
  printf("%hr", sf);
  printf("%lr", lf);
  printf("%hR", usf);
  printf("%lR", ulf);
  printf("%hk", sa);
  printf("%lk", la);
  printf("%hK", usa);
  printf("%lK", ula);

  printf("%hr", sat_sf);
  printf("%lr", sat_lf);
  printf("%hR", sat_usf);
  printf("%lR", sat_ulf);
  printf("%hk", sat_sa);
  printf("%lk", sat_la);
  printf("%hK", sat_usa);
  printf("%lK", sat_ula);

  printf("%10r", f);
  printf("%10.10r", f);
  printf("%010r", f);
  printf("%-10r", f);
  printf("%.10r", f);
  printf("%+r", f);
  printf("% r", f);
  printf("%#r", f);
  printf("%#.r", f);
  printf("%#.0r", f);

  /// Test some invalid length modifiers.
  printf("%zr", f);   // expected-warning{{length modifier 'z' results in undefined behavior or no effect with 'r' conversion specifier}}
  printf("%llr", f);  // expected-warning{{length modifier 'll' results in undefined behavior or no effect with 'r' conversion specifier}}
  printf("%hhr", f);  // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 'r' conversion specifier}}

  // + on an unsigned fixed point type.
  printf("%+hR", usf);  // expected-warning{{flag '+' results in undefined behavior with 'R' conversion specifier}}
  printf("%+R", uf);    // expected-warning{{flag '+' results in undefined behavior with 'R' conversion specifier}}
  printf("%+lR", ulf);  // expected-warning{{flag '+' results in undefined behavior with 'R' conversion specifier}}
  printf("%+hK", usa);  // expected-warning{{flag '+' results in undefined behavior with 'K' conversion specifier}}
  printf("%+K", ua);    // expected-warning{{flag '+' results in undefined behavior with 'K' conversion specifier}}
  printf("%+lK", ula);  // expected-warning{{flag '+' results in undefined behavior with 'K' conversion specifier}}
  printf("% hR", usf);  // expected-warning{{flag ' ' results in undefined behavior with 'R' conversion specifier}}
  printf("% R", uf);    // expected-warning{{flag ' ' results in undefined behavior with 'R' conversion specifier}}
  printf("% lR", ulf);  // expected-warning{{flag ' ' results in undefined behavior with 'R' conversion specifier}}
  printf("% hK", usa);  // expected-warning{{flag ' ' results in undefined behavior with 'K' conversion specifier}}
  printf("% K", ua);    // expected-warning{{flag ' ' results in undefined behavior with 'K' conversion specifier}}
  printf("% lK", ula);  // expected-warning{{flag ' ' results in undefined behavior with 'K' conversion specifier}}
}
#else
void test_fixed_point_specifiers_no_printf() {
  printf("%k", i);  // expected-warning{{invalid conversion specifier 'k'}}  
  printf("%K", i);  // expected-warning{{invalid conversion specifier 'K'}}
  printf("%r", i);  // expected-warning{{invalid conversion specifier 'r'}}
  printf("%R", i);  // expected-warning{{invalid conversion specifier 'R'}}
}
#endif  // WITHOUT_FIXED_POINT