Skip to content

[Clang][Concepts] Normalize SizeOfPackExpr's pack declaration #110238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Oct 1, 2024
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,8 @@ Bug Fixes to C++ Support
- Mangle friend function templates with a constraint that depends on a template parameter from an enclosing template as members of the enclosing class. (#GH110247)
- Fixed an issue in constraint evaluation, where type constraints on the lambda expression
containing outer unexpanded parameters were not correctly expanded. (#GH101754)
- Fixed a bug in constraint expression comparison where the ``sizeof...`` expression was not handled properly
in certain friend declarations. (#GH93099)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
14 changes: 9 additions & 5 deletions clang/lib/Sema/SemaConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -975,11 +975,14 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
// parameters that the surrounding function hasn't been instantiated yet. Note
// this may happen while we're comparing two templates' constraint
// equivalence.
LocalInstantiationScope ScopeForParameters(S);
if (auto *FD = DeclInfo.getDecl()->getAsFunction())
std::optional<LocalInstantiationScope> ScopeForParameters;
if (const NamedDecl *ND = DeclInfo.getDecl();
ND && ND->isFunctionOrFunctionTemplate()) {
ScopeForParameters.emplace(S);
const FunctionDecl *FD = ND->getAsFunction();
for (auto *PVD : FD->parameters()) {
if (!PVD->isParameterPack()) {
ScopeForParameters.InstantiatedLocal(PVD, PVD);
ScopeForParameters->InstantiatedLocal(PVD, PVD);
continue;
}
// This is hacky: we're mapping the parameter pack to a size-of-1 argument
Expand All @@ -998,9 +1001,10 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
// that we can eliminate the Scope in the cases where the declarations are
// not necessarily instantiated. It would also benefit the noexcept
// specifier comparison.
ScopeForParameters.MakeInstantiatedLocalArgPack(PVD);
ScopeForParameters.InstantiatedLocalPackArg(PVD, PVD);
ScopeForParameters->MakeInstantiatedLocalArgPack(PVD);
ScopeForParameters->InstantiatedLocalPackArg(PVD, PVD);
}
}

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

Expand Down
29 changes: 28 additions & 1 deletion clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
Specialization->getTemplateInstantiationArgs().asArray();
}
Result.addOuterTemplateArguments(
const_cast<FunctionTemplateDecl *>(FTD), Arguments,
TSTy->getTemplateName().getAsTemplateDecl(), Arguments,
/*Final=*/false);
}
}
Expand Down Expand Up @@ -1737,6 +1737,33 @@ namespace {
return inherited::TransformLambdaBody(E, Body);
}

ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc,
NamedDecl *Pack, SourceLocation PackLoc,
SourceLocation RParenLoc,
std::optional<unsigned> Length,
ArrayRef<TemplateArgument> PartialArgs) {
if (SemaRef.CodeSynthesisContexts.back().Kind !=
Sema::CodeSynthesisContext::ConstraintNormalization)
return inherited::RebuildSizeOfPackExpr(OperatorLoc, Pack, PackLoc,
RParenLoc, Length, PartialArgs);

#ifndef NDEBUG
for (auto *Iter = TemplateArgs.begin(); Iter != TemplateArgs.end();
++Iter)
for (const TemplateArgument &TA : Iter->Args)
assert(TA.getKind() != TemplateArgument::Pack || TA.pack_size() == 1);
#endif
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(
SemaRef, /*NewSubstitutionIndex=*/0);
Decl *NewPack = TransformDecl(PackLoc, Pack);
if (!NewPack)
return ExprError();

return inherited::RebuildSizeOfPackExpr(OperatorLoc,
cast<NamedDecl>(NewPack), PackLoc,
RParenLoc, Length, PartialArgs);
}

ExprResult TransformRequiresExpr(RequiresExpr *E) {
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
ExprResult TransReq = inherited::TransformRequiresExpr(E);
Expand Down
34 changes: 34 additions & 0 deletions clang/test/SemaTemplate/concepts-out-of-line-def.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,3 +666,37 @@ int foo() {
}

} // namespace eve

namespace GH93099 {

// Issues with sizeof...(expr)

template <typename T = int> struct C {
template <int... N>
requires(sizeof...(N) > 0)
friend class NTTP;

template <class... Tp>
requires(sizeof...(Tp) > 0)
friend class TP;

template <template <typename> class... TTp>
requires(sizeof...(TTp) > 0)
friend class TTP;
};

template <int... N>
requires(sizeof...(N) > 0)
class NTTP;

template <class... Tp>
requires(sizeof...(Tp) > 0)
class TP;

template <template <typename> class... TTp>
requires(sizeof...(TTp) > 0)
class TTP;

C v;

} // namespace GH93099