Skip to content

Commit

Permalink
Make LLVM build in C++20 mode
Browse files Browse the repository at this point in the history
Part of the <=> changes in C++20 make certain patterns of writing equality
operators ambiguous with themselves (sorry!).
This patch goes through and adjusts all the comparison operators such that
they should work in both C++17 and C++20 modes. It also makes two other small
C++20-specific changes (adding a constructor to a type that cases to be an
aggregate, and adding casts from u8 literals which no longer have type
const char*).

There were four categories of errors that this review fixes.
Here are canonical examples of them, ordered from most to least common:

// 1) Missing const
namespace missing_const {
    struct A {
    #ifndef FIXED
        bool operator==(A const&);
    #else
        bool operator==(A const&) const;
    #endif
    };

    bool a = A{} == A{}; // error
}

// 2) Type mismatch on CRTP
namespace crtp_mismatch {
    template <typename Derived>
    struct Base {
    #ifndef FIXED
        bool operator==(Derived const&) const;
    #else
        // in one case changed to taking Base const&
        friend bool operator==(Derived const&, Derived const&);
    #endif
    };

    struct D : Base<D> { };

    bool b = D{} == D{}; // error
}

// 3) iterator/const_iterator with only mixed comparison
namespace iter_const_iter {
    template <bool Const>
    struct iterator {
        using const_iterator = iterator<true>;

        iterator();

        template <bool B, std::enable_if_t<(Const && !B), int> = 0>
        iterator(iterator<B> const&);

    #ifndef FIXED
        bool operator==(const_iterator const&) const;
    #else
        friend bool operator==(iterator const&, iterator const&);
    #endif
    };

    bool c = iterator<false>{} == iterator<false>{} // error
          || iterator<false>{} == iterator<true>{}
          || iterator<true>{} == iterator<false>{}
          || iterator<true>{} == iterator<true>{};
}

// 4) Same-type comparison but only have mixed-type operator
namespace ambiguous_choice {
    enum Color { Red };

    struct C {
        C();
        C(Color);
        operator Color() const;
        bool operator==(Color) const;
        friend bool operator==(C, C);
    };

    bool c = C{} == C{}; // error
    bool d = C{} == Red;
}

Differential revision: https://reviews.llvm.org/D78938
  • Loading branch information
brevzin authored and nunoplopes committed Dec 17, 2020
1 parent cdb692e commit 9231045
Show file tree
Hide file tree
Showing 27 changed files with 108 additions and 98 deletions.
9 changes: 5 additions & 4 deletions clang/include/clang/AST/StmtIterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,13 @@ class StmtIteratorImpl : public StmtIteratorBase,
return tmp;
}

