aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/Sema.h5
-rw-r--r--lib/Sema/SemaChecking.cpp62
-rw-r--r--test/Sema/format-strings.c6
3 files changed, 64 insertions, 9 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index f098372d97..fc619c6f1f 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1516,6 +1516,11 @@ private:
Action::ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
bool SemaBuiltinPrefetch(CallExpr *TheCall);
bool SemaBuiltinObjectSize(CallExpr *TheCall);
+ bool SemaCheckStringLiteral(Expr *E, CallExpr *TheCall, bool HasVAListArg,
+ unsigned format_idx);
+ void CheckPrintfString(StringLiteral *FExpr, Expr *OrigFormatExpr,
+ CallExpr *TheCall, bool HasVAListArg,
+ unsigned format_idx);
void CheckPrintfArguments(CallExpr *TheCall,
bool HasVAListArg, unsigned format_idx);
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 5bb78cd765..ff9d75302f 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -369,6 +369,51 @@ bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
return false;
}
+// Handle i > 1 ? "x" : "y", recursivelly
+bool Sema::SemaCheckStringLiteral(Expr *E, CallExpr *TheCall, bool HasVAListArg,
+ unsigned format_idx) {
+
+ switch (E->getStmtClass()) {
+ case Stmt::ConditionalOperatorClass: {
+ ConditionalOperator *C = cast<ConditionalOperator>(E);
+ return SemaCheckStringLiteral(C->getLHS(), TheCall,
+ HasVAListArg, format_idx)
+ && SemaCheckStringLiteral(C->getRHS(), TheCall,
+ HasVAListArg, format_idx);
+ }
+
+ case Stmt::ImplicitCastExprClass: {
+ ImplicitCastExpr *Expr = dyn_cast<ImplicitCastExpr>(E);
+ return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg,
+ format_idx);
+ }
+
+ case Stmt::ParenExprClass: {
+ ParenExpr *Expr = dyn_cast<ParenExpr>(E);
+ return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg,
+ format_idx);
+ }
+
+ default: {
+ ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(E);
+ StringLiteral *StrE = NULL;
+
+ if (ObjCFExpr)
+ StrE = ObjCFExpr->getString();
+ else
+ StrE = dyn_cast<StringLiteral>(E);
+
+ if (StrE) {
+ CheckPrintfString(StrE, E, TheCall, HasVAListArg, format_idx);
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
+
+
/// CheckPrintfArguments - Check calls to printf (and similar functions) for
/// correct use of format strings.
///
@@ -444,15 +489,9 @@ Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
// C string (e.g. "%d")
// ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
- ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(OrigFormatExpr);
- StringLiteral *FExpr = NULL;
-
- if(ObjCFExpr != NULL)
- FExpr = ObjCFExpr->getString();
- else
- FExpr = dyn_cast<StringLiteral>(OrigFormatExpr);
+ bool isFExpr = SemaCheckStringLiteral(OrigFormatExpr, TheCall, HasVAListArg, format_idx);
- if (FExpr == NULL) {
+ if (!isFExpr) {
// For vprintf* functions (i.e., HasVAListArg==true), we add a
// special check to see if the format string is a function parameter
// of the function calling the printf function. If the function
@@ -475,13 +514,18 @@ Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(OrigFormatExpr))
if (isa<ParmVarDecl>(DR->getDecl()))
return;
-
+
Diag(TheCall->getArg(format_idx)->getLocStart(),
diag::warn_printf_not_string_constant)
<< OrigFormatExpr->getSourceRange();
return;
}
+}
+
+void Sema::CheckPrintfString(StringLiteral *FExpr, Expr *OrigFormatExpr,
+ CallExpr *TheCall, bool HasVAListArg, unsigned format_idx) {
+ ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(OrigFormatExpr);
// CHECK: is the format string a wide literal?
if (FExpr->isWide()) {
Diag(FExpr->getLocStart(),
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index 16d4943cda..19c29db343 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -31,6 +31,12 @@ void check_string_literal( FILE* fp, const char* s, char *buf, ... ) {
__builtin___vsnprintf_chk(buf,2,0,-1,global_fmt,ap); // expected-warning {{format string is not a string literal}}
}
+void check_conditional_literal(const char* s, int i) {
+ printf(i == 1 ? "yes" : "no"); // no-warning
+ printf(i == 0 ? (i == 1 ? "yes" : "no") : "dont know"); // no-warning
+ printf(i == 0 ? (i == 1 ? s : "no") : "dont know"); // expected-warning
+}
+
void check_writeback_specifier()
{
int x;