This is an archive of the discontinued LLVM Phabricator instance.

[Sema] PR27155: Fix a template argument deduction bug with base classes
ClosedPublic

Authored by erik.pilkington on Apr 7 2016, 2:22 PM.

Details

Reviewers
rsmith
Summary

Previously, clang would incorrectly reject the following:

struct S {};
template<class T, int i> struct D : T {};
template<class T> void Foo(D<T, 1>);
int fn() {
  D<D<S, 1>, 0> v;
  Foo(v);
}

The problem is that clang initially tries to apply D<S, 1> for T in Foo, storing the result (in Deduced). Then clang tries to match 0 for 1 in Foo, would fail, and begin to consider the base classes of v (per temp.deduct.call p4.3), without resetting the original faulty assumption. This patch simply saves the deduced arguments before attempting the faulty deduction, then restores them once the faulty deduction fails.

Note: This section of code still has a somewhat related latent bug where ambiguous base class deductions are left undiagnosed, for example:

int fn2() {
  D<D<D<S, 1>, 1>, 0> v;
  Foo(v); // error, is T deduced to be S or D<S, 1>?
}

Which is outlawed by temp.deduct.call p5. I have another patch that fixes this, which I'll submit once(/if) this goes through.

Diff Detail

Event Timeline

erik.pilkington retitled this revision from to [Sema] PR27155: Fix a template argument deduction bug with base classes.
erik.pilkington updated this object.
erik.pilkington added a reviewer: rsmith.
erik.pilkington added a subscriber: cfe-commits.
rsmith added inline comments.Apr 7 2016, 2:55 PM
lib/Sema/SemaTemplateDeduction.cpp
1424–1426

Can you also make this saving (and restoring) of the old deduced arguments conditional on TDF_DerivedClass and the argument type being a class type? Maybe duplicate the DeduceTemplateArguments call and put one copy inside the if (const RecordType *RecordT = ... block and the other on the else path, instead of moving the copy earlier.

Invert some control flow for clarity, avoid unnecessary copy of deduced template arguments.

rsmith accepted this revision.Apr 7 2016, 3:44 PM
rsmith edited edge metadata.
rsmith added inline comments.
lib/Sema/SemaTemplateDeduction.cpp
1449–1451

Can you move this up and merge it with the TDF_DerivedClass check to also skip the copy in the case where the argument is not of class type?

1453–1457

... This too, if it's not too awkward.

This revision is now accepted and ready to land.Apr 7 2016, 3:44 PM
erik.pilkington edited edge metadata.
erik.pilkington marked an inline comment as done.

Avoid another copy when Arg is not a record type.

Richard: I don't think it's possible to avoid copying Deduced when Arg is not a complete type, because we only try to complete it when we know that the deduction would otherwise fail (therefore clobbering Deduced).

If this looks good, would you mind committing it? Thanks for reviewing!

rsmith closed this revision.Apr 25 2016, 12:34 PM

Committed as r267444.

I refactored it to use CXXRecordDecl::forallBases instead of a hand-rolled traversal of the base classes in r267453.