aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
authorYingChi Long <me@inclyc.cn>2022-08-03 10:07:31 +0800
committerYingChi Long <me@inclyc.cn>2022-08-04 21:07:30 +0800
commitf417583f319bd60d1e32cdf9d0242e42f86101bf (patch)
tree000ade2999b3011d8c60c2e608f04bd066f88926 /clang/lib/Sema/SemaChecking.cpp
parentb8985ba0adb5fd881bb301fbc79370b86396e658 (diff)
downloadllvm-f417583f319bd60d1e32cdf9d0242e42f86101bf.zip
llvm-f417583f319bd60d1e32cdf9d0242e42f86101bf.tar.gz
llvm-f417583f319bd60d1e32cdf9d0242e42f86101bf.tar.bz2
[clang] format string checking for conpile-time evaluated str literal
This patch enhances clang's ability to check compile-time determinable string literals as format strings, and can give FixIt hints at literals (unlike gcc). Issue https://github.com/llvm/llvm-project/issues/55805 mentiond two compile-time string cases. And this patch partially fixes one. ``` constexpr const char* foo() { return "%s %d"; } int main() { printf(foo(), "abc", "def"); return 0; } ``` This patch enables clang check format string for this: ``` <source>:4:24: warning: format specifies type 'int' but the argument has type 'const char *' [-Wformat] printf(foo(), "abc", "def"); ~~~~~ ^~~~~ <source>:2:42: note: format string is defined here constexpr const char *foo() { return "%s %d"; } ^~ %s 1 warning generated. ``` Reviewed By: aaron.ballman Signed-off-by: YingChi Long <me@inclyc.cn> Differential Revision: https://reviews.llvm.org/D130906
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r--clang/lib/Sema/SemaChecking.cpp23
1 files changed, 22 insertions, 1 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 6b60312..6428be1 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -8473,6 +8473,9 @@ static void CheckFormatString(
llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
bool IgnoreStringsWithoutSpecifiers);
+static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
+ const Expr *E);
+
// Determine if an expression is a string literal or constant string.
// If this function returns false on the arguments to a function expecting a
// format string, we will usually need to emit a warning.
@@ -8713,7 +8716,11 @@ tryAgain:
}
}
}
-
+ if (const auto *SLE = maybeConstEvalStringLiteral(S.Context, E))
+ return checkFormatStringExpr(S, SLE, Args, APK, format_idx, firstDataArg,
+ Type, CallType, /*InFunctionCall*/ false,
+ CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
return SLCT_NotALiteral;
}
case Stmt::ObjCMessageExprClass: {
@@ -8823,6 +8830,20 @@ tryAgain:
}
}
+// If this expression can be evaluated at compile-time,
+// check if the result is a StringLiteral and return it
+// otherwise return nullptr
+static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
+ const Expr *E) {
+ Expr::EvalResult Result;
+ if (E->EvaluateAsRValue(Result, Context) && Result.Val.isLValue()) {
+ const auto *LVE = Result.Val.getLValueBase().dyn_cast<const Expr *>();
+ if (isa_and_nonnull<StringLiteral>(LVE))
+ return LVE;
+ }
+ return nullptr;
+}
+
Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
return llvm::StringSwitch<FormatStringType>(Format->getType()->getName())
.Case("scanf", FST_Scanf)