// RUN: %clang_cc1 -fsyntax-only -verify -Wformat -fexperimental-overflow-behavior-types -isystem %S/Inputs %s // Test format string checking with overflow behavior types // This ensures that OverflowBehaviorTypes work seamlessly with printf/scanf // without spurious format warnings. int printf(const char *restrict, ...); int sprintf(char *restrict, const char *restrict, ...); int snprintf(char *restrict, __SIZE_TYPE__, const char *restrict, ...); int scanf(const char *restrict, ...); int sscanf(const char *restrict, const char *restrict, ...); typedef int __ob_wrap wrap_int; typedef int __ob_trap no_trap_int; typedef unsigned int __ob_wrap wrap_uint; typedef unsigned int __ob_trap no_trap_uint; typedef short __ob_wrap wrap_short; typedef long __ob_trap no_trap_long; void test_printf_compatibility() { wrap_int wi = 42; no_trap_int ni = 42; wrap_uint wu = 42U; no_trap_uint nu = 42U; wrap_short ws = 42; no_trap_long nl = 42L; // These should all work without warnings - OBTs should be treated as their underlying types printf("%d", wi); printf("%d", ni); printf("%u", wu); printf("%u", nu); printf("%hd", ws); printf("%ld", nl); printf("%x", wu); printf("%o", nu); printf("%s", wi); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}} printf("%f", wi); // expected-warning{{format specifies type 'double' but the argument has type 'int'}} printf("%ld", wi); // expected-warning{{format specifies type 'long' but the argument has type 'int'}} } void test_scanf_compatibility() { wrap_int wi; no_trap_int ni; wrap_uint wu; no_trap_uint nu; wrap_short ws; no_trap_long nl; // These should all work without warnings - pointers to OBTs should be treated as pointers to underlying types scanf("%d", &wi); scanf("%d", &ni); scanf("%u", &wu); scanf("%u", &nu); scanf("%hd", &ws); scanf("%ld", &nl); scanf("%x", &wu); scanf("%o", &nu); scanf("%s", &wi); // expected-warning{{format specifies type 'char *' but the argument has type 'wrap_int *'}} scanf("%f", &wi); // expected-warning{{format specifies type 'float *' but the argument has type 'wrap_int *'}} scanf("%ld", &wi); // expected-warning{{format specifies type 'long *' but the argument has type 'wrap_int *'}} } void test_mixed_formats() { wrap_int wi = 42; int regular_int = 42; printf("%d + %d = %d", wi, regular_int, wi + regular_int); scanf("%d %d", &wi, ®ular_int); } typedef unsigned char __ob_wrap wrap_byte; typedef long long __ob_trap safe_longlong; void test_typedef_formats() { wrap_byte wb = 255; safe_longlong sll = 123456789LL; printf("%hhu", wb); // OK: wrap_byte -> unsigned char for %hhu printf("%lld", sll); // OK: safe_longlong -> long long for %lld scanf("%hhu", &wb); // OK: &wb treated as unsigned char* for %hhu scanf("%lld", &sll); // OK: &sll treated as long long* for %lld printf("%d", wb); // OK: wb implicitly cast to int printf("%d", sll); // expected-warning{{format specifies type 'int' but the argument has type 'long long'}} }