Skip to content

[llvm] Input iterators should not const-overload operator* with varying return types #119084

@StephanTLavavej

Description

@StephanTLavavej

The C++ Standard requires that input (and stronger) iterators return the same type when dereferenced, regardless of the top-level constness of the iterator. This is N4993 [iterator.cpp17.general]/1:

In the following sections, a and b denote values of type X or const X, difference_type and reference refer to the types iterator_traits<X>::difference_type and iterator_traits<X>::reference, respectively

followed by [tab:inputiterator]:

Expression: *a
Return type: reference, convertible to T

In MSVC's STL, we recently merged microsoft/STL#5135, which innocently added top-level constness to an iterator before dereferencing it, and that broke LLVM's build when this iterator was passed to std::uninitialized_copy:

const Value *operator*() const {
ValueAsMetadata *VAM = isa<ValueAsMetadata *>(I)
? cast<ValueAsMetadata *>(I)
: *cast<ValueAsMetadata **>(I);
return VAM->getValue();
};
Value *operator*() {

LLVM's iterator should not be overloading const Value *operator*() const and Value *operator*() with a varying return type like this. I searched this directory, and found a very similar occurrence:

const Value *operator*() const {
ValueAsMetadata *VAM = isa<ValueAsMetadata *>(I)
? cast<ValueAsMetadata *>(I)
: *cast<ValueAsMetadata **>(I);
return VAM->getValue();
};
Value *operator*() {

And more potentially affected occurrences:

ValueT &operator*() { return I->getFirst(); }
const ValueT &operator*() const { return I->getFirst(); }

const StringRef &operator*() const { return Current; }
StringRef &operator*() { return Current; }

const StringRef &operator*() const { return ThisValue; }
StringRef &operator*() { return ThisValue; }

reference operator*() {
assertIsChecked();
return *getStorage();
}
/// Returns a const reference to the stored T value.
const_reference operator*() const {

C &operator*() {
void *Tmp = Ptr.load(std::memory_order_acquire);
if (!Tmp)
RegisterManagedStatic(Creator::call, Deleter::call);
return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
}
C *operator->() { return &**this; }
const C &operator*() const {

I'm probably going to have to revert this specific change of adding top-level constness within MSVC's STL, but I wanted to let you know about these non-conforming LLVM iterators.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions