Skip to content

Commit 37b4df4

Browse files
authored
[Clang] Remove the wrong assumption when rebuilding SizeOfPackExprs for constraint normalization (#115120)
In 463a4f1, we assumed that all the template argument packs are of size 1 when normalizing a constraint expression because I mistakenly thought those packs were obtained from their injected template parameters. This was wrong because we might be checking constraints when instantiating a friend declaration within a class template specialization, where the parent class template is specialized with non-dependent template arguments. In that sense, we shouldn't assume any pack size nor expand anything in such a scenario. Moreover, there are no intermediate (substituted but unexpanded) AST nodes for template template parameters, so we have to special-case their transformations by looking into the instantiation scope instead of extracting anything from template arguments. Fixes #115098
1 parent 2f40e3e commit 37b4df4

File tree

3 files changed

+45
-25
lines changed

3 files changed

+45
-25
lines changed

clang/include/clang/AST/ExprCXX.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4326,6 +4326,8 @@ class SizeOfPackExpr final
43264326
/// Retrieve the parameter pack.
43274327
NamedDecl *getPack() const { return Pack; }
43284328

4329+
void setPack(NamedDecl *NewPack) { Pack = NewPack; }
4330+
43294331
/// Retrieve the length of the parameter pack.
43304332
///
43314333
/// This routine may only be invoked when the expression is not

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1749,31 +1749,21 @@ namespace {
17491749
return inherited::TransformLambdaBody(E, Body);
17501750
}
17511751

1752-
ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc,
1753-
NamedDecl *Pack, SourceLocation PackLoc,
1754-
SourceLocation RParenLoc,
1755-
std::optional<unsigned> Length,
1756-
ArrayRef<TemplateArgument> PartialArgs) {
1757-
if (SemaRef.CodeSynthesisContexts.back().Kind !=
1758-
Sema::CodeSynthesisContext::ConstraintNormalization)
1759-
return inherited::RebuildSizeOfPackExpr(OperatorLoc, Pack, PackLoc,
1760-
RParenLoc, Length, PartialArgs);
1761-
1762-
#ifndef NDEBUG
1763-
for (auto *Iter = TemplateArgs.begin(); Iter != TemplateArgs.end();
1764-
++Iter)
1765-
for (const TemplateArgument &TA : Iter->Args)
1766-
assert(TA.getKind() != TemplateArgument::Pack || TA.pack_size() == 1);
1767-
#endif
1768-
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(
1769-
SemaRef, /*NewSubstitutionIndex=*/0);
1770-
Decl *NewPack = TransformDecl(PackLoc, Pack);
1771-
if (!NewPack)
1772-
return ExprError();
1773-
1774-
return inherited::RebuildSizeOfPackExpr(OperatorLoc,
1775-
cast<NamedDecl>(NewPack), PackLoc,
1776-
RParenLoc, Length, PartialArgs);
1752+
ExprResult TransformSizeOfPackExpr(SizeOfPackExpr *E) {
1753+
ExprResult Transformed = inherited::TransformSizeOfPackExpr(E);
1754+
if (!Transformed.isUsable())
1755+
return Transformed;
1756+
auto *TransformedExpr = cast<SizeOfPackExpr>(Transformed.get());
1757+
if (SemaRef.CodeSynthesisContexts.back().Kind ==
1758+
Sema::CodeSynthesisContext::ConstraintNormalization &&
1759+
TransformedExpr->getPack() == E->getPack()) {
1760+
Decl *NewPack =
1761+
TransformDecl(E->getPackLoc(), TransformedExpr->getPack());
1762+
if (!NewPack)
1763+
return ExprError();
1764+
TransformedExpr->setPack(cast<NamedDecl>(NewPack));
1765+
}
1766+
return TransformedExpr;
17771767
}
17781768

17791769
ExprResult TransformRequiresExpr(RequiresExpr *E) {
@@ -1899,6 +1889,15 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
18991889
TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition());
19001890

19011891
if (TTP->isParameterPack()) {
1892+
// We might not have an index for pack expansion when normalizing
1893+
// constraint expressions. In that case, resort to instantiation scopes
1894+
// for the transformed declarations.
1895+
if (SemaRef.ArgumentPackSubstitutionIndex == -1 &&
1896+
SemaRef.CodeSynthesisContexts.back().Kind ==
1897+
Sema::CodeSynthesisContext::ConstraintNormalization) {
1898+
return SemaRef.FindInstantiatedDecl(Loc, cast<NamedDecl>(D),
1899+
TemplateArgs);
1900+
}
19021901
assert(Arg.getKind() == TemplateArgument::Pack &&
19031902
"Missing argument pack");
19041903
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);

clang/test/SemaTemplate/concepts-out-of-line-def.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,25 @@ C v;
703703

704704
} // namespace GH93099
705705

706+
namespace GH115098 {
707+
708+
template <typename... Ts> struct c {
709+
template <typename T>
710+
requires(sizeof...(Ts) > 0)
711+
friend bool operator==(c, c);
712+
};
713+
714+
template <typename... Ts> struct d {
715+
template <typename T>
716+
requires(sizeof...(Ts) > 0)
717+
friend bool operator==(d, d);
718+
};
719+
720+
template struct c<int>;
721+
template struct d<int, int>;
722+
723+
} // namespace GH115098
724+
706725
namespace GH114685 {
707726

708727
template <typename T> struct ptr {

0 commit comments

Comments
 (0)