diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index f9926c6b4adab..9cac9cf5c4df7 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -6149,18 +6149,19 @@ static StringLiteralCheckType checkFormatStringExpr( if (!Sema::getFormatStringInfo(D, PVFormat->getFormatIdx(), PVFormat->getFirstArg(), &CallerFSI)) continue; - // We also check if the formats are compatible. - // We can't pass a 'scanf' string to a 'printf' function. - if (Type != S.GetFormatStringType(PVFormat)) { - S.Diag(Args[format_idx]->getBeginLoc(), - diag::warn_format_string_type_incompatible) - << PVFormat->getType()->getName() - << S.GetFormatStringTypeName(Type); - if (!InFunctionCall) { - S.Diag(E->getBeginLoc(), diag::note_format_string_defined); + if (PV->getFunctionScopeIndex() == CallerFSI.FormatIdx) { + // We also check if the formats are compatible. + // We can't pass a 'scanf' string to a 'printf' function. + if (Type != S.GetFormatStringType(PVFormat)) { + S.Diag(Args[format_idx]->getBeginLoc(), + diag::warn_format_string_type_incompatible) + << PVFormat->getType()->getName() + << S.GetFormatStringTypeName(Type); + if (!InFunctionCall) { + S.Diag(E->getBeginLoc(), diag::note_format_string_defined); + } + return SLCT_UncheckedLiteral; } - return SLCT_UncheckedLiteral; - } else if (PV->getFunctionScopeIndex() == CallerFSI.FormatIdx) { // Lastly, check that argument passing kinds transition in a // way that makes sense: // from a caller with FAPK_VAList, allow FAPK_VAList diff --git a/clang/test/Sema/format-strings.c b/clang/test/Sema/format-strings.c index efd88d5c18e66..af30ad5d15fe2 100644 --- a/clang/test/Sema/format-strings.c +++ b/clang/test/Sema/format-strings.c @@ -496,6 +496,26 @@ void rdar8332221(va_list ap, int *x, long *y) { rdar8332221_vprintf_scanf("%", ap, "%d", x); // expected-warning{{incomplete format specifier}} } +void rdar8332221_vprintf_scanf(const char *p, va_list ap, const char *s, ...) { + vprintf(p, ap); + + va_list vs; + va_start(vs, s); + vscanf(s, vs); + va_end(vs); +} + +__attribute__((__format__(__printf__, 1, 0))) +__attribute__((__format__(__scanf__, 3, 4))) +void vprintf_scanf_bad(const char *p, va_list ap, const char *s, ...) { + vscanf(p, ap); // expected-warning{{passing 'printf' format string where 'scanf' format string is expected}} + + va_list vs; + va_start(vs, s); + vprintf(s, vs); // expected-warning{{passing 'scanf' format string where 'printf' format string is expected}} + va_end(vs); +} + // PR8641 void pr8641(void) { printf("%#x\n", 10);