[cfe-dev] Warn on template def after explicit instantiation?

John McCall rjmccall at apple.com
Sat Jan 5 16:14:09 PST 2013


On Jan 4, 2013, at 5:58 PM, "Robinson, Paul" <Paul.Robinson at am.sony.com> wrote:
>> On Jan 4, 2013, at 4:44 PM, "Robinson, Paul" <Paul.Robinson at am.sony.com> wrote:
>>> A client ran into the following situation. Suppose we have this:
>>> 
>>> // Declarations from a header file.
>>> template <class T> SomeTemplate {
>>> public:
>>>   void Init();
>>> };
>>> class FooBar { };
>>> // End of the header file.
>>> 
>>> // Here's the initial source module.
>>> // Explicitly instantiate SomeTemplate.
>>> template SomeTemplate<FooBar>;
>>> // Oops, forgot to define Init().
>>> template <class T> SomeTemplate<T>::Init() { }
>>> // Now we use the stuff.
>>> SomeTemplate<FooBar> Obj;
>>> void foo() {
>>>   Obj.Init();
>>> }
>>> 
>>> This built cleanly. But, moving Obj and foo() to another source file
>>> caused a link-time error, because of an undefined reference to
>>> SomeTemplate<FooBar>::Init().  (Call this "version 2.")
>>> 
>>> The client understands that the original module worked because
>>> "Obj.Init()" implicitly instantiated SomeTemplate<FooBar>::Init() as a
>>> definition, because the template definition existed in the same
>>> compilation unit. And moving the same code to a separate module
>>> implicitly instantiated Init() as a declaration, because that's all
>>> that was in the header file.  The "template SomeTemplate<FooBar>;"
>>> didn't instantiate a definition of Init() because that definition hadn't
>>> happened yet; hence, the link-time error. The fix was to move the
>>> explicit instantiation down past the template method definitions.
>>> (Call that one "version 3.")
>>> 
>>> His question is: Can we have a warning for the situation where a
>>> template definition of a method follows an explicit instantiation of
>>> its containing class?  (Or maybe, if a template definition follows an
>>> explicit instantiation of its declaration?)  He argues that while it's
>>> well-defined by the standard, it's probably a mistake on the
>>> programmer's part (as it was for his code), and a compile-time
>>> diagnostic would have made it a lot easier to figure out.
>> 
>> I'd be skeptical of such a warning.  It's certainly reasonable for a
>> user who's decided to play careful explicit-instantiation games to
>> be intentionally defining a member after the explicit instantiation
>> to avoid the instantiation of a particular member.  That makes it
>> hard to justify this warning being default-on — and I can't
>> really imagine it doing much good being default-off.
> 
> It's true that a template-savvy coder could devise something where some
> methods did not exist for certain specializations.  But...
> I should think the more common use-case is somebody porting code from
> MSVC or other less-careful compiler to Clang, and running into this
> unintentionally.
> 
> As a parallel example, Clang now complains if I fail to parenthesize
> expressions with multiple operators where it thinks I might not be
> getting the precedence right.  This is not exactly expert-friendly
> either.  I think this is another example in the same vein.

One major difference is that that warning can easily be suppressed
through innocuous code changes — changes that, in fact, make the
code more legible to people who haven't memorized the more
obscure parts of the precedence tables.  There is no way I can see
to suppress your proposed warning without significantly changing
the behavior of the code — for example, switching an explicit
instantiation of a class to an explicit instantiation of every defined
member of it.

Another major difference is that that warning points out something
that otherwise requires dynamic testing to detect.  Your warning
points out something that, if it matters at all, is going to cause the
build to fail anyway.  We still do like to warn about those things when
we can, but it does make it a lot less important.

A third difference is that I consider (and I think most people would
agree with me) explicit instantiation of out-of-line definitions of class
template members to be an expert technique.  That makes it more
likely that the user really is intending to do something subtle.

All that said, it would be reasonable to have a warning about explicit
instantiations that don't seem to be necessary.  If I had to make a
none-too-careful first guess at the criteria for such a warning, it would
be explicit instantiations of class templates that (1) aren't preceded
by an explicit instantiation declaration and (2) don't instantiate any
methods that aren't defined in the class definition.  If that would catch
your user's case, then great.

John.



More information about the cfe-dev mailing list