{"id":808274,"url":"http://patchwork.ozlabs.org/api/patches/808274/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/patch/CADzB+2n+cETRk6CPdNF95bNZrT_3vJVdggDPwAyyiH1fsucu-A@mail.gmail.com/","project":{"id":17,"url":"http://patchwork.ozlabs.org/api/projects/17/?format=json","name":"GNU Compiler Collection","link_name":"gcc","list_id":"gcc-patches.gcc.gnu.org","list_email":"gcc-patches@gcc.gnu.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<CADzB+2n+cETRk6CPdNF95bNZrT_3vJVdggDPwAyyiH1fsucu-A@mail.gmail.com>","list_archive_url":null,"date":"2017-08-31T15:18:07","name":"C++ PATCH for c++/82029, ICE with __func__ in lambda in template","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"7bce6c81af79cd031db020eaaeb71621a5dab8f2","submitter":{"id":4337,"url":"http://patchwork.ozlabs.org/api/people/4337/?format=json","name":"Jason Merrill","email":"jason@redhat.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/gcc/patch/CADzB+2n+cETRk6CPdNF95bNZrT_3vJVdggDPwAyyiH1fsucu-A@mail.gmail.com/mbox/","series":[{"id":847,"url":"http://patchwork.ozlabs.org/api/series/847/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/list/?series=847","date":"2017-08-31T15:18:07","name":"C++ PATCH for c++/82029, ICE with __func__ in lambda in template","version":1,"mbox":"http://patchwork.ozlabs.org/series/847/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/808274/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/808274/checks/","tags":{},"related":[],"headers":{"Return-Path":"<gcc-patches-return-461213-incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","mailing list gcc-patches@gcc.gnu.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org\n\t(client-ip=209.132.180.131; helo=sourceware.org;\n\tenvelope-from=gcc-patches-return-461213-incoming=patchwork.ozlabs.org@gcc.gnu.org;\n\treceiver=<UNKNOWN>)","ozlabs.org; dkim=pass (1024-bit key;\n\tunprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org\n\theader.b=\"cryFzkwX\"; dkim-atps=neutral","sourceware.org; auth=none"],"Received":["from sourceware.org (server1.sourceware.org [209.132.180.131])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xjmHF6V5sz9s7c\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri,  1 Sep 2017 01:18:48 +1000 (AEST)","(qmail 30838 invoked by alias); 31 Aug 2017 15:18:40 -0000","(qmail 30829 invoked by uid 89); 31 Aug 2017 15:18:40 -0000","from mail-io0-f172.google.com (HELO mail-io0-f172.google.com)\n\t(209.85.223.172) by sourceware.org\n\t(qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP;\n\tThu, 31 Aug 2017 15:18:30 +0000","by mail-io0-f172.google.com with SMTP id k22so332260iod.2 for\n\t<gcc-patches@gcc.gnu.org>; Thu, 31 Aug 2017 08:18:30 -0700 (PDT)","by 10.107.181.23 with HTTP; Thu, 31 Aug 2017 08:18:07 -0700 (PDT)"],"DomainKey-Signature":"a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id\n\t:list-unsubscribe:list-archive:list-post:list-help:sender\n\t:mime-version:from:date:message-id:subject:to:content-type; q=\n\tdns; s=default; b=dz3+AGN4Ppz+A+IM7DjPBGeom1zXn4M9DkWwKeh8o6I56E\n\tkXjEMq1vWyQE5zZfsBk4voEdH32NWIFMjtFeVB8Zc37WfZOub1STS5xN0lQMtlLO\n\t5+6tbNdJEqcpfDv6vlv2+GXK32yejrCqRgNZqAP1+gBSeqG3d+0l/Q8n4LfX0=","DKIM-Signature":"v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id\n\t:list-unsubscribe:list-archive:list-post:list-help:sender\n\t:mime-version:from:date:message-id:subject:to:content-type; s=\n\tdefault; bh=d4WKAnOzHPTTKI3YPA+o4SDePOc=; b=cryFzkwXSmMMsBF9cwEL\n\t0PaxTpOLxtadI9ImniKpyqx5ZvTGfNCZfuti9PXzvTMr0iMD+gmqsE00usLRd+P9\n\ty3L8+yRmuMUabdyQKFKU/XuX2XtAGYaRYamTika8xyLECVIDk8T4LyJEriyLoAF9\n\t3Kkdw03hwUxqedxDGxi0pkA=","Mailing-List":"contact gcc-patches-help@gcc.gnu.org; run by ezmlm","Precedence":"bulk","List-Id":"<gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<mailto:gcc-patches-unsubscribe-incoming=patchwork.ozlabs.org@gcc.gnu.org>","List-Archive":"<http://gcc.gnu.org/ml/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-help@gcc.gnu.org>","Sender":"gcc-patches-owner@gcc.gnu.org","X-Virus-Found":"No","X-Spam-SWARE-Status":"No, score=-25.0 required=5.0 tests=AWL, BAYES_00,\n\tGIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3,\n\tRCVD_IN_DNSWL_NONE,\n\tRCVD_IN_SORBS_SPAM autolearn=ham version=3.3.2 spammy=revisit","X-HELO":"mail-io0-f172.google.com","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net;\n\ts=20161025;\n\th=x-gm-message-state:mime-version:from:date:message-id:subject:to;\n\tbh=LO983qWA0tiSOJdiTidL4Y2OUiP/4pRxQUsaj8Te+68=;\n\tb=WBERXUiYhWQ+LvCdZNCrIutjRPCl99pq88hoOczbqsZTrHabai21nQyv6I4M6NGybB\n\tBYuZ7BezSa+opx5j88j8Y7hWIVLDIjPhojRCxUaUQsBqp+MbfmxLbHWwjPp6t2bvt5w7\n\tJdhpiboAmAQEreqhwZ49QgmCibgoMiQtzYmxdKOijZPRxICwZIPAZWW1QqYNeNxoVy4c\n\t7AVnwqzq7jeqrsiVVX1y6+BPAXonFgBBeZCLr3MxmU+twNIxBMKj7febec0vvsy7bPR4\n\thT2+br0ZgnzmSP3rcdn/Gd+a81b4u+6kqQnmbsPEGe8IHH1XKcG7Mpta0PrtSQ1MG3ji\n\tKPZg==","X-Gm-Message-State":"AHYfb5hArRGbsApNuC/L72Svyk8OYRm2ZosP294aHeDMaXLWRuec6G0x\tluJKndLZtMWrGnWSzuikdxqRsKTH4EIis4s=","X-Google-Smtp-Source":"ADKCNb7zsdKMqkEmzYlDMntAYBu6Lpih+hCaltrb1zrlVqIl9QNVxBWqMRggvtbc0D9wdewHdXgrKbjWctRnRxjh/GQ=","X-Received":"by 10.36.216.8 with SMTP id b8mr1244942itg.55.1504192708219;\n\tThu, 31 Aug 2017 08:18:28 -0700 (PDT)","MIME-Version":"1.0","From":"Jason Merrill <jason@redhat.com>","Date":"Thu, 31 Aug 2017 11:18:07 -0400","Message-ID":"<CADzB+2n+cETRk6CPdNF95bNZrT_3vJVdggDPwAyyiH1fsucu-A@mail.gmail.com>","Subject":"C++ PATCH for c++/82029, ICE with __func__ in lambda in template","To":"gcc-patches List <gcc-patches@gcc.gnu.org>","Content-Type":"multipart/mixed; boundary=\"94eb2c05e89e0caafc05580e28cd\"","X-IsSubscribed":"yes"},"content":"When tsubst_decl creates a new local static variable, it checks to see\nif it belongs to current_function_decl.  It has done this by tsubsting\nthe old DECL_CONTEXT, but that doesn't work with the new lambda model,\nwhere we can't get to the new lambda op() by tsubsting the old one.\nSo this patch introduces a new function enclosing_instantiation_of,\nwhich looks out from current_function_decl to find which enclosing\nfunction corresponds to the context of the variable in the template.\n\nI've attached two versions of this patch: one which matches up lambdas\nbased on nesting level within an enclosing function, and one which\nuses a hash table.  I've been ambivalent about which to go with; the\nfirst has more complicated logic, but uses less space, so I think\nthat's the one I'm going to check in now.  I might revisit this choice\nif I find other uses for the hash table.\n\nTested x86_64-pc-linux-gnu, applying to trunk.\ncommit 4c88ba8c2a00d662c33f0e2569526122759dc2cb\nAuthor: Jason Merrill <jason@redhat.com>\nDate:   Wed Aug 30 16:26:24 2017 -0400\n\n            PR c++/82029 - __PRETTY_FUNCTION__ in lambda in template\n    \n            * pt.c (enclosing_instantiation_of, lambda_fn_in_template_p)\n            (regenerated_lambda_fn_p): New.\n            (tsubst_decl) [VAR_DECL]: Use enclosing_instantiation_of.\n            (tsubst_copy) [VAR_DECL]: Likewise.\ncommit 3edefaa7d1dd5d6b947d4311be1e508552b303c9\nAuthor: Jason Merrill <jason@redhat.com>\nDate:   Wed Aug 30 16:26:24 2017 -0400\n\n            PR c++/82029 - __PRETTY_FUNCTION__ in lambda in template\n    \n            * pt.c (enclosing_instantiation_of): New.\n            (tsubst_decl) [VAR_DECL]: Use it.\n            (tsubst_copy) [VAR_DECL]: Likewise.\n            (lambda_fn_origin): New hash table.\n            (tsubst_lambda_expr): Populate it.\n\ndiff --git a/gcc/cp/pt.c b/gcc/cp/pt.c\nindex f4868ab..41fecaf 100644\n--- a/gcc/cp/pt.c\n+++ b/gcc/cp/pt.c\n@@ -12587,6 +12587,37 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,\n   return r;\n }\n \n+/* A hash table from a lambda op() in a template instantiation to the op() of\n+   the corresponding lambda in the uninstantiated template.  */\n+static GTY(()) hash_map<tree, tree> *lambda_fn_origin;\n+\n+/* We're instantiating a variable from template function TCTX.  Return the\n+   corresponding current enclosing scope.  This gets complicated because lambda\n+   functions in templates are regenerated rather than instantiated, but generic\n+   lambda functions are subsequently instantiated.  */\n+\n+static tree\n+enclosing_instantiation_of (tree tctx)\n+{\n+  for (tree fn = current_function_decl; fn; fn = decl_function_context (fn))\n+    {\n+      tree origin;\n+      tree *slot;\n+\n+      if (LAMBDA_FUNCTION_P (fn) && lambda_fn_origin\n+\t  && (slot = lambda_fn_origin->get (fn)))\n+\torigin = *slot;\n+      else if (DECL_TEMPLATE_INFO (fn))\n+\torigin = DECL_TEMPLATE_RESULT (most_general_template (fn));\n+      else\n+\torigin = fn;\n+\n+      if (origin == tctx)\n+\treturn fn;\n+    }\n+  gcc_unreachable ();\n+}\n+\n /* Substitute the ARGS into the T, which is a _DECL.  Return the\n    result of the substitution.  Issue error and warning messages under\n    control of COMPLAIN.  */\n@@ -12955,7 +12986,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)\n \t       enclosing function, in which case we need to fill it in now.  */\n \t    if (TREE_STATIC (t))\n \t      {\n-\t\ttree fn = tsubst (DECL_CONTEXT (t), args, complain, in_decl);\n+\t\ttree fn = enclosing_instantiation_of (DECL_CONTEXT (t));\n \t\tif (fn != current_function_decl)\n \t\t  ctx = fn;\n \t      }\n@@ -14734,9 +14765,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)\n \t      if (r && !is_capture_proxy (r))\n \t\t{\n \t\t  /* Make sure that the one we found is the one we want.  */\n-\t\t  tree ctx = DECL_CONTEXT (t);\n-\t\t  if (DECL_LANG_SPECIFIC (ctx) && DECL_TEMPLATE_INFO (ctx))\n-\t\t    ctx = tsubst (ctx, args, complain, in_decl);\n+\t\t  tree ctx = enclosing_instantiation_of (DECL_CONTEXT (t));\n \t\t  if (ctx != DECL_CONTEXT (r))\n \t\t    r = NULL_TREE;\n \t\t}\n@@ -16855,6 +16884,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)\n \t  finish_member_declaration (fn);\n \t}\n \n+      if (!lambda_fn_origin)\n+\tlambda_fn_origin = hash_map<tree,tree>::create_ggc (37);\n+      lambda_fn_origin->put (fn, oldfn);\n+\n       /* Let finish_function set this.  */\n       DECL_DECLARED_CONSTEXPR_P (fn) = false;\n \ndiff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C\nnew file mode 100644\nindex 0000000..bc0e3b2\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C\n@@ -0,0 +1,13 @@\n+// PR c++/82029\n+// { dg-do compile { target c++11 } }\n+\n+template <typename> struct A {\n+  void m_fn1() {\n+    [] { return __func__; }();\n+  }\n+};\n+struct B {\n+  A<int> a;\n+  void m_fn2();\n+};\n+void B::m_fn2() { a.m_fn1(); }","diff":"diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c\nindex f4868ab..d5ab939 100644\n--- a/gcc/cp/pt.c\n+++ b/gcc/cp/pt.c\n@@ -12587,6 +12587,63 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,\n   return r;\n }\n \n+/* True if FN is the op() for a lambda in an uninstantiated template.  */\n+\n+bool\n+lambda_fn_in_template_p (tree fn)\n+{\n+  if (!LAMBDA_FUNCTION_P (fn))\n+    return false;\n+  tree closure = DECL_CONTEXT (fn);\n+  return CLASSTYPE_TEMPLATE_INFO (closure) != NULL_TREE;\n+}\n+\n+/* True if FN is the op() for a lambda regenerated from a lambda in an\n+   uninstantiated template.  */\n+\n+bool\n+regenerated_lambda_fn_p (tree fn)\n+{\n+  return (LAMBDA_FUNCTION_P (fn)\n+\t  && !DECL_TEMPLATE_INSTANTIATION (fn));\n+}\n+\n+/* We're instantiating a variable from template function TCTX.  Return the\n+   corresponding current enclosing scope.  This gets complicated because lambda\n+   functions in templates are regenerated rather than instantiated, but generic\n+   lambda functions are subsequently instantiated.  */\n+\n+static tree\n+enclosing_instantiation_of (tree tctx)\n+{\n+  tree fn = current_function_decl;\n+  int lambda_count = 0;\n+\n+  for (; tctx && lambda_fn_in_template_p (tctx);\n+       tctx = decl_function_context (tctx))\n+    ++lambda_count;\n+  for (; fn; fn = decl_function_context (fn))\n+    {\n+      tree lambda = fn;\n+      int flambda_count = 0;\n+      for (; fn && regenerated_lambda_fn_p (fn);\n+\t   fn = decl_function_context (fn))\n+\t++flambda_count;\n+      if (DECL_TEMPLATE_INFO (fn)\n+\t  ? most_general_template (fn) != most_general_template (tctx)\n+\t  : fn != tctx)\n+\tcontinue;\n+      if (lambda_count)\n+\t{\n+\t  fn = lambda;\n+\t  while (flambda_count-- > lambda_count)\n+\t    fn = decl_function_context (fn);\n+\t}\n+      return fn;\n+    }\n+  gcc_unreachable ();\n+}\n+\n /* Substitute the ARGS into the T, which is a _DECL.  Return the\n    result of the substitution.  Issue error and warning messages under\n    control of COMPLAIN.  */\n@@ -12955,7 +13012,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)\n \t       enclosing function, in which case we need to fill it in now.  */\n \t    if (TREE_STATIC (t))\n \t      {\n-\t\ttree fn = tsubst (DECL_CONTEXT (t), args, complain, in_decl);\n+\t\ttree fn = enclosing_instantiation_of (DECL_CONTEXT (t));\n \t\tif (fn != current_function_decl)\n \t\t  ctx = fn;\n \t      }\n@@ -14734,9 +14791,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)\n \t      if (r && !is_capture_proxy (r))\n \t\t{\n \t\t  /* Make sure that the one we found is the one we want.  */\n-\t\t  tree ctx = DECL_CONTEXT (t);\n-\t\t  if (DECL_LANG_SPECIFIC (ctx) && DECL_TEMPLATE_INFO (ctx))\n-\t\t    ctx = tsubst (ctx, args, complain, in_decl);\n+\t\t  tree ctx = enclosing_instantiation_of (DECL_CONTEXT (t));\n \t\t  if (ctx != DECL_CONTEXT (r))\n \t\t    r = NULL_TREE;\n \t\t}\ndiff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C\nnew file mode 100644\nindex 0000000..bc0e3b2\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C\n@@ -0,0 +1,13 @@\n+// PR c++/82029\n+// { dg-do compile { target c++11 } }\n+\n+template <typename> struct A {\n+  void m_fn1() {\n+    [] { return __func__; }();\n+  }\n+};\n+struct B {\n+  A<int> a;\n+  void m_fn2();\n+};\n+void B::m_fn2() { a.m_fn1(); }\n","prefixes":[]}