diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 039c70710a28a82cadaadf6b1482247b948b335f..a9ce44bb21478fefab0b4d7a5f23deabe35c6858 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7626,7 +7626,8 @@ enum { nt_opaque = false, nt_transparent = true }; extern tree alias_template_specialization_p (const_tree, bool); extern tree dependent_alias_template_spec_p (const_tree, bool); extern bool dependent_opaque_alias_p (const_tree); -extern tree get_template_parm_object (tree expr, tree mangle); +extern tree get_template_parm_object (tree expr, tree mangle, + bool check_init = true); extern tree tparm_object_argument (tree); extern bool explicit_class_specialization_p (tree); extern bool push_tinst_level (tree); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index c3218bd5caf3a53785e2bd4ceb02f80ac6ad9fb8..0a4ceffa3d63377555dfd535a9d8a5b566745a03 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -9938,7 +9938,11 @@ trees_in::tree_node (bool is_use) tree name = tree_node (); if (!get_overrun ()) { - res = get_template_parm_object (init, name); + /* We don't want to check the initializer as that may require + name lookup, which could recursively start lazy loading. + Instead we know that INIT is already valid so we can just + apply that directly. */ + res = get_template_parm_object (init, name, /*check_init=*/false); int tag = insert (res); dump (dumper::TREE) && dump ("Created nttp object:%d %N", tag, name); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 32d164f0fd5b75bfcad2007fd3252ed090e95344..76edc7aad50c8dd6a708f27d0771fd476e3d15e2 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -7361,10 +7361,11 @@ create_template_parm_object (tree expr, tsubst_flags_t complain) static GTY(()) hash_map<tree, tree> *tparm_obj_values; /* Find or build an nttp object for (already-validated) EXPR with name - NAME. */ + NAME. When CHECK_INIT is false we don't need to process the initialiser, + it's already been done. */ tree -get_template_parm_object (tree expr, tree name) +get_template_parm_object (tree expr, tree name, bool check_init/*=true*/) { tree decl = get_global_binding (name); if (decl) @@ -7385,11 +7386,20 @@ get_template_parm_object (tree expr, tree name) { /* If EXPR contains any PTRMEM_CST, they will get clobbered by lower_var_init before we're done mangling. So store the original - value elsewhere. */ - tree copy = unshare_constructor (expr); + value elsewhere. We only need to unshare EXPR if it's not yet + been processed. */ + tree copy = check_init ? unshare_constructor (expr) : expr; hash_map_safe_put<hm_ggc> (tparm_obj_values, decl, copy); } + if (!check_init) + { + /* The EXPR is the already processed initializer, set it on the NTTP + object now so that cp_finish_decl doesn't do it again later. */ + DECL_INITIAL (decl) = expr; + DECL_INITIALIZED_P (decl) = 1; + } + pushdecl_top_level_and_finish (decl, expr); return decl; diff --git a/gcc/testsuite/g++.dg/modules/tpl-nttp-1_a.C b/gcc/testsuite/g++.dg/modules/tpl-nttp-1_a.C new file mode 100644 index 0000000000000000000000000000000000000000..46f6ecd0c1db8c1000da187487edc590c2f7eb13 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-nttp-1_a.C @@ -0,0 +1,8 @@ +// PR c++/116382 +// { dg-additional-options "-fmodules-ts -std=c++20" } +// { dg-module-cmi m:a } + +module m:a; +template <typename> struct X {}; +template <X<int> nttp> struct index {}; +template struct index<{}>; diff --git a/gcc/testsuite/g++.dg/modules/tpl-nttp-1_b.C b/gcc/testsuite/g++.dg/modules/tpl-nttp-1_b.C new file mode 100644 index 0000000000000000000000000000000000000000..a3241e7bc25cadc2a982dae32ea743f9d74412e7 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-nttp-1_b.C @@ -0,0 +1,6 @@ +// PR c++/116382 +// { dg-additional-options "-fmodules-ts -std=c++20" } +// { dg-module-cmi m } + +export module m; +import :a;