https://github.com/saschwartz updated 
https://github.com/llvm/llvm-project/pull/230513

>From 96972c2d0985f112a13107575f6f5624f2263da3 Mon Sep 17 00:00:00 2001
From: Sebastian Schwartz <[email protected]>
Date: Wed, 7 Oct 2026 21:29:09 -0500
Subject: [PATCH] [clang][Parse] Delay template-id destruction in NTTP default
 arguments

A non-type template parameter with a constrained placeholder type, as in

  template <typename T, C auto V = [] { return T(); }>

keeps the TemplateIdAnnotation of its type-constraint `C` in the DeclSpec
until ActOnNonTypeTemplateParameter builds the parameter's type. The
default argument is parsed before that. When it contains a lambda, each
statement of the lambda body ends with MaybeDestroyTemplateIds, which frees
all pending template-ids, including the one for `C`. GetTypeForDeclarator
then reads the freed annotation. Usually the freed memory still holds the
old values; when it was reused, clang builds the constraint from garbage
or corrupts the heap.

ParseTypeParameter already guards its default argument with
DelayTemplateIdDestructionRAII (#89494, for #67235). Do the same in
ParseNonTypeTemplateParameter.

Fixes #230539.

Co-authored-by: Emery Conrad <[email protected]>
Assisted-by: Claude Code (claude-opus-5-5)
---
 clang/docs/ReleaseNotes.md                    |  4 +++
 clang/lib/Parse/ParseTemplate.cpp             |  5 ++++
 .../cxx2a-constrained-template-param.cpp      | 26 +++++++++++++++++++
 3 files changed, 35 insertions(+)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index b5a6679e443d08..01f0b5ea2642ae 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -918,6 +918,10 @@ features cannot lower the translation-unit ABI level;
   parameters use pack-indexed template template parameters (`TT...[N]<int>`)
   with different template parameter lists. (#GH228870)
 
+- Fixed a use-after-free when parsing a non-type template parameter with a
+  constrained placeholder type (such as `C auto`) whose default argument
+  contains a lambda. (#GH230539)
+
 #### Bug Fixes to AST Handling
 
 - Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Parse/ParseTemplate.cpp 
b/clang/lib/Parse/ParseTemplate.cpp
index 1e5aa55338309e..ef6920fdc485c1 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -841,7 +841,12 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, 
unsigned Position) {
   // we introduce the template parameter into the local scope.
   SourceLocation EqualLoc;
   ExprResult DefaultArg;
+  std::optional<DelayTemplateIdDestructionRAII> DontDestructTemplateIds;
   if (TryConsumeToken(tok::equal, EqualLoc)) {
+    // The default argument might contain a lambda declaration; avoid 
destroying
+    // parsed template ids at the end of that declaration because they can be
+    // used in the type constraint of the parameter's placeholder type later.
+    DontDestructTemplateIds.emplace(*this, 
/*DelayTemplateIdDestruction=*/true);
     if (Tok.is(tok::l_paren) && NextToken().is(tok::l_brace)) {
       Diag(Tok.getLocation(), diag::err_stmt_expr_in_default_arg) << 1;
       SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch);
diff --git a/clang/test/Parser/cxx2a-constrained-template-param.cpp 
b/clang/test/Parser/cxx2a-constrained-template-param.cpp
index d27f0f8db9b885..dd15370df27de1 100644
--- a/clang/test/Parser/cxx2a-constrained-template-param.cpp
+++ b/clang/test/Parser/cxx2a-constrained-template-param.cpp
@@ -68,3 +68,29 @@ template <typename Ret, C Default = S<[] { return Ret(); }>>
 void func2() {}
 
 }
+
+namespace NTTPLambdaDefaultArg {
+
+template <class T>
+concept C = true;
+
+template <class T, class U>
+concept C2 = true;
+
+// Same as PR67235, for a non-type template parameter: don't destroy the
+// annotation 'C' at the end of the lambda body in the default argument; else
+// we'd read freed memory while building the placeholder type 'C auto'.
+template <typename T, C auto Default = [](int) { return T{}; }>
+constexpr auto V = Default;
+
+template <typename T, C2<int> auto Default = [] { return T(); }>
+void func() {}
+
+// The source locations of these diagnostics come from the annotation 'C'.
+template <typename T, const C auto &Default = [] { return T(); }> // 
expected-error{{constrained placeholder types other than simple 'auto' on 
non-type template parameters not supported yet}}
+void func2() {}
+
+template <typename T, C decltype(auto) Default = [] { return T(); }> // 
expected-error{{constrained placeholder types other than simple 'auto' on 
non-type template parameters not supported yet}}
+void func3() {}
+
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to