[PATCH] D112981: Fix iterator_adaptor_base/enumerator_iter to allow composition of llvm::enumerate with llvm::make_filter_range

Duncan P. N. Exon Smith via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 3 14:27:03 PDT 2021


dexonsmith added a comment.

This doesn't look correct to me.

Here are two examples that I think this patch breaks:

  // Setup: simple wrappers around `int *` and `const int *`.
  struct const_iterator : public iterator_adaptor_base<const_iterator, const int *> {};
  struct iterator : public iterator_adaptor_base<iterator, int *> {};
  
  // `const`-qualified iterators (wrapping `int *const` and `const int *const`).
  const int &ConstRef = *std::declval<const const_iterator &>(); // (example #1)
  int &Ref = *std::declval<const iterator &>(); // (example #2)

The `const`-qualification on `iterator_adaptor_base` should not affect the reference value:

- non-const iterator: `int *` (dereferencing returns `int &`)
- non-const iterator with `const`: `int *const` (dereferencing returns `int &`)
- const iterator: `const int *` (dereferencing returns `const int &`)
- const iterator with `const`: `const int *const` (dereferencing returns `const int &`)

I think I found the actual bug; see my inline comments.



================
Comment at: llvm/include/llvm/ADT/STLExtras.h:1920-1921
 
   result_type &operator*() { return Result; }
   const result_type &operator*() const { return Result; }
 
----------------
This is the actual bug. The `const`-ness of the iterator shouldn't affect the `const`-ness of the returned value.

The non-const `operator*()` should be deleted and only a `const result_type&` should ever be returned. The caller should never be allowed to modify `Result.Iter` or `Result.Index`.


================
Comment at: llvm/include/llvm/ADT/iterator.h:299-300
 
-  ReferenceT operator*() const { return *I; }
+  const ReferenceT operator*() const { return *I; }
+  ReferenceT operator*() { return *I; }
 };
----------------
If you used `std::add_const_t<ReferenceT>` then I think (1) would start compiling again but (2) would still fail.

I think this code change would "fix" the problem you encountered:
```
lang=c++
ReferenceT operator*() const { return *const_cast<WrappedIteratorT &>(I); }
```
... but I think the actual bug is in the `WrappedIteratorT`.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112981/new/

https://reviews.llvm.org/D112981



More information about the llvm-commits mailing list