Skip to content

Commit

Permalink
subsumption for concept template arguments packs
Browse files Browse the repository at this point in the history
  • Loading branch information
cor3ntin committed Oct 7, 2024
1 parent 793a862 commit 2d34163
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 39 deletions.
5 changes: 5 additions & 0 deletions clang/include/clang/Sema/SemaConcept.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,9 @@ struct NormalizedConstraint {
fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E, const ConceptSpecializationExpr* CSE = nullptr);
static std::optional<NormalizedConstraint>
BuildConceptDependentConstraint(Sema &S, NamedDecl *D, const UnresolvedLookupExpr *E, const ConceptSpecializationExpr *CSE);
static std::optional<unsigned> ConceptTemplateParameterExpansionCount(Sema &S, NamedDecl *D,
const Expr *E,
const ConceptSpecializationExpr *CSE);
};

struct alignas(ConstraintAlignment) NormalizedConstraintPair {
Expand Down Expand Up @@ -301,6 +304,8 @@ bool FoldExpandedConstraint::subsumes(
return clang::subsumes(PDNF, QCNF, E);
}

bool ConstraintHasConceptTemplateParameterConceptReference(const Expr* E);

} // clang

#endif // LLVM_CLANG_SEMA_SEMACONCEPT_H
115 changes: 95 additions & 20 deletions clang/lib/Sema/SemaConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/RecursiveASTVisitor.h"
Expand All @@ -32,6 +34,7 @@
#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
#include <optional>
Expand Down Expand Up @@ -1631,6 +1634,23 @@ NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D,
return Conjunction;
}

bool clang::ConstraintHasConceptTemplateParameterConceptReference(const Expr* E) {
if(auto* ULE = dyn_cast<UnresolvedLookupExpr>(E); ULE && ULE->isConceptReference())
return true;
if(auto* P = dyn_cast<ParenExpr>(E))
return ConstraintHasConceptTemplateParameterConceptReference(P->getSubExpr());
if(auto* B = dyn_cast<BinaryOperator>(E); B && llvm::is_contained({BO_And, BO_Or}, B->getOpcode()))
return ConstraintHasConceptTemplateParameterConceptReference(B->getLHS()) ||
ConstraintHasConceptTemplateParameterConceptReference(B->getRHS());
if(auto* FE = dyn_cast<CXXFoldExpr>(E); FE && llvm::is_contained({BO_And, BO_Or}, FE->getOperator())) {
if(FE->getInit() && ConstraintHasConceptTemplateParameterConceptReference(FE->getInit()))
return true;
return ConstraintHasConceptTemplateParameterConceptReference(FE->getPattern());
}
return false;
}


