yaxunl created this revision.
yaxunl added reviewers: rsmith, rjmccall, tra.
yaxunl requested review of this revision.

A lambda in a function template may be recursively instantiated as the 
following example:

  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>{})
  {
    auto f = [&](auto fs, auto i) {
      if constexpr(i.value > 0)
      {
        return fs(fs, Number<IBegin>{});
      }
    };
  
    return f(f, Number<IEnd>{});
  }
  
  
  void fun2() {
    fun1();
  }

The recursive lambda will cause a bunch of lambda's instantiated, one inside 
another.
For each instantiation, clang asserts any formal arguments do not show up as 
formal
arguments of its outer instantiation. If these instantiations are not 
originated from the
same lambda, this is true. Unfortunately this is not true for recursive 
lambda's.


https://reviews.llvm.org/D98068

Files:
  clang/lib/Sema/SemaTemplateInstantiate.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,30 @@
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
+
+// expected-no-diagnostics
+
+// Check recursive instantiation of lambda does not cause assertion.
+
+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>{})
+{
+  auto f = [&](auto fs, auto i) {
+    if constexpr(i.value > 0)
+    {
+      return fs(fs, Number<IBegin>{});
+    }
+  };
+
+  return f(f, Number<IEnd>{});
+}
+
+
+void fun2() {
+  fun1();
+}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -3621,15 +3621,6 @@
   D = getCanonicalParmVarDecl(D);
   llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
   if (Stored.isNull()) {
-#ifndef NDEBUG
-    // It should not be present in any surrounding scope either.
-    LocalInstantiationScope *Current = this;
-    while (Current->CombineWithOuterScope && Current->Outer) {
-      Current = Current->Outer;
-      assert(Current->LocalDecls.find(D) == Current->LocalDecls.end() &&
-             "Instantiated local in inner and outer scopes");
-    }
-#endif
     Stored = Inst;
   } else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) {
     Pack->push_back(cast<VarDecl>(Inst));
@@ -3646,14 +3637,6 @@
 }
 
 void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) {
-#ifndef NDEBUG
-  // This should be the first time we've been told about this decl.
-  for (LocalInstantiationScope *Current = this;
-       Current && Current->CombineWithOuterScope; Current = Current->Outer)
-    assert(Current->LocalDecls.find(D) == Current->LocalDecls.end() &&
-           "Creating local pack after instantiation of local");
-#endif
-
   D = getCanonicalParmVarDecl(D);
   llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
   DeclArgumentPack *Pack = new DeclArgumentPack;


Index: clang/test/SemaCXX/recursive-lambda.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/recursive-lambda.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
+
+// expected-no-diagnostics
+
+// Check recursive instantiation of lambda does not cause assertion.
+
+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>{})
+{
+  auto f = [&](auto fs, auto i) {
+    if constexpr(i.value > 0)
+    {
+      return fs(fs, Number<IBegin>{});
+    }
+  };
+
+  return f(f, Number<IEnd>{});
+}
+
+
+void fun2() {
+  fun1();
+}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -3621,15 +3621,6 @@
   D = getCanonicalParmVarDecl(D);
   llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
   if (Stored.isNull()) {
-#ifndef NDEBUG
-    // It should not be present in any surrounding scope either.
-    LocalInstantiationScope *Current = this;
-    while (Current->CombineWithOuterScope && Current->Outer) {
-      Current = Current->Outer;
-      assert(Current->LocalDecls.find(D) == Current->LocalDecls.end() &&
-             "Instantiated local in inner and outer scopes");
-    }
-#endif
     Stored = Inst;
   } else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) {
     Pack->push_back(cast<VarDecl>(Inst));
@@ -3646,14 +3637,6 @@
 }
 
 void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) {
-#ifndef NDEBUG
-  // This should be the first time we've been told about this decl.
-  for (LocalInstantiationScope *Current = this;
-       Current && Current->CombineWithOuterScope; Current = Current->Outer)
-    assert(Current->LocalDecls.find(D) == Current->LocalDecls.end() &&
-           "Creating local pack after instantiation of local");
-#endif
-
   D = getCanonicalParmVarDecl(D);
   llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
   DeclArgumentPack *Pack = new DeclArgumentPack;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D98068: Remove asse... Yaxun Liu via Phabricator via cfe-commits

Reply via email to