Skip to content

Commit ebdc2a3

Browse files
committed
[ADT] Fix llvm::concat_iterator for ValueT == common_base_class *
Fix llvm::concat_iterator for the case of `ValueT` being a pointer to a common base class to which the result of dereferencing any iterator in `ItersT` can be casted to.
1 parent c7d8581 commit ebdc2a3

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

llvm/include/llvm/ADT/STLExtras.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,14 +1030,15 @@ class concat_iterator
10301030
std::forward_iterator_tag, ValueT> {
10311031
using BaseT = typename concat_iterator::iterator_facade_base;
10321032

1033-
static constexpr bool ReturnsByValue =
1034-
!(std::is_reference_v<decltype(*std::declval<IterTs>())> && ...);
1033+
static constexpr bool ReturnsValueOrPointer =
1034+
!(std::is_reference_v<decltype(*std::declval<IterTs>())> && ...)
1035+
|| (std::is_pointer_v<IterTs> && ...);
10351036

10361037
using reference_type =
1037-
typename std::conditional_t<ReturnsByValue, ValueT, ValueT &>;
1038+
typename std::conditional_t<ReturnsValueOrPointer, ValueT, ValueT &>;
10381039

10391040
using handle_type =
1040-
typename std::conditional_t<ReturnsByValue, std::optional<ValueT>,
1041+
typename std::conditional_t<ReturnsValueOrPointer, std::optional<ValueT>,
10411042
ValueT *>;
10421043

10431044
/// We store both the current and end iterators for each concatenated
@@ -1088,7 +1089,7 @@ class concat_iterator
10881089
if (Begin == End)
10891090
return {};
10901091

1091-
if constexpr (ReturnsByValue)
1092+
if constexpr (ReturnsValueOrPointer)
10921093
return *Begin;
10931094
else
10941095
return &*Begin;

llvm/unittests/ADT/STLExtrasTest.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,9 @@ struct some_struct {
398398
std::string swap_val;
399399
};
400400

401+
struct derives_from_some_struct : some_struct {
402+
};
403+
401404
std::vector<int>::const_iterator begin(const some_struct &s) {
402405
return s.data.begin();
403406
}
@@ -532,6 +535,19 @@ TEST(STLExtrasTest, ConcatRangeADL) {
532535
EXPECT_THAT(concat<const int>(S0, S1), ElementsAre(1, 2, 3, 4));
533536
}
534537

538+
TEST(STLExtrasTest, ConcatRangePtrToDerivedClass) {
539+
auto S0 = std::make_unique<some_namespace::some_struct>();
540+
auto S1 = std::make_unique<some_namespace::derives_from_some_struct>();
541+
SmallVector<some_namespace::some_struct *> V0{S0.get()};
542+
SmallVector<some_namespace::derives_from_some_struct *> V1{S1.get(), S1.get()};
543+
544+
// Use concat over ranges of pointers to different (but related) types.
545+
EXPECT_THAT(concat<some_namespace::some_struct *>(V0, V1),
546+
ElementsAre(S0.get(),
547+
static_cast<some_namespace::some_struct *>(S1.get()),
548+
static_cast<some_namespace::some_struct *>(S1.get())));
549+
}
550+
535551
TEST(STLExtrasTest, MakeFirstSecondRangeADL) {
536552
// Make sure that we use the `begin`/`end` functions from `some_namespace`,
537553
// using ADL.

0 commit comments

Comments
 (0)