Skip to content

Commit 654b959

Browse files
Address naming/documentation-level review feedback
1 parent 75d5026 commit 654b959

File tree

4 files changed

+57
-16
lines changed

4 files changed

+57
-16
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,39 @@ related warnings within the method body.
382382
``format_matches`` accepts an example valid format string as its third
383383
argument. For more information, see the Clang attributes documentation.
384384

385-
- Format string checking now supports the compile-time evaluation of format
386-
strings as a fallback mechanism.
385+
- Clang can now verify format strings that can be constant-folded even if they
386+
do not resolve to a string literal. For instance, all of these can now be
387+
verified:
388+
389+
.. code-block:: c++
390+
391+
const char format[] = {'h', 'e', 'l', 'l', 'o', ' ', '%', 's', 0};
392+
printf(format, "world");
393+
// no warning
394+
395+
printf(format, 123);
396+
// warning: format specifies type 'char *' but the argument has type 'int'
397+
398+
printf(("%"s + "i"s).c_str(), "world");
399+
// warning: format specifies type 'int' but the argument has type 'char *'
400+
401+
When the format expression does not evaluate to a string literal, Clang
402+
points diagnostics into a pseudo-file called ``<scratch space>`` that contains
403+
the format string literal as it evaluated, like so:
404+
405+
.. code-block:: text
406+
407+
example.c:6:17: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
408+
6 | printf(format, 123);
409+
| ~~~~~~ ^~~
410+
<scratch space>:1:4: note: format string resolved to a constant string
411+
1 | "hello %s"
412+
| ^~
413+
| %d
414+
415+
This may mean that format strings which were previously unverified (or which
416+
triggered ``-Wformat-nonliteral``) are now verified by ``-Wformat`` and its
417+
allies.
387418

388419
- Introduced a new statement attribute ``[[clang::atomic]]`` that enables
389420
fine-grained control over atomic code generation on a per-statement basis.

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10355,7 +10355,7 @@ def warn_format_bool_as_character : Warning<
1035510355
InGroup<Format>;
1035610356
def note_format_string_defined : Note<"format string is defined here">;
1035710357
def note_format_string_evaluated_to : Note<
10358-
"format string was constant-evaluated">;
10358+
"format string resolved to a constant string">;
1035910359
def note_format_fix_specifier : Note<"did you mean to use '%0'?">;
1036010360
def note_printf_c_str: Note<"did you mean to call the %0 method?">;
1036110361
def note_format_security_fixit: Note<

clang/lib/AST/ExprConstant.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17981,14 +17981,17 @@ static bool EvaluateStringAsLValue(EvalInfo &Info, const Expr *E,
1798117981
String.addArray(Info, E, CAT);
1798217982
else
1798317983
String.addUnsizedArray(Info, E, CharTy);
17984-
} else if (Ty->hasPointerRepresentation()) {
17984+
return true;
17985+
}
17986+
17987+
if (Ty->hasPointerRepresentation()) {
1798517988
if (!EvaluatePointer(E, String, Info))
1798617989
return false;
1798717990
CharTy = Ty->getPointeeType();
17988-
} else {
17989-
return false;
17991+
return true;
1799017992
}
17991-
return true;
17993+
17994+
return false;
1799217995
}
1799317996

1799417997
static const StringLiteral *StringLValueIsLiteral(EvalInfo &Info,

clang/lib/Sema/SemaChecking.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6050,15 +6050,22 @@ static void CheckFormatString(
60506050
llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
60516051
bool IgnoreStringsWithoutSpecifiers);
60526052

6053-
enum StringLiteralConstEvalResult {
6053+
enum StringLiteralConstantEvaluationResult {
60546054
SLCER_NotEvaluated,
60556055
SLCER_NotNullTerminated,
60566056
SLCER_Evaluated,
60576057
};
60586058

6059-
static StringLiteralConstEvalResult
6060-
constEvalStringAsLiteral(Sema &S, const Expr *E, const StringLiteral *&SL,
6061-
uint64_t &Offset);
6059+
/// Attempt to fold \c E into a constant string that \c checkFormatStringExpr
6060+
/// can use. If \c E folds to a string literal, that string literal will be used
6061+
/// for diagnostics. If \c E has a constant string value but it does not fold to
6062+
/// a literal (for instance, ("%"s + "i"s).c_str() constant-folds to "%i"), a
6063+
/// <scratch space> pseudo-source file will be allocated, containing a string
6064+
/// literal representation of the constant string, and format diagnostics will
6065+
/// point to it.
6066+
static StringLiteralConstantEvaluationResult
6067+
EvaluateStringAndCreateLiteral(Sema &S, const Expr *E, const StringLiteral *&SL,
6068+
uint64_t &Offset);
60626069

60636070
// Determine if an expression is a string literal or constant string.
60646071
// If this function returns false on the arguments to a function expecting a
@@ -6447,7 +6454,7 @@ static StringLiteralCheckType checkFormatStringExpr(
64476454

64486455
uint64_t EvalOffset = 0;
64496456
const StringLiteral *FakeLiteral = nullptr;
6450-
switch (constEvalStringAsLiteral(S, E, FakeLiteral, EvalOffset)) {
6457+
switch (EvaluateStringAndCreateLiteral(S, E, FakeLiteral, EvalOffset)) {
64516458
case SLCER_NotEvaluated:
64526459
return SLCT_NotALiteral;
64536460

@@ -6469,9 +6476,9 @@ static StringLiteralCheckType checkFormatStringExpr(
64696476
}
64706477
}
64716478

6472-
static StringLiteralConstEvalResult
6473-
constEvalStringAsLiteral(Sema &S, const Expr *E, const StringLiteral *&SL,
6474-
uint64_t &Offset) {
6479+
static StringLiteralConstantEvaluationResult
6480+
EvaluateStringAndCreateLiteral(Sema &S, const Expr *E, const StringLiteral *&SL,
6481+
uint64_t &Offset) {
64756482
// As a last resort, try to constant-evaluate the format string.
64766483
bool HasNul;
64776484
auto SER = E->tryEvaluateString(S.Context, &HasNul);
@@ -6500,7 +6507,7 @@ constEvalStringAsLiteral(Sema &S, const Expr *E, const StringLiteral *&SL,
65006507
"<scratch space>", true));
65016508
}
65026509

6503-
auto ScratchFile = S.getSourceManager().createFileID(std::move(MemBuf));
6510+
FileID ScratchFile = S.getSourceManager().createFileID(std::move(MemBuf));
65046511
SourceLocation Begin = S.getSourceManager().getLocForStartOfFile(ScratchFile);
65056512
QualType SLType = S.Context.getStringLiteralArrayType(
65066513
S.Context.CharTy, SER->getString().size());

0 commit comments

Comments
 (0)