Skip to content

Commit

Permalink
[ADT] Defend against getting slightly wrong template arguments passed
Browse files Browse the repository at this point in the history
into CRTP base classes.

This can sometimes happen and not cause an immediate failure when the
derived class is, itself, a template. You can end up essentially calling
methods on the wrong derived type but a type where many things will
appear to "work".

To fail fast and with a clear error message we can use a static_assert,
but we have to stash that static_assert inside a method body or nested
type that won't need to be completed while building the base class. I've
tried to pick a reasonably small number of places that seemed like
reliably places for this to be instantiated.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@294271 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
chandlerc committed Feb 7, 2017
1 parent 1511b08 commit 167cdd0
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 1 deletion.
2 changes: 2 additions & 0 deletions include/llvm/ADT/DenseMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,8 @@ class DenseMapBase : public DebugEpochBase {
return KeyInfoT::getHashValue(Val);
}
static const KeyT getEmptyKey() {
static_assert(std::is_base_of<DenseMapBase, DerivedT>::value,
"Must pass the derived type to this template!");
return KeyInfoT::getEmptyKey();
}
static const KeyT getTombstoneKey() {
Expand Down
9 changes: 8 additions & 1 deletion include/llvm/ADT/iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class iterator_facade_base

public:
DerivedT operator+(DifferenceTypeT n) const {
static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
"Must pass the derived type to this template!");
static_assert(
IsRandomAccess,
"The '+' operator is only defined for random access iterators.");
Expand All @@ -114,6 +116,8 @@ class iterator_facade_base
}

DerivedT &operator++() {
static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
"Must pass the derived type to this template!");
return static_cast<DerivedT *>(this)->operator+=(1);
}
DerivedT operator++(int) {
Expand Down Expand Up @@ -202,7 +206,10 @@ class iterator_adaptor_base

iterator_adaptor_base() = default;

explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) {}
explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) {
static_assert(std::is_base_of<iterator_adaptor_base, DerivedT>::value,
"Must pass the derived type to this template!");
}

const WrappedIteratorT &wrapped() const { return I; }

Expand Down

0 comments on commit 167cdd0

Please sign in to comment.