c++: generic lambdas and local-externs from outer scopes [PR 99030]
authorNathan Sidwell <nathan@acm.org>
Wed, 10 Feb 2021 13:29:39 +0000 (05:29 -0800)
committerNathan Sidwell <nathan@acm.org>
Wed, 10 Feb 2021 13:34:42 +0000 (05:34 -0800)
Lambdas can refer to local externs from their enclosing scope.  When
the lambda's generic but the containing function is not a temploid,
we'll never have tsubsted the declaring decl so won't have a local
specialization.  But in that case we can just use the decl we
tsubsting directly -- it's not dependent.

PR c++/99030
gcc/cp
* pt.c (tsubst_copy) [VAR_DECL]: For a DECL_LOCAL_DECL_P T is the
answer if there's no local specialization.
gcc/testsuite/
* g++.dg/lookup/pr99030.C: New.

gcc/cp/pt.c
gcc/testsuite/g++.dg/lookup/pr99030.C [new file with mode: 0644]

index f73deb3aee3d58c1c8376dd23205d919ed931290..d8574f649b28f83bb9c5a7740dcc24199a3f6c15 100644 (file)
@@ -16650,11 +16650,16 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
        r = tsubst (t, args, complain, in_decl);
       else if (DECL_LOCAL_DECL_P (t))
        {
-         /* Local specialization will have been created when we
-            instantiated the DECL_EXPR_DECL. */
+         /* Local specialization will usually have been created when
+            we instantiated the DECL_EXPR_DECL. */
          r = retrieve_local_specialization (t);
          if (!r)
-           r = error_mark_node;
+           {
+             /* We're in a generic lambda referencing a local extern
+                from an outer block-scope of a non-template.  */
+             gcc_checking_assert (LAMBDA_FUNCTION_P (current_function_decl));
+             r = t;
+           }
        }
       else if (local_variable_p (t)
               && uses_template_parms (DECL_CONTEXT (t)))
diff --git a/gcc/testsuite/g++.dg/lookup/pr99030.C b/gcc/testsuite/g++.dg/lookup/pr99030.C
new file mode 100644 (file)
index 0000000..080847c
--- /dev/null
@@ -0,0 +1,16 @@
+// PR 99030 ICE with generic lambda accessing local extern
+// { dg-do compile { target c++14 } }
+
+void foo ()
+{
+  extern int a;
+  [] (auto b) { a; } (1);
+}
+
+template<typename T> void bar ()
+{
+  extern T a;
+  [] (auto b) { a; } (1);
+}
+
+template void bar<int> ();