This is an archive of the discontinued LLVM Phabricator instance.

[clang] Don't crash on an incomplete-type base specifier in template context.
ClosedPublic

Authored by hokein on Nov 9 2021, 2:15 AM.

Diff Detail

Event Timeline

hokein requested review of this revision.Nov 9 2021, 2:15 AM
hokein created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptNov 9 2021, 2:15 AM
sammccall accepted this revision.Nov 9 2021, 3:51 AM
sammccall added inline comments.
clang/test/SemaCXX/base-class-ambiguity-check.cpp
15

maybe put (dependent) in this comment, as it's the reason this code is valid without diagnostics

17

we're asserting here there are no diagnostics, maybe instantiate the template and assert those?

clang/test/SemaCXX/ms-interface.cpp
114

is there some tricky interaction with __interface here that justifies testing this again? If it's testing the same codepath, I'd say one test is enough

This revision is now accepted and ready to land.Nov 9 2021, 3:51 AM
hokein updated this revision to Diff 385807.Nov 9 2021, 7:08 AM
hokein marked 2 inline comments as done.

address comments and added a missing case

hokein added inline comments.Nov 9 2021, 7:12 AM
clang/test/SemaCXX/base-class-ambiguity-check.cpp
16

The diagnostic is suboptimal (I'd expect it is "invalid use of incomplete type"), but it is not regression, clang shows the same diagnostics for the following non-crash case:

template <typename T> struct Foo2 {
  struct Base1;
  struct Derived : Base1 {};
}
clang/test/SemaCXX/ms-interface.cpp
114

They test different paths (this was founded in my previous-and-incomplete fix):

  • this tests isInterface() on Line 2740 in SemaDeclCxx.cpp;
  • the above one tests NoteIndirectBases (multiple base classes) on Line 2736 in SemaDeclCXX.cpp;
sammccall accepted this revision.Nov 9 2021, 7:36 AM
sammccall added inline comments.
clang/test/SemaCXX/base-class-ambiguity-check.cpp
16

Or even

template <int> struct X;
X<42> y;

I think the diagnostic is OK - it's diagnosing why the type *is* incomplete, rather than why the type *may not* be complete.

Typical use of this pattern would be to provide an out-of-line definition template:

template <typename T> struct Foo2<T>::Base1 {
  T contents;
}

in which case instantiation is the right idea.