diff mbox series

[C++] : instantiation via vtable marking

Message ID 8cda4082-5b50-289b-eba6-7ba59de39fb9@acm.org
State New
Headers show
Series [C++] : instantiation via vtable marking | expand

Commit Message

Nathan Sidwell Feb. 14, 2018, 4:28 p.m. UTC
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
diff mbox series

Patch

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

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

	gcc/testsuite/
	* 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;