Index: cfe/trunk/include/clang/Analysis/Analyses/FormatString.h =================================================================== --- cfe/trunk/include/clang/Analysis/Analyses/FormatString.h +++ cfe/trunk/include/clang/Analysis/Analyses/FormatString.h @@ -211,6 +211,8 @@ return false; case PercentArg: return false; + case InvalidSpecifier: + return false; default: return true; } Index: cfe/trunk/test/CodeGen/builtins.c =================================================================== --- cfe/trunk/test/CodeGen/builtins.c +++ cfe/trunk/test/CodeGen/builtins.c @@ -538,6 +538,34 @@ __builtin_os_log_format(buf, "Hello %*.*s World", precision, width, data); } +// CHECK-LABEL: define void @test_builtin_os_log_invalid +// CHECK: (i8* [[BUF:%.*]], i32 [[DATA:%.*]]) +void test_builtin_os_log_invalid(void *buf, int data) { + volatile int len; + // CHECK: store i8* [[BUF]], i8** [[BUF_ADDR:%.*]], align 8 + // CHECK: store i32 [[DATA]], i32* [[DATA_ADDR:%.*]] + + // CHECK: store volatile i32 8, + len = __builtin_os_log_format_buffer_size("invalid specifier %: %d even a trailing one%", data); + + // CHECK: [[BUF2:%.*]] = load i8*, i8** [[BUF_ADDR]] + // CHECK: [[SUMMARY:%.*]] = getelementptr i8, i8* [[BUF2]], i64 0 + // CHECK: store i8 0, i8* [[SUMMARY]] + // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* [[BUF2]], i64 1 + // CHECK: store i8 1, i8* [[NUM_ARGS]] + + // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 2 + // CHECK: store i8 0, i8* [[ARG1_DESC]] + // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 3 + // CHECK: store i8 4, i8* [[ARG1_SIZE]] + // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* [[BUF2]], i64 4 + // CHECK: [[ARG1_INT:%.*]] = bitcast i8* [[ARG1]] to i32* + // CHECK: [[ARG1_VAL:%.*]] = load i32, i32* [[DATA_ADDR]] + // CHECK: store i32 [[ARG1_VAL]], i32* [[ARG1_INT]] + + __builtin_os_log_format(buf, "invalid specifier %: %d even a trailing one%", data); +} + // CHECK-LABEL: define void @test_builtin_os_log_percent // CHECK: (i8* [[BUF:%.*]], i8* [[DATA1:%.*]], i8* [[DATA2:%.*]]) // Check that the %% which does not consume any argument is correctly handled Index: cfe/trunk/test/Sema/format-strings.c =================================================================== --- cfe/trunk/test/Sema/format-strings.c +++ cfe/trunk/test/Sema/format-strings.c @@ -156,10 +156,10 @@ void check_invalid_specifier(FILE* fp, char *buf) { - printf("%s%lb%d","unix",10,20); // expected-warning {{invalid conversion specifier 'b'}} + printf("%s%lb%d","unix",10,20); // expected-warning {{invalid conversion specifier 'b'}} expected-warning {{data argument not used by format string}} fprintf(fp,"%%%l"); // expected-warning {{incomplete format specifier}} sprintf(buf,"%%%%%ld%d%d", 1, 2, 3); // expected-warning{{format specifies type 'long' but the argument has type 'int'}} - snprintf(buf, 2, "%%%%%ld%;%d", 1, 2, 3); // expected-warning{{format specifies type 'long' but the argument has type 'int'}} expected-warning {{invalid conversion specifier ';'}} + snprintf(buf, 2, "%%%%%ld%;%d", 1, 2, 3); // expected-warning{{format specifies type 'long' but the argument has type 'int'}} expected-warning {{invalid conversion specifier ';'}} expected-warning {{data argument not used by format string}} } void check_null_char_string(char* b) @@ -251,7 +251,7 @@ printf("%**\n"); // expected-warning{{invalid conversion specifier '*'}} printf("%d%d\n", x); // expected-warning{{more '%' conversions than data arguments}} printf("%d\n", x, x); // expected-warning{{data argument not used by format string}} - printf("%W%d\n", x, x); // expected-warning{{invalid conversion specifier 'W'}} + printf("%W%d\n", x, x); // expected-warning{{invalid conversion specifier 'W'}} expected-warning {{data argument not used by format string}} printf("%"); // expected-warning{{incomplete format specifier}} printf("%.d", x); // no-warning printf("%.", x); // expected-warning{{incomplete format specifier}} @@ -270,7 +270,7 @@ printf("%.0Lf", (long double) 1.0); // no-warning printf("%c\n", "x"); // expected-warning{{format specifies type 'int' but the argument has type 'char *'}} printf("%c\n", 1.23); // expected-warning{{format specifies type 'int' but the argument has type 'double'}} - printf("Format %d, is %! %f", 1, 2, 4.4); // expected-warning{{invalid conversion specifier '!'}} + printf("Format %d, is %! %f", 1, 4.4); // expected-warning{{invalid conversion specifier '!'}} } typedef unsigned char uint8_t; Index: cfe/trunk/test/SemaObjC/format-strings-objc.m =================================================================== --- cfe/trunk/test/SemaObjC/format-strings-objc.m +++ cfe/trunk/test/SemaObjC/format-strings-objc.m @@ -47,7 +47,7 @@ void check_nslog(unsigned k) { NSLog(@"%d%%", k); // no-warning - NSLog(@"%s%lb%d", "unix", 10,20); // expected-warning {{invalid conversion specifier 'b'}} + NSLog(@"%s%lb%d", "unix", 10, 20); // expected-warning {{invalid conversion specifier 'b'}} expected-warning {{data argument not used by format string}} } // Check type validation