This is an archive of the discontinued LLVM Phabricator instance.

[clang] Fix serializers for `TypeTemplateParmDecl` + related types
AbandonedPublic

Authored by elsteveogrande on Sep 27 2017, 8:47 AM.

Details

Summary

Addresses issue: https://bugs.llvm.org/show_bug.cgi?id=34728

Template type parameters can optionally have default values; at the first parameter declaration at which the default is declared, e.g. i in template <int i=0, class T>, this decl is treated as the "owner" of the default value, in this case 0.

However the serializer originally didn't record inherited-from-decl (owner) info at non-owners, only the default value in the owner's serialized bytes. So subsequent template declarations that should inherit this default value wouldn't, when used in a PCH or some serialized form.

For example, a precompiled header containing this:

template <int foo=1, class T> int func(T const&);
template <int foo, class T> int func(T const&) { return foo; }

would not work in this source file, if used with PCH (but it would if it were included as an ordinary, non-pre-compiled header):

int main(int, char**) { return func(1.23); }

because of a spurious error about not being able to deduce foo, having lost the default value inheritance info during serialization:

candidate template ignored: couldn't infer template argument 'foo'

Tested with:

  • New test cases added, now passing.
  • Existing test cases look ok. (ninja check-clang)

Diff Detail

Event Timeline

elsteveogrande created this revision.Sep 27 2017, 8:47 AM
elsteveogrande edited the summary of this revision. (Show Details)Sep 27 2017, 8:48 AM
elsteveogrande added a reviewer: rsmith.

I submitted this patch relative to the clang project root, hopefully that's ok.

Hi @bruno, @rsmith, does this approach look ok?

I couldn't easily figure out a better way to store inherited-default-info; doing it alongside the default value seemed the cleanest.

Note: I saw there are three ways to store these data inside the DefaultArgStorage struct, see here:
https://reviews.llvm.org/diffusion/L/browse/cfe/trunk/include/clang/AST/DeclTemplate.h;315074$272

There's (1) the default arg; (2) the reference to the Decl having the default arg (inherited by this Decl); and (3) a pointer to a Chain link, which is the case when modules are used.

The serializer already had (1) covered, and I'm adding (2) here. Maybe the most proper fix is to handle (3) as well. Although it seems no unit tests broke, so this is either ok as is, or there's no test for it :)

So: right now the serialization stream generated in ASTWriterDecl.cpp looks sort of like:

 [ . . . other fields]
bool defaultArgFollows
[Stmt defaultArgStmtRef (if above is true)]
bool inheritedFromDeclFollows
[Decl inheritedFromDecl (if above is true)]

This could be changed to:

 [ . . . other fields]
bool isPartOfChain     <----- add this
bool defaultArgFollows
[Stmt defaultArgStmtRef (if above is true)]
bool inheritedFromDeclFollows
[Decl inheritedFromDecl (if above is true)]

so this can store the DefaultArgStorage with better fidelity. Thoughts?

Thanks! :)

Hi,

Thanks for your patch! Could you please post a patch with full context (git diff -U99999)?

lib/Serialization/ASTWriterDecl.cpp
1541
1551

I think that cast to bool here and below is redundant.

Hi @arphaman, thanks very much! Sorry, I didn't notice there was activity on this old patch until now.

I'll make these changes as suggested and re-send it with full context.

elsteveogrande edited the summary of this revision. (Show Details)

Fixed local var names. Using arc diff which hopefully submits latest changes w/ full context

elsteveogrande marked 2 inline comments as done.Jan 2 2018, 2:29 PM

Update: now works properly with modules as well.

This needed to handle the case where a ParmDecl is already inheriting, but it's innocuously inheriting from the same decl. Now inheritDefaultTemplateArgument will return successfully and avoid the assertion error saying that default argument already inherited.

We'll now possibly step once or twice through the inheritance list, so when a ParmDecl is inheriting from another ParmDecl, which *itself* is inheriting from a third decl. This is the case where inheritDefaultTemplateArgument is called with From being an inheriting (and not "owning") template parameter.

Modules make use of the Chain struct as well, and IIUC this can lead to one extra level of indirection, as it too has a ParmDecl * field. So this now handles up to 2 indirections before validating that the inheritance is consistent.

Passes existing and new tests; also works with a mini project that uses modules, which was previously broken.

Rebase very old diff

cc @rsmith as this has to do with modules.

Verified that (1) existing tests pass on trunk; (2) the new test included here fails when applied to trunk; (3) all tests (including new test) pass when this patch is applied.

hi @rsmith have a look and let me know if this change looks sensible :) Please make sure I have the right mental model for inheritance in the module case

rsmith added inline comments.Jul 31 2018, 2:06 PM
lib/Serialization/ASTReaderDecl.cpp
3448–3456

The idea is to reconstruct the 'inherited default template argument' information when we read a template declaration and find it's a redeclaration of another one, rather than serializing it and deserializing it. (In particular, if an imported template redeclares a non-imported template or a template imported from an unrelated module, it won't know that the prior declaration had a default argument because it doesn't know what the prior declaration was.)

The problem with our implementation of that idea is these breaks: we're (incorrectly) assuming that a template parameter cannot have a default argument if there's a later template parameter that does not have one.

I removed the breaks in r338438, and it fixed your testcase (which I committed alongside that change). Can you check to see if that also fixes the original problem from which this was reduced? Thanks!

elsteveogrande added inline comments.Jul 31 2018, 7:43 PM
lib/Serialization/ASTReaderDecl.cpp
3448–3456

Thanks @rsmith! It sounds like that ought to do it. We'll try again on our end and let you know. Thanks for the quick fix!

elsteveogrande abandoned this revision.Aug 13 2018, 12:33 PM

Dropped in favor of other fix as mentioned above