1// RUN: %clang_cc1 -triple i386-apple-darwin9 -x c++ -std=c++11 -verify %s
2// RUN: %clang_cc1 -triple i386-apple-darwin9 -x objective-c -verify %s
3// RUN: %clang_cc1 -triple i386-apple-darwin9 -x objective-c++ -verify %s
4
5#ifdef __cplusplus
6# define EXTERN_C extern "C"
7#else
8# define EXTERN_C extern
9#endif
10
11EXTERN_C int printf(const char *,...);
12
13typedef enum : short { Constant = 0 } TestEnum;
14// Note that in C (and Objective-C), the type of 'Constant' is 'short'.
15// In C++ (and Objective-C++) it is 'TestEnum'.
16// This is why we don't check for that in the expected output.
17
18void test(TestEnum input) {
19  printf("%hhd", input); // expected-warning{{format specifies type 'char' but the argument has underlying type 'short'}}
20  printf("%hhd", Constant); // expected-warning{{format specifies type 'char'}}
21
22  printf("%hd", input); // no-warning
23  printf("%hd", Constant); // no-warning
24
25  // While these are less correct, they are still safe.
26  printf("%d", input); // no-warning
27  printf("%d", Constant); // no-warning
28
29  printf("%lld", input); // expected-warning{{format specifies type 'long long' but the argument has underlying type 'short'}}
30  printf("%lld", Constant); // expected-warning{{format specifies type 'long long'}}
31}
32
33
34typedef enum : unsigned long { LongConstant = ~0UL } LongEnum;
35
36void testLong(LongEnum input) {
37  printf("%u", input); // expected-warning{{format specifies type 'unsigned int' but the argument has underlying type 'unsigned long'}}
38  printf("%u", LongConstant); // expected-warning{{format specifies type 'unsigned int'}}
39
40  printf("%lu", input);
41  printf("%lu", LongConstant);
42}
43
44
45typedef short short_t;
46typedef enum : short_t { ShortConstant = 0 } ShortEnum;
47
48void testUnderlyingTypedef(ShortEnum input) {
49  printf("%hhd", input); // expected-warning{{format specifies type 'char' but the argument has underlying type 'short_t' (aka 'short')}}
50  printf("%hhd", ShortConstant); // expected-warning{{format specifies type 'char'}}
51
52  printf("%hd", input); // no-warning
53  printf("%hd", ShortConstant); // no-warning
54
55  // While these are less correct, they are still safe.
56  printf("%d", input); // no-warning
57  printf("%d", ShortConstant); // no-warning
58
59  printf("%lld", input); // expected-warning{{format specifies type 'long long' but the argument has underlying type 'short_t' (aka 'short')}}
60  printf("%lld", ShortConstant); // expected-warning{{format specifies type 'long long'}}
61}
62
63
64typedef ShortEnum ShortEnum2;
65
66void testTypedefChain(ShortEnum2 input) {
67  printf("%hhd", input); // expected-warning{{format specifies type 'char' but the argument has underlying type 'short_t' (aka 'short')}}
68  printf("%hd", input); // no-warning
69  printf("%d", input); // no-warning
70  printf("%lld", input); // expected-warning{{format specifies type 'long long' but the argument has underlying type 'short_t' (aka 'short')}}
71}
72
73
74typedef enum : char { CharConstant = 'a' } CharEnum;
75
76// %hhd is deliberately not required to be signed, because 'char' isn't either.
77// This is a separate code path in FormatString.cpp.
78void testChar(CharEnum input) {
79  printf("%hhd", input); // no-warning
80  printf("%hhd", CharConstant); // no-warning
81
82  // This is not correct but it is safe. We warn because '%hd' shows intent.
83  printf("%hd", input); // expected-warning{{format specifies type 'short' but the argument has underlying type 'char'}}
84  printf("%hd", CharConstant); // expected-warning{{format specifies type 'short'}}
85
86  // This is not correct but it matches the promotion rules (and is safe).
87  printf("%d", input); // no-warning
88  printf("%d", CharConstant); // no-warning
89
90  printf("%lld", input); // expected-warning{{format specifies type 'long long' but the argument has underlying type 'char'}}
91  printf("%lld", CharConstant); // expected-warning{{format specifies type 'long long'}}
92}
93