Skip to content

Commit 463a4f1

Browse files
zyn0217mizvekov
andauthored
[Clang][Concepts] Normalize SizeOfPackExpr's pack declaration (#110238)
SizeOfPackExpr has a pointer to the referenced pack declaration, which is left as-is during the transformation process. The situation could be subtle when a friend class template declaration comes into play. The declaration per se would be instantiated into its parent declaration context, and consequently, the template parameter list would have a depth adjustment; however, as we don't evaluate constraints during instantiation, those constraints would still reference the original template parameters, which is fine for constraint evaluation because we have handled friend cases in the template argument collection. However, things are different when we want to profile the constraint expression with dependent template arguments. The hash algorithm of SizeOfPackExpr takes its pack declaration as a factor, which is the original template parameter that might still have untransformed template depths after the constraint normalization. This patch transforms the pack declaration when normalizing constraint expressions and pluses a fix in HandleFunctionTemplateDecl() where the associated declaration is incorrect for nested specifiers. Note that the fix in HandleFunctionTemplateDecl(), as well as the handling logic for NestedNameSpecifier, would be removed once Krystian's refactoring patch lands. But I still want to incorporate it in the patch for the correction purpose, though it hasn't caused any problems so far - I just tripped over that in getFullyPackExpandedSize() when I tried to extract the transformed declarations from the TemplateArgument. Fixes #93099 --------- Co-authored-by: Matheus Izvekov <[email protected]>
1 parent 47d42cf commit 463a4f1

File tree

4 files changed

+73
-6
lines changed

4 files changed

+73
-6
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,8 @@ Bug Fixes to C++ Support
453453
- Mangle friend function templates with a constraint that depends on a template parameter from an enclosing template as members of the enclosing class. (#GH110247)
454454
- Fixed an issue in constraint evaluation, where type constraints on the lambda expression
455455
containing outer unexpanded parameters were not correctly expanded. (#GH101754)
456+
- Fixed a bug in constraint expression comparison where the ``sizeof...`` expression was not handled properly
457+
in certain friend declarations. (#GH93099)
456458

457459
Bug Fixes to AST Handling
458460
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaConcept.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -975,11 +975,14 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
975975
// parameters that the surrounding function hasn't been instantiated yet. Note
976976
// this may happen while we're comparing two templates' constraint
977977
// equivalence.
978-
LocalInstantiationScope ScopeForParameters(S);
979-
if (auto *FD = DeclInfo.getDecl()->getAsFunction())
978+
std::optional<LocalInstantiationScope> ScopeForParameters;
979+
if (const NamedDecl *ND = DeclInfo.getDecl();
980+
ND && ND->isFunctionOrFunctionTemplate()) {
981+
ScopeForParameters.emplace(S);
982+
const FunctionDecl *FD = ND->getAsFunction();
980983
for (auto *PVD : FD->parameters()) {
981984
if (!PVD->isParameterPack()) {
982-
ScopeForParameters.InstantiatedLocal(PVD, PVD);
985+
ScopeForParameters->InstantiatedLocal(PVD, PVD);
983986
continue;
984987
}
985988
// This is hacky: we're mapping the parameter pack to a size-of-1 argument
@@ -998,9 +1001,10 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
9981001
// that we can eliminate the Scope in the cases where the declarations are
9991002
// not necessarily instantiated. It would also benefit the noexcept
10001003
// specifier comparison.
1001-
ScopeForParameters.MakeInstantiatedLocalArgPack(PVD);
1002-
ScopeForParameters.InstantiatedLocalPackArg(PVD, PVD);
1004+
ScopeForParameters->MakeInstantiatedLocalArgPack(PVD);
1005+
ScopeForParameters->InstantiatedLocalPackArg(PVD, PVD);
10031006
}
1007+
}
10041008

10051009
std::optional<Sema::CXXThisScopeRAII> ThisScope;
10061010

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
371371
Specialization->getTemplateInstantiationArgs().asArray();
372372
}
373373
Result.addOuterTemplateArguments(
374-
const_cast<FunctionTemplateDecl *>(FTD), Arguments,
374+
TSTy->getTemplateName().getAsTemplateDecl(), Arguments,
375375
/*Final=*/false);
376376
}
377377
}
@@ -1737,6 +1737,33 @@ namespace {
17371737
return inherited::TransformLambdaBody(E, Body);
17381738
}
17391739

1740+
ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc,
1741+
NamedDecl *Pack, SourceLocation PackLoc,
1742+
SourceLocation RParenLoc,
1743+
std::optional<unsigned> Length,
1744+
ArrayRef<TemplateArgument> PartialArgs) {
1745+
if (SemaRef.CodeSynthesisContexts.back().Kind !=
1746+
Sema::CodeSynthesisContext::ConstraintNormalization)
1747+
return inherited::RebuildSizeOfPackExpr(OperatorLoc, Pack, PackLoc,
1748+
RParenLoc, Length, PartialArgs);
1749+
1750+
#ifndef NDEBUG
1751+
for (auto *Iter = TemplateArgs.begin(); Iter != TemplateArgs.end();
1752+
++Iter)
1753+
for (const TemplateArgument &TA : Iter->Args)
1754+
assert(TA.getKind() != TemplateArgument::Pack || TA.pack_size() == 1);
1755+
#endif
1756+
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(
1757+
SemaRef, /*NewSubstitutionIndex=*/0);
1758+
Decl *NewPack = TransformDecl(PackLoc, Pack);
1759+
if (!NewPack)
1760+
return ExprError();
1761+
1762+
return inherited::RebuildSizeOfPackExpr(OperatorLoc,
1763+
cast<NamedDecl>(NewPack), PackLoc,
1764+
RParenLoc, Length, PartialArgs);
1765+
}
1766+
17401767
ExprResult TransformRequiresExpr(RequiresExpr *E) {
17411768
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
17421769
ExprResult TransReq = inherited::TransformRequiresExpr(E);

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,3 +666,37 @@ int foo() {
666666
}
667667

668668
} // namespace eve
669+
670+
namespace GH93099 {
671+
672+
// Issues with sizeof...(expr)
673+
674+
template <typename T = int> struct C {
675+
template <int... N>
676+
requires(sizeof...(N) > 0)
677+
friend class NTTP;
678+
679+
template <class... Tp>
680+
requires(sizeof...(Tp) > 0)
681+
friend class TP;
682+
683+
template <template <typename> class... TTp>
684+
requires(sizeof...(TTp) > 0)
685+
friend class TTP;
686+
};
687+
688+
template <int... N>
689+
requires(sizeof...(N) > 0)
690+
class NTTP;
691+
692+
template <class... Tp>
693+
requires(sizeof...(Tp) > 0)
694+
class TP;
695+
696+
template <template <typename> class... TTp>
697+
requires(sizeof...(TTp) > 0)
698+
class TTP;
699+
700+
C v;
701+
702+
} // namespace GH93099

0 commit comments

Comments
 (0)