bool operator==(const DERIVED& RHS) const {
return stmt == RHS.stmt && DGI == RHS.DGI && RawVAPtr == RHS.RawVAPtr;
friend bool operator==(const DERIVED &LHS, const DERIVED &RHS) {
return LHS.stmt == RHS.stmt && LHS.DGI == RHS.DGI &&
LHS.RawVAPtr == RHS.RawVAPtr;
}

bool operator!=(const DERIVED& RHS) const {
return stmt != RHS.stmt || DGI != RHS.DGI || RawVAPtr != RHS.RawVAPtr;
friend bool operator!=(const DERIVED &LHS, const DERIVED &RHS) {
return !(LHS == RHS);
}

REFERENCE operator*() const {
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Parse/ParseOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ enum OpenMPDirectiveKindEx {
struct OpenMPDirectiveKindExWrapper {
OpenMPDirectiveKindExWrapper(unsigned Value) : Value(Value) {}
OpenMPDirectiveKindExWrapper(OpenMPDirectiveKind DK) : Value(unsigned(DK)) {}
bool operator==(OpenMPDirectiveKindExWrapper V) const {
return Value == V.Value;
}
bool operator!=(OpenMPDirectiveKindExWrapper V) const {
return Value != V.Value;
}
bool operator==(OpenMPDirectiveKind V) const { return Value == unsigned(V); }
bool operator!=(OpenMPDirectiveKind V) const { return Value != unsigned(V); }
bool operator<(OpenMPDirectiveKind V) const { return Value < unsigned(V); }
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ class GenericTaintChecker : public Checker<check::PreCall, check::PostCall> {

struct FunctionData {
FunctionData() = delete;
FunctionData(const FunctionDecl *FDecl, StringRef Name,
std::string FullName)
: FDecl(FDecl), Name(Name), FullName(std::move(FullName)) {}
FunctionData(const FunctionData &) = default;
FunctionData(FunctionData &&) = default;
FunctionData &operator=(const FunctionData &) = delete;
Expand All @@ -123,7 +126,7 @@ class GenericTaintChecker : public Checker<check::PreCall, check::PostCall> {
if (Name.empty() || FullName.empty())
return None;

return FunctionData{FDecl, Name, FullName};
return FunctionData{FDecl, Name, std::move(FullName)};
}

bool isInScope(StringRef Scope) const {
Expand Down
7 changes: 0 additions & 7 deletions llvm/include/llvm/ADT/AllocatorList.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,6 @@ template <class T, class AllocatorT> class AllocatorList : AllocatorT {

reference operator*() const { return base_type::wrapped()->V; }
pointer operator->() const { return &operator*(); }

friend bool operator==(const IteratorImpl &L, const IteratorImpl &R) {
return L.wrapped() == R.wrapped();
}
friend bool operator!=(const IteratorImpl &L, const IteratorImpl &R) {
return !(L == R);
}
};

public:
Expand Down
20 changes: 8 additions & 12 deletions llvm/include/llvm/ADT/DenseMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -1242,22 +1242,18 @@ class DenseMapIterator : DebugEpochBase::HandleBase {
return Ptr;
}

template <typename T>
bool operator==(const T &RHS) const {
assert((!Ptr || isHandleInSync()) && "handle not in sync!");
friend bool operator==(const DenseMapIterator &LHS,
const DenseMapIterator &RHS) {
assert((!LHS.Ptr || LHS.isHandleInSync()) && "handle not in sync!");
assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
assert(getEpochAddress() == RHS.getEpochAddress() &&
assert(LHS.getEpochAddress() == RHS.getEpochAddress() &&
"comparing incomparable iterators!");
return Ptr == RHS.Ptr;
return LHS.Ptr == RHS.Ptr;
}

template <typename T>
bool operator!=(const T &RHS) const {
assert((!Ptr || isHandleInSync()) && "handle not in sync!");
assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
assert(getEpochAddress() == RHS.getEpochAddress() &&
"comparing incomparable iterators!");
return Ptr != RHS.Ptr;
friend bool operator!=(const DenseMapIterator &LHS,
const DenseMapIterator &RHS) {
return !(LHS == RHS);
}

inline DenseMapIterator& operator++() { // Preincrement
Expand Down
16 changes: 12 additions & 4 deletions llvm/include/llvm/ADT/DenseSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,12 @@ class DenseSetImpl {

Iterator& operator++() { ++I; return *this; }
Iterator operator++(int) { auto T = *this; ++I; return T; }
bool operator==(const ConstIterator& X) const { return I == X.I; }
bool operator!=(const ConstIterator& X) const { return I != X.I; }
friend bool operator==(const Iterator &X, const Iterator &Y) {
return X.I == Y.I;
}
friend bool operator!=(const Iterator &X, const Iterator &Y) {
return X.I != Y.I;
}
};

class ConstIterator {
Expand All @@ -155,8 +159,12 @@ class DenseSetImpl {

ConstIterator& operator++() { ++I; return *this; }
ConstIterator operator++(int) { auto T = *this; ++I; return T; }
bool operator==(const ConstIterator& X) const { return I == X.I; }
bool operator!=(const ConstIterator& X) const { return I != X.I; }
friend bool operator==(const ConstIterator &X, const ConstIterator &Y) {
return X.I == Y.I;
}
friend bool operator!=(const ConstIterator &X, const ConstIterator &Y) {
return X.I != Y.I;
}
};

using iterator = Iterator;
Expand Down
14 changes: 10 additions & 4 deletions llvm/include/llvm/ADT/DirectedGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ template <class NodeType, class EdgeType> class DGEdge {

/// Static polymorphism: delegate implementation (via isEqualTo) to the
/// derived class.
bool operator==(const EdgeType &E) const { return getDerived().isEqualTo(E); }
bool operator!=(const EdgeType &E) const { return !operator==(E); }
bool operator==(const DGEdge &E) const {
return getDerived().isEqualTo(E.getDerived());
}
bool operator!=(const DGEdge &E) const { return !operator==(E); }

/// Retrieve the target node this edge connects to.
const NodeType &getTargetNode() const { return TargetNode; }
Expand Down Expand Up @@ -91,8 +93,12 @@ template <class NodeType, class EdgeType> class DGNode {

/// Static polymorphism: delegate implementation (via isEqualTo) to the
/// derived class.
bool operator==(const NodeType &N) const { return getDerived().isEqualTo(N); }
bool operator!=(const NodeType &N) const { return !operator==(N); }
friend bool operator==(const NodeType &M, const NodeType &N) {
return M.isEqualTo(N);
}
friend bool operator!=(const NodeType &M, const NodeType &N) {
return !(M == N);
}

const_iterator begin() const { return Edges.begin(); }
const_iterator end() const { return Edges.end(); }
Expand Down
8 changes: 4 additions & 4 deletions llvm/include/llvm/ADT/STLExtras.h
Original file line number Diff line number Diff line change
Expand Up @@ -555,12 +555,12 @@ class early_inc_iterator_impl
return *this;
}

using BaseT::operator==;
bool operator==(const early_inc_iterator_impl &RHS) const {
friend bool operator==(const early_inc_iterator_impl &LHS,
const early_inc_iterator_impl &RHS) {
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
assert(!IsEarlyIncremented && "Cannot compare after dereferencing!");
assert(!LHS.IsEarlyIncremented && "Cannot compare after dereferencing!");
#endif
return BaseT::operator==(RHS);
return (const BaseT &)LHS == (const BaseT &)RHS;
}
};

Expand Down
4 changes: 3 additions & 1 deletion llvm/include/llvm/ADT/StringMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,9 @@ class StringMapIterBase
return static_cast<DerivedTy &>(*this);
}

bool operator==(const DerivedTy &RHS) const { return Ptr == RHS.Ptr; }
friend bool operator==(const DerivedTy &LHS, const DerivedTy &RHS) {
return LHS.Ptr == RHS.Ptr;
}

DerivedTy &operator++() { // Preincrement
++Ptr;
Expand Down
22 changes: 14 additions & 8 deletions llvm/include/llvm/ADT/iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,28 +142,30 @@ class iterator_facade_base
return tmp;
}

#ifndef __cpp_impl_three_way_comparison
bool operator!=(const DerivedT &RHS) const {
return !static_cast<const DerivedT *>(this)->operator==(RHS);
return !(static_cast<const DerivedT &>(*this) == RHS);
}
#endif

bool operator>(const DerivedT &RHS) const {
static_assert(
IsRandomAccess,
"Relational operators are only defined for random access iterators.");
return !static_cast<const DerivedT *>(this)->operator<(RHS) &&
!static_cast<const DerivedT *>(this)->operator==(RHS);
return !(static_cast<const DerivedT &>(*this) < RHS) &&
!(static_cast<const DerivedT &>(*this) == RHS);
}
bool operator<=(const DerivedT &RHS) const {
static_assert(
IsRandomAccess,
"Relational operators are only defined for random access iterators.");
return !static_cast<const DerivedT *>(this)->operator>(RHS);
return !(static_cast<const DerivedT &>(*this) > RHS);
}
bool operator>=(const DerivedT &RHS) const {
static_assert(
IsRandomAccess,
"Relational operators are only defined for random access iterators.");
return !static_cast<const DerivedT *>(this)->operator<(RHS);
return !(static_cast<const DerivedT &>(*this) < RHS);
}

PointerT operator->() { return &static_cast<DerivedT *>(this)->operator*(); }
Expand Down Expand Up @@ -260,12 +262,16 @@ class iterator_adaptor_base
return *static_cast<DerivedT *>(this);
}

bool operator==(const DerivedT &RHS) const { return I == RHS.I; }
bool operator<(const DerivedT &RHS) const {
friend bool operator==(const iterator_adaptor_base &LHS,
const iterator_adaptor_base &RHS) {
return LHS.I == RHS.I;
}
friend bool operator<(const iterator_adaptor_base &LHS,
const iterator_adaptor_base &RHS) {
static_assert(
BaseT::IsRandomAccess,
"Relational operators are only defined for random access iterators.");
return I < RHS.I;
return LHS.I < RHS.I;
}

ReferenceT operator*() const { return *I; }
Expand Down
2 changes: 0 additions & 2 deletions llvm/include/llvm/CodeGen/DIE.h
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,6 @@ template <class T> class IntrusiveBackList : IntrusiveBackListBase {
T &operator*() const { return *static_cast<T *>(N); }

bool operator==(const iterator &X) const { return N == X.N; }
bool operator!=(const iterator &X) const { return N != X.N; }
};

class const_iterator
Expand All @@ -613,7 +612,6 @@ template <class T> class IntrusiveBackList : IntrusiveBackListBase {
const T &operator*() const { return *static_cast<const T *>(N); }

bool operator==(const const_iterator &X) const { return N == X.N; }
bool operator!=(const const_iterator &X) const { return N != X.N; }
};

iterator begin() {
Expand Down
4 changes: 2 additions & 2 deletions llvm/include/llvm/CodeGen/LiveInterval.h
Original file line number Diff line number Diff line change
Expand Up @@ -736,10 +736,10 @@ namespace llvm {
++*this;
return res;
}
bool operator!=(const SingleLinkedListIterator<T> &Other) {
bool operator!=(const SingleLinkedListIterator<T> &Other) const {
return P != Other.operator->();
}
bool operator==(const SingleLinkedListIterator<T> &Other) {
bool operator==(const SingleLinkedListIterator<T> &Other) const {
return P == Other.operator->();
}
T &operator*() const {
Expand Down
10 changes: 0 additions & 10 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
Original file line number Diff line number Diff line change
Expand Up @@ -382,11 +382,6 @@ inline bool operator==(const DWARFDie::iterator &LHS,
return LHS.Die == RHS.Die;
}

inline bool operator!=(const DWARFDie::iterator &LHS,
const DWARFDie::iterator &RHS) {
return !(LHS == RHS);
}

// These inline functions must follow the DWARFDie::iterator definition above
// as they use functions from that class.
inline DWARFDie::iterator DWARFDie::begin() const {
Expand Down Expand Up @@ -468,11 +463,6 @@ inline bool operator==(const std::reverse_iterator<DWARFDie::iterator> &LHS,
return LHS.equals(RHS);
}

inline bool operator!=(const std::reverse_iterator<DWARFDie::iterator> &LHS,
const std::reverse_iterator<DWARFDie::iterator> &RHS) {
return !(LHS == RHS);
}

inline std::reverse_iterator<DWARFDie::iterator> DWARFDie::rbegin() const {
return llvm::make_reverse_iterator(end());
}
Expand Down
5 changes: 0 additions & 5 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,5 @@ inline bool operator==(const DWARFExpression::iterator &LHS,
const DWARFExpression::iterator &RHS) {
return LHS.Expr == RHS.Expr && LHS.Offset == RHS.Offset;
}

inline bool operator!=(const DWARFExpression::iterator &LHS,
const DWARFExpression::iterator &RHS) {
return !(LHS == RHS);
}
}
#endif
6 changes: 2 additions & 4 deletions llvm/include/llvm/IR/Attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -938,10 +938,8 @@ class AttrBuilder {

bool td_empty() const { return TargetDepAttrs.empty(); }

bool operator==(const AttrBuilder &B);
bool operator!=(const AttrBuilder &B) {
return !(*this == B);
}
bool operator==(const AttrBuilder &B) const;
bool operator!=(const AttrBuilder &B) const { return !(*this == B); }
};

namespace AttributeFuncs {
Expand Down
4 changes: 3 additions & 1 deletion llvm/include/llvm/IR/BasicBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,9 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
phi_iterator_impl() = default;

// Allow conversion between instantiations where valid.
template <typename PHINodeU, typename BBIteratorU>
template <typename PHINodeU, typename BBIteratorU,
typename = std::enable_if_t<
std::is_convertible<PHINodeU *, PHINodeT *>::value>>
phi_iterator_impl(const phi_iterator_impl<PHINodeU, BBIteratorU> &Arg)
: PN(Arg.PN) {}

Expand Down
6 changes: 4 additions & 2 deletions llvm/include/llvm/Object/StackMapParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ class StackMapParser {
return tmp;
}

bool operator==(const AccessorIterator &Other) {
bool operator==(const AccessorIterator &Other) const {
return A.P == Other.A.P;
}

bool operator!=(const AccessorIterator &Other) { return !(*this == Other); }
bool operator!=(const AccessorIterator &Other) const {
return !(*this == Other);
}

AccessorT& operator*() { return A; }
AccessorT* operator->() { return &A; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ class CoverageMappingIterator
increment();
return *this;
}
bool operator==(const CoverageMappingIterator &RHS) {
bool operator==(const CoverageMappingIterator &RHS) const {
return Reader == RHS.Reader;
}
bool operator!=(const CoverageMappingIterator &RHS) {
bool operator!=(const CoverageMappingIterator &RHS) const {
return Reader != RHS.Reader;
}
Expected<CoverageMappingRecord &> operator*() {
Expand Down
8 changes: 6 additions & 2 deletions llvm/include/llvm/ProfileData/InstrProfReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@ class InstrProfIterator : public std::iterator<std::input_iterator_tag,
InstrProfIterator(InstrProfReader *Reader) : Reader(Reader) { Increment(); }

InstrProfIterator &operator++() { Increment(); return *this; }
bool operator==(const InstrProfIterator &RHS) { return Reader == RHS.Reader; }
bool operator!=(const InstrProfIterator &RHS) { return Reader != RHS.Reader; }
bool operator==(const InstrProfIterator &RHS) const {
return Reader == RHS.Reader;
}
bool operator!=(const InstrProfIterator &RHS) const {
return Reader != RHS.Reader;
}
value_type &operator*() { return Record; }
value_type *operator->() { return &Record; }
};
Expand Down
8 changes: 4 additions & 4 deletions llvm/include/llvm/Support/BinaryStreamRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,12 @@ template <class RefType, class StreamType> class BinaryStreamRefBase {

bool valid() const { return BorrowedImpl != nullptr; }

bool operator==(const RefType &Other) const {
if (BorrowedImpl != Other.BorrowedImpl)
friend bool operator==(const RefType &LHS, const RefType &RHS) {
if (LHS.BorrowedImpl != RHS.BorrowedImpl)
return false;
if (ViewOffset != Other.ViewOffset)
if (LHS.ViewOffset != RHS.ViewOffset)
return false;
if (Length != Other.Length)
if (LHS.Length != RHS.Length)
return false;
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions llvm/include/llvm/Support/SuffixTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,10 @@ class SuffixTree {
return It;
}

bool operator==(const RepeatedSubstringIterator &Other) {
bool operator==(const RepeatedSubstringIterator &Other) const {
return N == Other.N;
}
bool operator!=(const RepeatedSubstringIterator &Other) {
bool operator!=(const RepeatedSubstringIterator &Other) const {
return !(*this == Other);
}

Expand Down

0 comments on commit 9231045

Please sign in to comment.