Skip to content

Commit 2984a8d

Browse files
authored
[Clang] Fix an iterator invalidation bug in concept normalization cache (#165352)
The NormalizationCache may be inserted recursively when normalizing template arguments with non-dependent default arguments. Since the ADT doesn't preserve iterator validity, this caused undefined behavior. This is a regression on trunk so there is no release note. Fixes #165238
1 parent 385c121 commit 2984a8d

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed

clang/lib/Sema/SemaConcept.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2408,11 +2408,16 @@ const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints(
24082408
if (CacheEntry == NormalizationCache.end()) {
24092409
auto *Normalized = NormalizedConstraint::fromAssociatedConstraints(
24102410
*this, ND, AssociatedConstraints);
2411+
if (!Normalized) {
2412+
NormalizationCache.try_emplace(ConstrainedDeclOrNestedReq, nullptr);
2413+
return nullptr;
2414+
}
2415+
// substitute() can invalidate iterators of NormalizationCache.
2416+
bool Failed = SubstituteParameterMappings(*this).substitute(*Normalized);
24112417
CacheEntry =
24122418
NormalizationCache.try_emplace(ConstrainedDeclOrNestedReq, Normalized)
24132419
.first;
2414-
if (!Normalized ||
2415-
SubstituteParameterMappings(*this).substitute(*Normalized))
2420+
if (Failed)
24162421
return nullptr;
24172422
}
24182423
return CacheEntry->second;

clang/test/SemaTemplate/concepts.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,3 +1632,29 @@ void fn3() {
16321632
}
16331633

16341634
}
1635+
1636+
namespace GH165238 {
1637+
1638+
namespace std {
1639+
template <typename, typename _Tp>
1640+
concept output_iterator = requires(_Tp __t) { __t; };
1641+
template <typename _Out> struct basic_format_context {
1642+
static_assert(output_iterator<_Out, int>);
1643+
using char_type = _Out;
1644+
};
1645+
template <typename> class basic_format_parse_context;
1646+
template <typename, typename _Context, typename _Formatter,
1647+
typename = basic_format_parse_context<typename _Context::char_type>>
1648+
concept __parsable_with = requires(_Formatter __f) { __f; };
1649+
template <typename _Tp, typename _CharT,
1650+
typename _Context = basic_format_context<_CharT>>
1651+
concept __formattable_impl = __parsable_with<_Tp, _Context, _Context>;
1652+
template <typename _Tp, typename _CharT>
1653+
concept formattable = __formattable_impl<_Tp, _CharT>;
1654+
} // namespace std
1655+
struct {
1656+
void operator()(std::formattable<char> auto);
1657+
} call;
1658+
void foo() { call(""); }
1659+
1660+
}

0 commit comments

Comments
 (0)