Skip to content

Commit adcd1bb

Browse files
authored
[Clang] Fix the template argument collection after CWG2369 (#147894)
Since the function template isn't instantiated before constraint checking, we'll not be able to find the outer template arguments through function specialization when evaluating the inner constraint that is nested within a larger constraint expression. The only practical solution is to get them back through the code synthesis context, which also allows us to eliminate an overload of getTemplateInstantiationArgs. No release note because it's a regression on trunk. Fixes #147772
1 parent 1ccd779 commit adcd1bb

File tree

4 files changed

+50
-37
lines changed

4 files changed

+50
-37
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13318,18 +13318,6 @@ class Sema final : public SemaBase {
1331813318
/// \param ForDefaultArgumentSubstitution indicates we should continue looking
1331913319
/// when encountering a specialized member function template, rather than
1332013320
/// returning immediately.
13321-
void getTemplateInstantiationArgs(
13322-
MultiLevelTemplateArgumentList &Result, const NamedDecl *D,
13323-
const DeclContext *DC = nullptr, bool Final = false,
13324-
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
13325-
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
13326-
bool ForConstraintInstantiation = false,
13327-
bool SkipForSpecialization = false,
13328-
bool ForDefaultArgumentSubstitution = false);
13329-
13330-
/// This creates a new \p MultiLevelTemplateArgumentList and invokes the other
13331-
/// overload with it as the first parameter. Prefer this overload in most
13332-
/// situations.
1333313321
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
1333413322
const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
1333513323
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,

clang/lib/Sema/SemaConcept.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,15 +1078,23 @@ static bool CheckFunctionConstraintsWithoutInstantiation(
10781078
// template. We need the entire list, since the constraint is completely
10791079
// uninstantiated at this point.
10801080

1081-
// FIXME: Add TemplateArgs through the 'Innermost' parameter once
1082-
// the refactoring of getTemplateInstantiationArgs() relands.
10831081
MultiLevelTemplateArgumentList MLTAL;
1084-
MLTAL.addOuterTemplateArguments(Template, {}, /*Final=*/false);
1085-
SemaRef.getTemplateInstantiationArgs(
1086-
MLTAL, /*D=*/FD, FD,
1087-
/*Final=*/false, /*Innermost=*/{}, /*RelativeToPrimary=*/true,
1088-
/*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true);
1089-
MLTAL.replaceInnermostTemplateArguments(Template, TemplateArgs);
1082+
{
1083+
// getTemplateInstantiationArgs uses this instantiation context to find out
1084+
// template arguments for uninstantiated functions.
1085+
// We don't want this RAII object to persist, because there would be
1086+
// otherwise duplicate diagnostic notes.
1087+
Sema::InstantiatingTemplate Inst(
1088+
SemaRef, PointOfInstantiation,
1089+
Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs,
1090+
PointOfInstantiation);
1091+
if (Inst.isInvalid())
1092+
return true;
1093+
MLTAL = SemaRef.getTemplateInstantiationArgs(
1094+
/*D=*/FD, FD,
1095+
/*Final=*/false, /*Innermost=*/{}, /*RelativeToPrimary=*/true,
1096+
/*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true);
1097+
}
10901098

10911099
Sema::ContextRAII SavedContext(SemaRef, FD);
10921100
std::optional<Sema::CXXThisScopeRAII> ThisScope;

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -309,10 +309,24 @@ Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
309309
isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
310310
return Response::Done();
311311

312-
} else if (Function->getDescribedFunctionTemplate()) {
312+
} else if (auto *Template = Function->getDescribedFunctionTemplate()) {
313313
assert(
314314
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
315315
"Outer template not instantiated?");
316+
if (ForConstraintInstantiation) {
317+
for (auto &Inst : llvm::reverse(SemaRef.CodeSynthesisContexts)) {
318+
if (Inst.Kind == Sema::CodeSynthesisContext::ConstraintsCheck &&
319+
Inst.Entity == Template) {
320+
// After CWG2369, the outer templates are not instantiated when
321+
// checking its associated constraints. So add them back through the
322+
// synthesis context; this is useful for e.g. nested constraints
323+
// involving lambdas.
324+
Result.addOuterTemplateArguments(Template, Inst.template_arguments(),
325+
/*Final=*/false);
326+
break;
327+
}
328+
}
329+
}
316330
}
317331
// If this is a friend or local declaration and it declares an entity at
318332
// namespace scope, take arguments from its lexical parent
@@ -474,21 +488,6 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
474488
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
475489
// Accumulate the set of template argument lists in this structure.
476490
MultiLevelTemplateArgumentList Result;
477-
getTemplateInstantiationArgs(
478-
Result, ND, DC, Final, Innermost, RelativeToPrimary, Pattern,
479-
ForConstraintInstantiation, SkipForSpecialization,
480-
ForDefaultArgumentSubstitution);
481-
return Result;
482-
}
483-
484-
void Sema::getTemplateInstantiationArgs(
485-
MultiLevelTemplateArgumentList &Result, const NamedDecl *ND,
486-
const DeclContext *DC, bool Final,
487-
std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
488-
const FunctionDecl *Pattern, bool ForConstraintInstantiation,
489-
bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) {
490-
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
491-
// Accumulate the set of template argument lists in this structure.
492491

493492
using namespace TemplateInstArgsHelpers;
494493
const Decl *CurDecl = ND;
@@ -548,12 +547,13 @@ void Sema::getTemplateInstantiationArgs(
548547
}
549548

550549
if (R.IsDone)
551-
return;
550+
return Result;
552551
if (R.ClearRelativeToPrimary)
553552
RelativeToPrimary = false;
554553
assert(R.NextDecl);
555554
CurDecl = R.NextDecl;
556555
}
556+
return Result;
557557
}
558558

559559
bool Sema::CodeSynthesisContext::isInstantiationRecord() const {

clang/test/SemaTemplate/concepts-lambda.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,23 @@ void foo() {
341341

342342
}
343343

344+
namespace GH147772 {
345+
346+
template<int...>
347+
struct seq {};
348+
349+
using arr = char[1];
350+
351+
struct foo {
352+
template<int... i>
353+
constexpr foo(seq<i...>) requires requires {
354+
arr { [](auto) requires(i, true) { return 0; }(i)... };
355+
} {}
356+
};
357+
358+
constexpr auto bar = foo(seq<0>());
359+
}
360+
344361
namespace GH147650 {
345362
template <int> int b;
346363
template <int b>

0 commit comments

Comments
 (0)