Skip to content

Commit a0651db

Browse files
authored
[clang][Sema] Avoid guessing unexpanded packs' size in getFullyPackExpandedSize (#87768)
There has been an optimization for `SizeOfPackExprs` since c5452ed, in which we overlooked a case where the template arguments were not yet formed into a `PackExpansionType` at the token annotation stage. This led to a problem in that a template involving such expressions may lose its nature of being dependent, causing some false-positive diagnostics. Fixes #84220
1 parent 89ba7e1 commit a0651db

File tree

3 files changed

+35
-0
lines changed

3 files changed

+35
-0
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ Bug Fixes to C++ Support
526526
- Fix crash when inheriting from a cv-qualified type. Fixes:
527527
(`#35603 <https://github.com/llvm/llvm-project/issues/35603>`_)
528528
- Fix a crash when the using enum declaration uses an anonymous enumeration. Fixes (#GH86790).
529+
- Handled an edge case in ``getFullyPackExpandedSize`` so that we now avoid a false-positive diagnostic. (#GH84220)
529530
- Clang now correctly tracks type dependence of by-value captures in lambdas with an explicit
530531
object parameter.
531532
Fixes (#GH70604), (#GH79754), (#GH84163), (#GH84425), (#GH86054), (#GH86398), and (#GH86399).

clang/lib/Sema/SemaTemplateVariadic.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,17 @@ std::optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
12431243
// expanded this pack expansion into the enclosing pack if we could.
12441244
if (Elem.isPackExpansion())
12451245
return std::nullopt;
1246+
// Don't guess the size of unexpanded packs. The pack within a template
1247+
// argument may have yet to be of a PackExpansion type before we see the
1248+
// ellipsis in the annotation stage.
1249+
//
1250+
// This doesn't mean we would invalidate the optimization: Arg can be an
1251+
// unexpanded pack regardless of Elem's dependence. For instance,
1252+
// A TemplateArgument that contains either a SubstTemplateTypeParmPackType
1253+
// or SubstNonTypeTemplateParmPackExpr is always considered Unexpanded, but
1254+
// the underlying TemplateArgument thereof may not.
1255+
if (Elem.containsUnexpandedParameterPack())
1256+
return std::nullopt;
12461257
}
12471258
return Pack.pack_size();
12481259
}

clang/test/SemaTemplate/alias-templates.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,29 @@ namespace PR14858 {
236236
void test_q(int (&a)[5]) { Q<B, B, B>().f<B, B>(&a); }
237237
}
238238

239+
namespace PR84220 {
240+
241+
template <class...> class list {};
242+
243+
template <int> struct foo_impl {
244+
template <class> using f = int;
245+
};
246+
247+
template <class... xs>
248+
using foo = typename foo_impl<sizeof...(xs)>::template f<xs...>;
249+
250+
// We call getFullyPackExpandedSize at the annotation stage
251+
// before parsing the ellipsis next to the foo<xs>. This happens before
252+
// a PackExpansionType is formed for foo<xs>.
253+
// getFullyPackExpandedSize shouldn't determine the value here. Otherwise,
254+
// foo_impl<sizeof...(xs)> would lose its dependency despite the template
255+
// arguments being unsubstituted.
256+
template <class... xs> using test = list<foo<xs>...>;
257+
258+
test<int> a;
259+
260+
}
261+
239262
namespace redecl {
240263
template<typename> using A = int;
241264
template<typename = void> using A = int;

0 commit comments

Comments
 (0)