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