Skip to content

Commit 560fccc

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 560fccc

File tree

2 files changed

+23
-5
lines changed

2 files changed

+23
-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: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ struct some_struct {
398398
std::string swap_val;
399399
};
400400

401+
struct derives_from_some_struct : some_struct {};
402+
401403
std::vector<int>::const_iterator begin(const some_struct &s) {
402404
return s.data.begin();
403405
}
@@ -532,6 +534,21 @@ TEST(STLExtrasTest, ConcatRangeADL) {
532534
EXPECT_THAT(concat<const int>(S0, S1), ElementsAre(1, 2, 3, 4));
533535
}
534536

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

0 commit comments

Comments
 (0)