[clang] [clang] Implement __attribute__((format_matches)) (PR #116708)

via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 6 09:14:03 PST 2025


=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/116708 at github.com>


================
@@ -7400,7 +7407,25 @@ bool DecomposePrintfHandler::GetSpecifiers(
       [](const EquatableFormatArgument &A, const EquatableFormatArgument &B) {
         return A.getPosition() < B.getPosition();
       });
-  return true;
+
+  // If there are duplicate positional arguments, ensure that they are all
+  // mutually compatible.
+  bool HadError = false;
+  auto ArgIter = Args.begin();
+  auto ArgEnd = Args.end();
+  while (ArgIter != ArgEnd) {
----------------
apple-fcloutier wrote:

At a high level, this groups `Args` by value of `getPosition()`, and for each group, we check that all arguments starting from index 1 are compatible with the argument at index 0. `Args` is already sorted by `getPosition()`, so the act of grouping is just to find the end iterator of each range. In `std::`, we have `lower_bound`/`upper_bound` that can be used to find the first and the one-past-the-end iterators for any given `getPosition()` value, but since we're going through the whole array anyways, I started at `begin()` and used `find_if` instead of `upper_bound`.

Now that you challenged me to find another way to write the same thing, I came up with this:

```
  bool HadError = false;
  auto Iter = Args.begin();
  auto End = Args.end();
  // Group arguments by getPosition() value, and check that each member of the group is
  // compatible with the first member. As an optimization, don't test the first member
  // against itself.
  while (Iter != End) {
    const auto &First = *Iter;
    for (++Iter; Iter != End && Iter->getPosition() == First.getPosition(); ++Iter) {
      HadError |= !Iter->VerifyCompatible(*this, First, Str, true);
    }
  }
```

which I think I like better, and if you like it better too, I will go with that.

https://github.com/llvm/llvm-project/pull/116708


More information about the cfe-commits mailing list