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 11 EXTERN_C int printf(const char *,...); 12 13 typedef 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 18 void 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 34 typedef enum : unsigned long { LongConstant = ~0UL } LongEnum; 35 36 void 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 45 typedef short short_t; 46 typedef enum : short_t { ShortConstant = 0 } ShortEnum; 47 48 void 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 64 typedef ShortEnum ShortEnum2; 65 66 void 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 74 typedef 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. 78 void 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