Skip to content

Commit 70e06e6

Browse files
Simplify loops around getPosition() groups
1 parent 94a5aa6 commit 70e06e6

File tree

1 file changed

+45
-46
lines changed

1 file changed

+45
-46
lines changed

clang/lib/Sema/SemaChecking.cpp

Lines changed: 45 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7332,8 +7332,8 @@ bool EquatableFormatArgument::VerifyCompatible(
73327332
S.PDiag(diag::warn_format_cmp_sensitivity_mismatch)
73337333
<< Sensitivity << Other.Sensitivity,
73347334
FmtExpr, InFunctionCall);
7335-
S.Diag(Other.ElementLoc, diag::note_format_cmp_with) << 0 << Other.Range;
7336-
HadError = true;
7335+
HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with)
7336+
<< 0 << Other.Range;
73377337
}
73387338

73397339
switch (ArgType.matchesArgType(S.Context, Other.ArgType)) {
@@ -7351,8 +7351,8 @@ bool EquatableFormatArgument::VerifyCompatible(
73517351
<< buildFormatSpecifier()
73527352
<< Other.buildFormatSpecifier(),
73537353
FmtExpr, InFunctionCall);
7354-
S.Diag(Other.ElementLoc, diag::note_format_cmp_with) << 0 << Other.Range;
7355-
HadError = true;
7354+
HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with)
7355+
<< 0 << Other.Range;
73567356
break;
73577357

73587358
case MK::NoMatchPedantic:
@@ -7361,8 +7361,8 @@ bool EquatableFormatArgument::VerifyCompatible(
73617361
<< buildFormatSpecifier()
73627362
<< Other.buildFormatSpecifier(),
73637363
FmtExpr, InFunctionCall);
7364-
S.Diag(Other.ElementLoc, diag::note_format_cmp_with) << 0 << Other.Range;
7365-
HadError = true;
7364+
HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with)
7365+
<< 0 << Other.Range;
73667366
break;
73677367

