diff mbox series

c++: NSDMI instantiation from template context [PR109506]

Message ID 20230427163956.3051552-1-ppalka@redhat.com
State New
Headers show
Series c++: NSDMI instantiation from template context [PR109506] | expand

Commit Message

Patrick Palka April 27, 2023, 4:39 p.m. UTC
The testcase from this PR fails to link when -fchecking=2 with the error:

  /usr/bin/ld: /tmp/ccpHiXEY.o: in function `bar<int>::bar()':
  ...: undefined reference to `foo<int>::foo()'

ultimately because we end up instantiating the NSDMI for bar<int>::alloc_
from the template context func1<T> for which in_template_function is
true and thus mark_used is inhibited from scheduling other templates for
instantiation.  So we end up never instantiating foo<int>'s ctor.

Although maybe_instantiate_nsdmi_init does call push_to_top_level, which
would have gotten us out of the template context, it doesn't happen in
this case because currently_open_class (ctx) is true, thanks to an
earlier call to push_scope from synthesized_method_walk.

We could perhaps arrange to call push_to_top_level unconditionally in
maybe_instantiate_nsdmi_init or even from from synthesized_method_walk,
but that seems rather heavyweight for this situation.  Ideally we just
want a way to allow mark_used to work here despite being in a template
context.

To that end, this patch first generalizes the in_template_function test
in mark_used to instead test current_template_parms, which has two
benefits: it works for all template contexts, not just function template
contexts, and it can be cheaply disabled by simply clearing
current_template_parms.  This patch then makes us disable this test from
maybe_instantiate_nsdmi_init.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  This doesn't seem worth backporting since the bug seems to
manifest only with -fchecking=2.

	PR c++/109506

gcc/cp/ChangeLog:

	* decl2.cc (mark_used): Check current_template_parms instead
	of in_template_function.
	* init.cc (maybe_instantiate_nsdmi_init): Clear
	current_template_parms before instantiating.

gcc/testsuite/ChangeLog:

	* g++.dg/warn/Waddress-of-packed-member2.C: No longer expect
	a "used but never defined" warning due to the use from an
	uninstantiated template.
	* g++.dg/template/non-dependent25.C: New test.
---
 gcc/cp/decl2.cc                               |  6 ++++-
 gcc/cp/init.cc                                |  3 +++
 gcc/testsuite/g++.dg/cpp0x/nsdmi-template26.C | 23 +++++++++++++++++++
 .../g++.dg/warn/Waddress-of-packed-member2.C  |  2 +-
 4 files changed, 32 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-template26.C

Comments

Sam James April 27, 2023, 10:35 p.m. UTC | #1
FWIW, we'd love to be able to backport this to GCC 13 (maybe 12, but no
big deal there) in Gentoo so we can continue doing large testing builds with
a lot of checking enabled, given this affects Chromium.

But it's no big deal if it's too invasive.
diff mbox series

Patch

diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 9594be4092c..b9d37d76bf6 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -5781,7 +5781,11 @@  mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */)
 	  && DECL_OMP_DECLARE_REDUCTION_P (decl)))
     maybe_instantiate_decl (decl);
 
-  if (processing_template_decl || in_template_function ())
+  /* We don't want to instantiate templates based on uses from other
+     uninstantiated templates.  Since processing_template_decl is cleared
+     during instantiate_non_dependent_expr, we check current_template_parms
+     as well.  */
+  if (processing_template_decl || current_template_parms)
     return true;
 
   /* Check this too in case we're within instantiate_non_dependent_expr.  */
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 1dd24e30d7c..ef32ef2a8c2 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -610,6 +610,9 @@  maybe_instantiate_nsdmi_init (tree member, tsubst_flags_t complain)
 	      push_deferring_access_checks (dk_no_deferred);
 	      pushed = true;
 	    }
+	  /* Make sure current_template_parms is cleared so that mark_used
+	     is uninhibited.  */
+	  auto ctpo = make_temp_override (current_template_parms, NULL_TREE);
 
 	  /* If we didn't push_to_top_level, still step out of constructor
 	     scope so build_base_path doesn't try to use its __in_chrg.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-template26.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-template26.C
new file mode 100644
index 00000000000..d9e17ea6724
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-template26.C
@@ -0,0 +1,23 @@ 
+// PR c++/109506
+// { dg-do link { target c++11 } }
+// { dg-additional-options "-fchecking=2" }
+
+template<class T>
+struct foo {
+  foo() { };
+};
+
+template<class T>
+class bar {
+  foo<int> alloc_{};
+};
+
+template<class T>
+bar<int> func1() {
+  return bar<int>{};
+}
+
+int main() {
+  func1<int>();
+}
+
diff --git a/gcc/testsuite/g++.dg/warn/Waddress-of-packed-member2.C b/gcc/testsuite/g++.dg/warn/Waddress-of-packed-member2.C
index e9bf7cac04c..d619b28cfe1 100644
--- a/gcc/testsuite/g++.dg/warn/Waddress-of-packed-member2.C
+++ b/gcc/testsuite/g++.dg/warn/Waddress-of-packed-member2.C
@@ -1,7 +1,7 @@ 
 // PR c++/89973
 // { dg-do compile { target c++14 } }
 
-constexpr int a(); // { dg-warning "used but never defined" }
+constexpr int a();
 
 template <typename>
 constexpr void *b = a(); // { dg-error "invalid conversion" }