This revision was automatically updated to reflect the committed changes. Closed by commit rG79f9cfbc21e0: Do not merge LocalInstantiationScope for template specialization (authored by yaxunl). Herald added a project: clang.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D98068/new/ https://reviews.llvm.org/D98068 Files: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/test/SemaCXX/recursive-lambda.cpp Index: clang/test/SemaCXX/recursive-lambda.cpp =================================================================== --- /dev/null +++ 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 <unsigned v> +struct Number +{ + static constexpr unsigned value = v; +}; + +template <unsigned IBegin = 0, + unsigned IEnd = 1> +constexpr auto fun1(Number<IBegin> = Number<0>{}, Number<IEnd> = Number<1>{}) +{ + constexpr unsigned a = 0; + auto f = [&](auto fs, auto i) { + if constexpr(i.value > 0) + { + (void)a; + return fs(fs, Number<IBegin>{}); + } + (void)a; + }; + + return f(f, Number<IEnd>{}); +} + + +void fun2() { + fun1(); +} Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4890,10 +4890,13 @@ // 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<CXXRecordDecl>(Function->getDeclContext())) - MergeWithParentScope = Rec->isLocalClass(); + MergeWithParentScope = + Rec->isLocalClass() && !Function->isFunctionTemplateSpecialization(); LocalInstantiationScope Scope(*this, MergeWithParentScope);
Index: clang/test/SemaCXX/recursive-lambda.cpp =================================================================== --- /dev/null +++ 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 <unsigned v> +struct Number +{ + static constexpr unsigned value = v; +}; + +template <unsigned IBegin = 0, + unsigned IEnd = 1> +constexpr auto fun1(Number<IBegin> = Number<0>{}, Number<IEnd> = Number<1>{}) +{ + constexpr unsigned a = 0; + auto f = [&](auto fs, auto i) { + if constexpr(i.value > 0) + { + (void)a; + return fs(fs, Number<IBegin>{}); + } + (void)a; + }; + + return f(f, Number<IEnd>{}); +} + + +void fun2() { + fun1(); +} Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4890,10 +4890,13 @@ // 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<CXXRecordDecl>(Function->getDeclContext())) - MergeWithParentScope = Rec->isLocalClass(); + MergeWithParentScope = + Rec->isLocalClass() && !Function->isFunctionTemplateSpecialization(); LocalInstantiationScope Scope(*this, MergeWithParentScope);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits