When a local class has an NSDMI that references a static local variable
from the enclosing template function, we ICE during synthesized method
walking.

The issue is that r14-8981 added maybe_push_to_top_level in
synthesized_method_walk, which calls push_function_context for
function-local classes (non-lambdas). This clears current_function_decl.
When processing an NSDMI that references a static local variable from
the enclosing function, tsubst_decl calls enclosing_instantiation_of to
find the function instantiation.
That function walks up current_function_decl looking for a function with
matching source location, but since current_function_decl is NULL, the
loop exits immediately and hits gcc_unreachable().

This patch makes enclosing_instantiation_of return NULL_TREE when it
cannot find the enclosing instantiation, and have the caller fall back
to using tsubst_decl on DECL_CONTEXT to obtain the instantiated function.

gcc/cp/ChangeLog:

        PR c++/123354
        * pt.cc (enclosing_instantiation_of): Return NULL_TREE instead
        of crashing when current_function_decl is NULL.
        (tsubst_decl): Handle NULL return from enclosing_instantiation_of
        by using tsubst to find the enclosing function instantiation.

gcc/testsuite/ChangeLog:

        PR c++/123354
        * g++.dg/template/pr123354.C: New test.
---
 gcc/cp/pt.cc                             | 10 +++++++++-
 gcc/testsuite/g++.dg/template/pr123354.C | 18 ++++++++++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/pr123354.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 759418c344e..4ec9cd71b20 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -15520,7 +15520,9 @@ enclosing_instantiation_of (tree tctx)
   for (; fn; fn = decl_function_context (fn))
     if (DECL_SOURCE_LOCATION (fn) == DECL_SOURCE_LOCATION (tctx))
       return fn;
-  gcc_unreachable ();
+
+  /* If we can't find the enclosing instantiation, return NULL.  */
+  return NULL_TREE;
 }
 
 /* Substitute the ARGS into the T, which is a _DECL.  Return the
@@ -15938,6 +15940,12 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain,
            if (TREE_STATIC (t))
              {
                tree fn = enclosing_instantiation_of (DECL_CONTEXT (t));
+               if (fn == NULL_TREE)
+                 /* We're in a context where current_function_decl is cleared
+                    (e.g., synthesized_method_walk); use tsubst_decl to find
+                    the enclosing function instantiation.  */
+                 fn = tsubst_decl (DECL_CONTEXT (t), args, complain,
+                                   use_spec_table);
                if (fn != current_function_decl)
                  ctx = fn;
              }
diff --git a/gcc/testsuite/g++.dg/template/pr123354.C 
b/gcc/testsuite/g++.dg/template/pr123354.C
new file mode 100644
index 00000000000..f87956a4c39
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/pr123354.C
@@ -0,0 +1,18 @@
+// PR c++/123354
+// { dg-do compile { target c++11 } }
+// ICE with static local var referenced in NSDMI of local class
+
+template<typename T>
+void foo() {
+    static constexpr int value = 42;
+    struct s1_t {
+        struct s2_t {
+            int dummy { 0 };
+            char* ptr { static_cast<char*>(::operator new(sizeof(value)))};
+        } s2;
+    } object;
+}
+
+int main() {
+    foo<void>();
+}
-- 
2.52.0

Reply via email to