std::optional<NormalizedConstraint>
NormalizedConstraint::BuildConceptDependentConstraint(Sema &S, NamedDecl *D,
const UnresolvedLookupExpr *E,
Expand Down Expand Up @@ -1676,6 +1696,44 @@ NormalizedConstraint::BuildConceptDependentConstraint(Sema &S, NamedDecl *D,

}

std::optional<unsigned> NormalizedConstraint::ConceptTemplateParameterExpansionCount(Sema &S, NamedDecl *D,
const Expr *E,
const ConceptSpecializationExpr *CSE) {
llvm::SmallVector<UnexpandedParameterPack> Unexpanded;
S.collectUnexpandedParameterPacks(const_cast<Expr*>(E), Unexpanded);
bool ExpandConceptTemplateParameter = false;
for(const UnexpandedParameterPack & P : Unexpanded) {
if(NamedDecl *ND = P.first.dyn_cast<NamedDecl *>()) {
if(const auto* TTP = dyn_cast<TemplateTemplateParmDecl>(ND); TTP && TTP->kind() == TNK_Concept_template) {
ExpandConceptTemplateParameter = true;
break;
}
}
}

if(!ExpandConceptTemplateParameter)
return std::nullopt;

Sema::ContextRAII SavedContext(S, D->getDeclContext());
LocalInstantiationScope Scope(S);

std::optional<ArrayRef<TemplateArgument>> InnerMostArgs;
if(CSE) {
InnerMostArgs = CSE->getTemplateArguments();
}

MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(D, D->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/InnerMostArgs,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);

if(FunctionDecl* FD = dyn_cast<FunctionDecl>(D))
S.SetupConstraintScope(FD, {}, MLTAL, Scope);

return S.getNumArgumentsInExpansionFromUnexpanded(Unexpanded, MLTAL);
}

std::optional<NormalizedConstraint>
NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E,
const ConceptSpecializationExpr *CSE) {
Expand Down Expand Up @@ -1747,29 +1805,46 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E,
? FoldExpandedConstraint::FoldOperatorKind::And
: FoldExpandedConstraint::FoldOperatorKind::Or;

if (FE->getInit()) {
auto LHS = fromConstraintExpr(S, D, FE->getLHS(), CSE);
auto RHS = fromConstraintExpr(S, D, FE->getRHS(), CSE);
if (!LHS || !RHS)
std::optional<NormalizedConstraint> NormalizedPattern;

if(std::optional<unsigned> Expansions
= NormalizedConstraint::ConceptTemplateParameterExpansionCount(S, D, FE->getPattern(), CSE)) {
for(unsigned I = 0; I < *Expansions; I++) {
Sema::ArgumentPackSubstitutionIndexRAII _(S, I);
std::optional<NormalizedConstraint> New = NormalizedConstraint::fromConstraintExpr(S, D, FE->getPattern(), CSE);
if(!New)
return std::nullopt;
if(!NormalizedPattern)
NormalizedPattern = std::move(New);
else
NormalizedPattern = NormalizedConstraint(
S.Context, std::move(*NormalizedPattern), std::move(*New),
FE->getOperator() == BinaryOperatorKind::BO_LAnd ? CCK_Conjunction
: CCK_Disjunction);
}
}
else {
NormalizedPattern = NormalizedConstraint::fromConstraintExpr(S, D, FE->getPattern(), CSE);
if(!NormalizedPattern)
return std::nullopt;
NormalizedPattern = NormalizedConstraint{new (S.Context) FoldExpandedConstraint{
Kind, std::move(*NormalizedPattern), FE->getPattern()}};
}

if (FE->isRightFold())
RHS = NormalizedConstraint{new (S.Context) FoldExpandedConstraint{
Kind, std::move(*RHS), FE->getPattern()}};
else
LHS = NormalizedConstraint{new (S.Context) FoldExpandedConstraint{
Kind, std::move(*LHS), FE->getPattern()}};
if(!FE->getInit())
return NormalizedPattern;

return NormalizedConstraint(
S.Context, std::move(*LHS), std::move(*RHS),
FE->getOperator() == BinaryOperatorKind::BO_LAnd ? CCK_Conjunction
: CCK_Disjunction);
}
auto Sub = fromConstraintExpr(S, D, FE->getPattern(), CSE);
if (!Sub)
return std::nullopt;
return NormalizedConstraint{new (S.Context) FoldExpandedConstraint{
Kind, std::move(*Sub), FE->getPattern()}};
std::optional<NormalizedConstraint> NormalizedInit = fromConstraintExpr(S, D, FE->getInit(), CSE);
if(!NormalizedInit)
return std::nullopt;

auto RHS = std::move(FE->isRightFold() ? NormalizedPattern : NormalizedInit);
auto LHS = std::move(FE->isLeftFold() ? NormalizedPattern : NormalizedInit);

return NormalizedConstraint(
S.Context, std::move(*LHS), std::move(*RHS),
FE->getOperator() == BinaryOperatorKind::BO_LAnd ? CCK_Conjunction
: CCK_Disjunction);
} else if (auto* ULE = dyn_cast<UnresolvedLookupExpr>(E); ULE && ULE->isConceptReference()) {
return BuildConceptDependentConstraint(S, D, ULE, CSE);
}
Expand Down
20 changes: 2 additions & 18 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6152,22 +6152,6 @@ UnresolvedSetIterator Sema::getMostSpecialized(
return SpecEnd;
}

static bool ConstraintHasConceptTemplateParameterConceptReference(const Expr* E) {
if(auto* ULE = dyn_cast<UnresolvedLookupExpr>(E); ULE && ULE->isConceptReference())
return true;
if(auto* P = dyn_cast<ParenExpr>(E))
return ConstraintHasConceptTemplateParameterConceptReference(P->getSubExpr());
if(auto* B = dyn_cast<BinaryOperator>(E); B && llvm::is_contained({BO_And, BO_Or}, B->getOpcode()))
return ConstraintHasConceptTemplateParameterConceptReference(B->getLHS()) ||
ConstraintHasConceptTemplateParameterConceptReference(B->getRHS());
if(auto* FE = dyn_cast<CXXFoldExpr>(E); FE && llvm::is_contained({BO_And, BO_Or}, FE->getOperator())) {
if(FE->getInit() && ConstraintHasConceptTemplateParameterConceptReference(FE->getInit()))
return true;
return ConstraintHasConceptTemplateParameterConceptReference(FE->getPattern());
}
return false;
}

FunctionDecl *Sema::getMoreConstrainedFunction(FunctionDecl *FD1,
FunctionDecl *FD2) {
assert(!FD1->getDescribedTemplate() && !FD2->getDescribedTemplate() &&
Expand All @@ -6178,13 +6162,13 @@ FunctionDecl *Sema::getMoreConstrainedFunction(FunctionDecl *FD1,
isa<CXXConversionDecl>(FD2));

FunctionDecl *F1 = FD1;
if(!F1->getTrailingRequiresClause() || !ConstraintHasConceptTemplateParameterConceptReference(F1->getTrailingRequiresClause())) {
if(!F1->getTrailingRequiresClause() || !clang::ConstraintHasConceptTemplateParameterConceptReference(F1->getTrailingRequiresClause())) {
if (FunctionDecl *P = FD1->getTemplateInstantiationPattern(false))
F1 = P;
}

FunctionDecl *F2 = FD2;
if(!F2->getTrailingRequiresClause() || !ConstraintHasConceptTemplateParameterConceptReference(F2->getTrailingRequiresClause())) {
if(!F2->getTrailingRequiresClause() || !clang::ConstraintHasConceptTemplateParameterConceptReference(F2->getTrailingRequiresClause())) {
if (FunctionDecl *P = FD2->getTemplateInstantiationPattern(false))
F2 = P;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/SemaCXX/cxx2c-template-template-param.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -std=c++2b -verify %s
// RUN: %clang_cc1 -std=c++2c -verify %s

namespace Errors {

Expand Down

0 comments on commit 2d34163

Please sign in to comment.