diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 8de09def4d52a..b2590d3deaad7 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4890,10 +4890,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Introduce a new scope where local variable instantiations will be // recorded, unless we're actually a member function within a local // class, in which case we need to merge our results with the parent - // scope (of the enclosing function). + // scope (of the enclosing function). The exception is instantiating + // a function template specialization, since the template to be + // instantiated already has references to locals properly substituted. bool MergeWithParentScope = false; if (CXXRecordDecl *Rec = dyn_cast(Function->getDeclContext())) - MergeWithParentScope = Rec->isLocalClass(); + MergeWithParentScope = + Rec->isLocalClass() && !Function->isFunctionTemplateSpecialization(); LocalInstantiationScope Scope(*this, MergeWithParentScope); diff --git a/clang/test/SemaCXX/recursive-lambda.cpp b/clang/test/SemaCXX/recursive-lambda.cpp new file mode 100644 index 0000000000000..58087628db988 --- /dev/null +++ b/clang/test/SemaCXX/recursive-lambda.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s + +// expected-no-diagnostics + +// Check recursive instantiation of lambda does not cause assertion. +// lambda function `f` in `fun1` is instantiated twice: first +// as f(f, Number<1>), then as f(f, Number<0>). The +// LocalInstantiationScopes of these two instantiations both contain +// `f` and `i`. However, since they are not merged, clang should not +// assert for that. + +template +struct Number +{ + static constexpr unsigned value = v; +}; + +template +constexpr auto fun1(Number = Number<0>{}, Number = Number<1>{}) +{ + constexpr unsigned a = 0; + auto f = [&](auto fs, auto i) { + if constexpr(i.value > 0) + { + (void)a; + return fs(fs, Number{}); + } + (void)a; + }; + + return f(f, Number{}); +} + + +void fun2() { + fun1(); +}