73687368
case MK::NoMatchSignedness:
@@ -7374,8 +7374,8 @@ bool EquatableFormatArgument::VerifyCompatible(
73747374
<< buildFormatSpecifier()
73757375
<< Other.buildFormatSpecifier(),
73767376
FmtExpr, InFunctionCall);
7377-
S.Diag(Other.ElementLoc, diag::note_format_cmp_with) << 0 << Other.Range;
7378-
HadError = true;
7377+
HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with)
7378+
<< 0 << Other.Range;
73797379
}
73807380
break;
73817381
}
@@ -8500,52 +8500,50 @@ static bool CompareFormatSpecifiers(Sema &S, const StringLiteral *Ref,
85008500
auto RefIter = RefArgs.begin(), RefEnd = RefArgs.end();
85018501
while (FmtIter < FmtEnd && RefIter < RefEnd) {
85028502
// In positional-style format strings, the same specifier can appear
8503-
// multiple times. In the Ref format string, we have already verified that
8504-
// each repetition of the same positional specifier are mutually compatible,
8505-
// so we only need to test each repetition in the Fmt string with the first
8506-
// corresponding Ref specifier.
8507-
auto FmtIterEnd = std::find_if(FmtIter + 1, FmtEnd, [=](const auto &Arg) {
8508-
return Arg.getPosition() != FmtIter->getPosition();
8509-
});
8510-
auto RefIterEnd = std::find_if(RefIter + 1, RefEnd, [=](const auto &Arg) {
8511-
return Arg.getPosition() != RefIter->getPosition();
8512-
});
8503+
// multiple times (like %2$i %2$d). Specifiers in both RefArgs and FmtArgs
8504+
// are sorted by getPosition(), and we process each range of equal
8505+
// getPosition() values as one group.
8506+
// RefArgs are taken from a string literal that was given to
8507+
// attribute(format_matches), and if we got this far, we have already
8508+
// verified that if it has positional specifiers that appear in multiple
8509+
// locations, then they are all mutually compatible. What's left for us to
8510+
// do is verify that all specifiers with the same position in FmtArgs are
8511+
// compatible with the RefArgs specifiers. We check each specifier from
8512+
// FmtArgs against the first member of the RefArgs group.
8513+
for (; FmtIter < FmtEnd; ++FmtIter) {
8514+
// Clang does not diagnose missing format specifiers in positional-style
8515+
// strings (TODO: which it probably should do, as it is UB to skip over a
8516+
// format argument). Skip specifiers if needed.
8517+
if (FmtIter->getPosition() < RefIter->getPosition())
8518+
continue;
85138519

8514-
// Clang does not diagnose missing format specifiers in positional-style
8515-
// strings (TODO: which it probably should do, as it is UB to skip over a
8516-
// format argument). Skip specifiers if needed.
8517-
if (FmtIter->getPosition() < RefIter->getPosition()) {
8518-
FmtIter = FmtIterEnd;
8519-
continue;
8520-
}
8521-
if (RefIter->getPosition() < FmtIter->getPosition()) {
8522-
RefIter = RefIterEnd;
8523-
continue;
8524-
}
8520+
// Delimits a new getPosition() value.
8521+
if (FmtIter->getPosition() > RefIter->getPosition())
8522+
break;
85258523

8526-
while (FmtIter != FmtIterEnd) {
85278524
HadError |=
85288525
!FmtIter->VerifyCompatible(S, *RefIter, FmtExpr, InFunctionCall);
8529-
++FmtIter;
85308526
}
8531-
RefIter = RefIterEnd;
8527+
8528+
// Jump RefIter to the start of the next group.
8529+
RefIter = std::find_if(RefIter + 1, RefEnd, [=](const auto &Arg) {
8530+
return Arg.getPosition() != RefIter->getPosition();
8531+
});
85328532
}
85338533

85348534
if (FmtIter < FmtEnd) {
85358535
CheckFormatHandler::EmitFormatDiagnostic(
85368536
S, InFunctionCall, FmtExpr,
85378537
S.PDiag(diag::warn_format_cmp_specifier_arity) << 1,
85388538
FmtExpr->getBeginLoc(), false, FmtIter->getSourceRange());
8539-
S.Diag(Ref->getBeginLoc(), diag::note_format_cmp_with) << 1;
8540-
HadError = true;
8539+
HadError = S.Diag(Ref->getBeginLoc(), diag::note_format_cmp_with) << 1;
85418540
} else if (RefIter < RefEnd) {
85428541
CheckFormatHandler::EmitFormatDiagnostic(
85438542
S, InFunctionCall, FmtExpr,
85448543
S.PDiag(diag::warn_format_cmp_specifier_arity) << 0,
85458544
FmtExpr->getBeginLoc(), false, Fmt->getSourceRange());
8546-
S.Diag(Ref->getBeginLoc(), diag::note_format_cmp_with)
8547-
<< 1 << RefIter->getSourceRange();
8548-
HadError = true;
8545+
HadError = S.Diag(Ref->getBeginLoc(), diag::note_format_cmp_with)
8546+
<< 1 << RefIter->getSourceRange();
85498547
}
85508548
return !HadError;
85518549
}
@@ -8683,21 +8681,22 @@ bool Sema::ValidateFormatString(FormatStringType Type,
86838681
true, Args))
86848682
return false;
86858683

8686-
// If positional arguments are used multiple times in the same format string,
8687-
// ensure that they are used in compatible ways.
8684+
// Group arguments by getPosition() value, and check that each member of the
8685+
// group is compatible with the first member. This verifies that when
8686+
// positional arguments are used multiple times (such as %2$i %2$d), all uses
8687+
// are mutually compatible. As an optimization, don't test the first member
8688+
// against itself.
86888689
bool HadError = false;
86898690
auto Iter = Args.begin();
86908691
auto End = Args.end();
86918692
while (Iter != End) {
8692-
auto PosEnd = std::find_if(Iter + 1, End, [=](const auto &Arg) {
8693-
return Arg.getPosition() != Iter->getPosition();
8694-
});
8695-
for (auto PosIter = Iter + 1; PosIter != PosEnd; ++PosIter) {
8696-
HadError |= !PosIter->VerifyCompatible(*this, *Iter, Str, true);
8693+
const auto &FirstInGroup = *Iter;
8694+
for (++Iter;
8695+
Iter != End && Iter->getPosition() == FirstInGroup.getPosition();
8696+
++Iter) {
8697+
HadError |= !Iter->VerifyCompatible(*this, FirstInGroup, Str, true);
86978698
}
8698-
Iter = PosEnd;
86998699
}
8700-
87018700
return !HadError;
87028701
}
87038702

0 commit comments

Comments
 (0)