Skip to content

Commit

Permalink
[Concepts] Fix Concepts on generic lambda in a VarTemplateSpecDecl
Browse files Browse the repository at this point in the history
As fallout of the Deferred Concept Instantiation patch (babdef2), we
got a number of reports of a regression, where we asserted when
instantiating a constraint on a generic lambda inside of a variable
template. See: #57958

The problem was that getTemplateInstantiationArgs function only walked
up declaration contexts, and missed that this is not necessarily the
case with a lambda (which can ALSO be in a separate context).

This patch refactors the getTemplateInstantiationArgs function in a way
that is hopefully more readable, and fixes the problem with the concepts
on a generic lambda.

Differential Revision: https://reviews.llvm.org/D134874
  • Loading branch information
Erich Keane committed Oct 3, 2022
1 parent 7919350 commit 939a3d2
Show file tree
Hide file tree
Showing 8 changed files with 307 additions and 163 deletions.
3 changes: 3 additions & 0 deletions clang/include/clang/AST/DeclBase.h
Expand Up @@ -474,6 +474,9 @@ class alignas(8) Decl {

bool isInStdNamespace() const;

// Return true if this is a FileContext Decl.
bool isFileContextDecl() const;

ASTContext &getASTContext() const LLVM_READONLY;

/// Helper to get the language options from the ASTContext.
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Sema/Sema.h
Expand Up @@ -9053,7 +9053,7 @@ class Sema final {
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
const NamedDecl *D, const TemplateArgumentList *Innermost = nullptr,
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
bool LookBeyondLambda = false, bool IncludeContainingStruct = false);
bool ForConstraintInstantiation = false);

/// A context in which code is being synthesized (where a source location
/// alone is not sufficient to identify the context). This covers template
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/DeclBase.cpp
Expand Up @@ -397,6 +397,11 @@ bool Decl::isInStdNamespace() const {
return DC && DC->isStdNamespace();
}

bool Decl::isFileContextDecl() const {
const auto *DC = dyn_cast<DeclContext>(this);
return DC && DC->isFileContext();
}

TranslationUnitDecl *Decl::getTranslationUnitDecl() {
if (auto *TUD = dyn_cast<TranslationUnitDecl>(this))
return TUD;
Expand Down
25 changes: 16 additions & 9 deletions clang/lib/Sema/SemaConcept.cpp
Expand Up @@ -505,9 +505,10 @@ Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
// Collect the list of template arguments relative to the 'primary' template.
// We need the entire list, since the constraint is completely uninstantiated
// at this point.
MLTAL = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary*/ true,
/*Pattern*/ nullptr,
/*LookBeyondLambda*/ true);
MLTAL = getTemplateInstantiationArgs(FD, /*Innermost=*/nullptr,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
return {};

Expand Down Expand Up @@ -581,9 +582,9 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
static unsigned CalculateTemplateDepthForConstraints(Sema &S,
const NamedDecl *ND) {
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
ND, nullptr, /*RelativeToPrimary*/ true,
/*Pattern*/ nullptr,
/*LookBeyondLambda*/ true, /*IncludeContainingStruct*/ true);
ND, /*Innermost=*/nullptr, /*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
return MLTAL.getNumSubstitutedLevels();
}

Expand Down Expand Up @@ -724,6 +725,12 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
Record = Method->getParent();
}
CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
FunctionScopeRAII FuncScope(*this);
if (isLambdaCallOperator(Decl))
PushLambdaScope();
else
FuncScope.disable();

llvm::SmallVector<Expr *, 1> Converted;
return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL,
PointOfInstantiation, Satisfaction);
Expand Down Expand Up @@ -1062,9 +1069,9 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
CSE->getTemplateArguments()};
MultiLevelTemplateArgumentList MLTAL =
S.getTemplateInstantiationArgs(CSE->getNamedConcept(), &TAL,
/*RelativeToPrimary*/ true,
/*Pattern*/ nullptr,
/*LookBeyondLambda*/ true);
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);

return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL,
CSE->getTemplateArgsAsWritten());
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Sema/SemaTemplate.cpp
Expand Up @@ -6103,9 +6103,9 @@ bool Sema::CheckTemplateArgumentList(
CXXThisScopeRAII(*this, RD, ThisQuals, RD != nullptr);

MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
Template, &StackTemplateArgs, /*RelativeToPrimary*/ true,
/*Pattern*/ nullptr,
/*LookBeyondLambda*/ true, /*IncludeContainingStruct*/ true);
Template, &StackTemplateArgs, /*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConceptInstantiation=*/true);
if (EnsureTemplateArgumentListConstraints(
Template, MLTAL,
SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Expand Up @@ -2876,9 +2876,9 @@ CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
TemplateArgumentList DeducedTAL{TemplateArgumentList::OnStack, DeducedArgs};

MLTAL = S.getTemplateInstantiationArgs(
Template, /*InnerMost*/ NeedsReplacement ? nullptr : &DeducedTAL,
/*RelativeToPrimary*/ true, /*Pattern*/
nullptr, /*LookBeyondLambda*/ true);
Template, /*InnerMost=*/NeedsReplacement ? nullptr : &DeducedTAL,
/*RelativeToPrimary=*/true, /*Pattern=*/
nullptr, /*ForConstraintInstantiation=*/true);

// getTemplateInstantiationArgs picks up the non-deduced version of the
// template args when this is a variable template partial specialization and
Expand Down

0 comments on commit 939a3d2

Please sign in to comment.