[clang] [Clang] Fix an iterator invalidation bug in concept normalization cache (PR #165352)

Younan Zhang via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 27 22:12:05 PDT 2025


https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/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.

We convert it to std::map where the insert operation doesn't invalidate iterators, than calling find() twice for performance concerns.

This is a regression on trunk so there is no release note.

Fixes https://github.com/llvm/llvm-project/issues/165238

>From 1cd7eb42b24d9558d25ce3d3232df25d68d741de Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Tue, 28 Oct 2025 12:57:58 +0800
Subject: [PATCH] [Clang] Fix an iterator invalidation bug in concept
 normalization cache

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.

We convert it std::map where the insert operation doesn't invalidate
iterators.
---
 clang/include/clang/Sema/Sema.h      |  2 +-
 clang/test/SemaTemplate/concepts.cpp | 26 ++++++++++++++++++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 52904c72d1cfc..031d1811c5c27 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -14941,7 +14941,7 @@ class Sema final : public SemaBase {
   /// constrained declarations). If an error occurred while normalizing the
   /// associated constraints of the template or concept, nullptr will be cached
   /// here.
-  llvm::DenseMap<ConstrainedDeclOrNestedRequirement, NormalizedConstraint *>
+  std::map<ConstrainedDeclOrNestedRequirement, NormalizedConstraint *>
       NormalizationCache;
 
   /// Cache whether the associated constraint of a declaration
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index becf5467a1b61..c90af41a09468 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1632,3 +1632,29 @@ void fn3() {
 }
 
 }
+
+namespace GH165238 {
+
+namespace std {
+template <typename, typename _Tp>
+concept output_iterator = requires(_Tp __t) { __t; };
+template <typename _Out> struct basic_format_context {
+  static_assert(output_iterator<_Out, int>);
+  using char_type = _Out;
+};
+template <typename> class basic_format_parse_context;
+template <typename, typename _Context, typename _Formatter,
+          typename = basic_format_parse_context<typename _Context::char_type>>
+concept __parsable_with = requires(_Formatter __f) { __f; };
+template <typename _Tp, typename _CharT,
+          typename _Context = basic_format_context<_CharT>>
+concept __formattable_impl = __parsable_with<_Tp, _Context, _Context>;
+template <typename _Tp, typename _CharT>
+concept formattable = __formattable_impl<_Tp, _CharT>;
+} // namespace std
+struct {
+  void operator()(std::formattable<char> auto);
+} call;
+void foo() { call(""); }
+
+}



More information about the cfe-commits mailing list