Skip to content

Commit 17e4298

Browse files
committed
[Clang] Fix the template argument collection after CWG2369
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.
1 parent 613c38a commit 17e4298

File tree

4 files changed

+46
-36
lines changed

4 files changed

+46
-36
lines changed

clang/include/clang/Sema/Sema.h

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

clang/lib/Sema/SemaConcept.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,15 +1078,19 @@ 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.
1083-
MultiLevelTemplateArgumentList MLTAL;
1084-
MLTAL.addOuterTemplateArguments(Template, {}, /*Final=*/false);
1085-
SemaRef.getTemplateInstantiationArgs(
1086-
MLTAL, /*D=*/FD, FD,
1081+
// getTemplateInstantiationArgs uses this instantiation context to find out
1082+
// template arguments for uninstantiated functions.
1083+
std::optional<Sema::InstantiatingTemplate> Inst(
1084+
std::in_place, SemaRef, PointOfInstantiation,
1085+
Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs,
1086+
PointOfInstantiation);
1087+
if (Inst->isInvalid())
1088+
return true;
1089+
MultiLevelTemplateArgumentList MLTAL = SemaRef.getTemplateInstantiationArgs(
1090+
/*D=*/FD, FD,
10871091
/*Final=*/false, /*Innermost=*/{}, /*RelativeToPrimary=*/true,
10881092
/*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true);
1089-
MLTAL.replaceInnermostTemplateArguments(Template, TemplateArgs);
1093+
Inst = std::nullopt;
10901094

10911095
Sema::ContextRAII SavedContext(SemaRef, FD);
10921096
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: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,3 +340,21 @@ void foo() {
340340
}
341341

342342
}
343+
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+
}

0 commit comments

Comments
 (0)