We had encountered a bogus warning about class visibility. Namely a lambda had captured a variable whose type was in the anonymous namespace. The problem was that in_main_input_context was returning false (i.e. we're in a header file), as that was the location of the outermost template instantiation (yup, the lambda came out of a template instantiation).

The problem was the location was wrong -- it was pointing to some much earlier non-template class definition. (funnily enough, the class was to do with Futures, messing with my head about reaching into the future of the compilation).

The problem stemmed from the c_parse_final_cleanups. That consists of a do-until-no-more loop that does a bunch of things. Early in the loop it maybe_emits_vtables and later in the loop it emits inline function that need a body. In this case, an earlier non-template class needed its virtual deleting dtor synthesized and emitted. That sets the input_location to that of the class. But doesn't immediately restore it.

Then the next iteration of the main loop in c_parse_final_cleanups discovered a new vtable needed emitting and calls mark_used on the vfuncs it points at. That caused instantiation of the body of a vfunc within the template class whose vtable we were emitting. We still had the stale input_location from the above synthesis.

The upshot of which is we think the cause of the template instantiation of the vfunc was at the other class definition, and as that was from a header file, don't think we're in the main input file.

I failed at reducing the testcase.

Anyway, the fix is to set input_location to something definite before calling mark_used in maybe_emit_vtables. Candidates are:
1) locus_at_end_of_compilation
2) locus of the class owning the vtable
3) locus of the vfunc being marked.

I went with #3 in this patch. Although #2 is attractive, the class definition could easily be in a header file, which would fail the is_main_input_context test.

This changes the location of the 'required-from' message in g++.dg/template/instantiate5.C. It now points at the vfunc. However, the current location is misleading -- although it's on the 'C<B> c;' line, that's just happenstance as the last token in the file. If we append some unrelated C++, we'll point to that. Which isn't really helpful.

committing to trunk.


Nathan Sidwell
2018-02-14  Nathan Sidwell  <nat...@acm.org>

	* decl2.c (mark_vtable_entries): Set input_location to decl's.
	(c_parse_final_cleanups): Restore input_location after emitting

	* g++.dg/template/instantiate5.C: Adjust required-from loc.

Index: cp/decl2.c
--- cp/decl2.c	(revision 257657)
+++ cp/decl2.c	(working copy)
@@ -1825,6 +1825,11 @@ mark_vtable_entries (tree decl)
 	 function, so we emit the thunks there instead.  */
       if (DECL_THUNK_P (fn))
 	use_thunk (fn, /*emit_p=*/0);
+      /* Set the location, as marking the function could cause
+         instantiation.  We do not need to preserve the incoming
+         location, as we're called from c_parse_final_cleanups, which
+         takes care of that.  */
+      input_location = DECL_SOURCE_LOCATION (fn);
       mark_used (fn);
@@ -4727,6 +4732,9 @@ c_parse_final_cleanups (void)
 	    reconsider = true;
 	    keyed_classes->unordered_remove (i);
+      /* The input_location may have been changed during marking of
+	 vtable entries.  */
+      input_location = locus_at_end_of_parsing;
       /* Write out needed type info variables.  We have to be careful
 	 looping through unemitted decls, because emit_tinfo_decl may
Index: testsuite/g++.dg/template/instantiate5.C
--- testsuite/g++.dg/template/instantiate5.C	(revision 257657)
+++ testsuite/g++.dg/template/instantiate5.C	(working copy)
@@ -18,7 +18,12 @@ struct B
 template <typename T> struct C
-  virtual void bar() const { T::foo(); } // { dg-error "no matching function" }
+  virtual void bar() const	// { dg-message "required" }
+  {
+    T::foo(); // { dg-error "no matching function" }
+  }
-C<B> c;				// { dg-message "required" }
+C<B> c;
+int k;

Reply via email to