================ @@ -6331,26 +6321,79 @@ static StringLiteralCheckType checkFormatStringExpr( } } - return SLCT_NotALiteral; + // try to constant-evaluate the string + break; } default: + // try to constant-evaluate the string + break; + } + + const StringLiteral *FakeLiteral = nullptr; + switch (constEvalStringAsLiteral(S, E, FakeLiteral)) { + case SLCER_NotEvaluated: return SLCT_NotALiteral; + + case SLCER_NotNullTerminated: + S.Diag(Args[format_idx]->getBeginLoc(), + diag::warn_printf_format_string_not_null_terminated) + << Args[format_idx]->getSourceRange(); + if (!InFunctionCall) + S.Diag(E->getBeginLoc(), diag::note_format_string_defined); + // Stop checking, as this might just mean we're missing a chunk of the + // format string and there would be other spurious format issues. + return SLCT_UncheckedLiteral; + + case SLCER_Evaluated: + InFunctionCall = false; + E = FakeLiteral; + goto 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) { +static StringLiteralConstEvalResult +constEvalStringAsLiteral(Sema &S, const Expr *E, const StringLiteral *&SL) { + // As a last resort, try to constant-evaluate the format string. If it + // evaluates to a string literal in the first place, we can point to that + // string literal in source and use that. Expr::EvalResult Result; - if (E->EvaluateAsRValue(Result, Context) && Result.Val.isLValue()) { + if (E->EvaluateAsRValue(Result, S.Context) && Result.Val.isLValue()) { const auto *LVE = Result.Val.getLValueBase().dyn_cast<const Expr *>(); - if (isa_and_nonnull<StringLiteral>(LVE)) - return LVE; + if (auto *BaseSL = dyn_cast_or_null<StringLiteral>(LVE)) { + SL = BaseSL; + return SLCER_Evaluated; + } } - return nullptr; + + // Otherwise, try to evaluate the expression as a string constant. + std::string FormatString; + if (!E->tryEvaluateString(S.Context, FormatString)) { + return FormatString.empty() ? SLCER_NotEvaluated : SLCER_NotNullTerminated; + } + + std::unique_ptr<llvm::MemoryBuffer> MemBuf; + { + llvm::SmallString<80> EscapedString; + { + llvm::raw_svector_ostream OS(EscapedString); + OS << '"'; + OS.write_escaped(FormatString); + OS << '"'; + } + MemBuf.reset(new llvm::SmallVectorMemoryBuffer(std::move(EscapedString), + "<scratch space>", true)); + } + + // Plop that string into a scratch buffer, create a string literal and then + // go with that. + auto ScratchFile = S.getSourceManager().createFileID(std::move(MemBuf)); ---------------- AaronBallman wrote:
Please spell out the type. https://github.com/llvm/llvm-project/pull/135864 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits