Skip to content

Commit

Permalink
subsumption for concept template arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
cor3ntin committed Oct 6, 2024
1 parent 9053226 commit 793a862
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 29 deletions.
6 changes: 3 additions & 3 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -14524,7 +14524,8 @@ class Sema final : public SemaBase {
bool First = true);

const NormalizedConstraint *getNormalizedAssociatedConstraints(NamedDecl *ConstrainedDecl,
ArrayRef<const Expr *> AssociatedConstraints);
ArrayRef<const Expr *> AssociatedConstraints,
const ConceptSpecializationExpr *CSE = nullptr);

/// \brief Check whether the given declaration's associated constraints are
/// at least as constrained than another declaration's according to the
Expand Down Expand Up @@ -14555,8 +14556,7 @@ class Sema final : public SemaBase {
/// constrained declarations). If an error occurred while normalizing the
/// associated constraints of the template or concept, nullptr will be cached
/// here.
llvm::DenseMap<NamedDecl *, NormalizedConstraint *> NormalizationCache;

std::map<llvm::SmallVector<void *, 1>, NormalizedConstraint *> NormalizationCache;
llvm::ContextualFoldingSet<ConstraintSatisfaction, const ASTContext &>
SatisfactionCache;

Expand Down
7 changes: 4 additions & 3 deletions clang/include/clang/Sema/SemaConcept.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
Expand Down Expand Up @@ -178,11 +179,11 @@ struct NormalizedConstraint {

private:
static std::optional<NormalizedConstraint>
fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef<const Expr *> E);
fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef<const Expr *> E, const ConceptSpecializationExpr* CSE = nullptr);
static std::optional<NormalizedConstraint>
fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E);
fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E, const ConceptSpecializationExpr* CSE = nullptr);
static std::optional<NormalizedConstraint>
BuildConceptDependentConstraint(Sema &S, NamedDecl *D, const UnresolvedLookupExpr *E);
BuildConceptDependentConstraint(Sema &S, NamedDecl *D, const UnresolvedLookupExpr *E, const ConceptSpecializationExpr *CSE);
};

struct alignas(ConstraintAlignment) NormalizedConstraintPair {
Expand Down
83 changes: 60 additions & 23 deletions clang/lib/Sema/SemaConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1430,20 +1430,43 @@ void Sema::DiagnoseUnsatisfiedConstraint(

const NormalizedConstraint *
Sema::getNormalizedAssociatedConstraints(
NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints) {
NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints,
const ConceptSpecializationExpr* CSE) {
// In case the ConstrainedDecl comes from modules, it is necessary to use
// the canonical decl to avoid different atomic constraints with the 'same'
// declarations.
ConstrainedDecl = cast<NamedDecl>(ConstrainedDecl->getCanonicalDecl());

auto CacheEntry = NormalizationCache.find(ConstrainedDecl);
llvm::SmallVector<void *, 1> Key = {ConstrainedDecl};

auto AddTemplateArgument = [&](const TemplateArgument &Arg) {
if (Arg.getKind() == TemplateArgument::Template) {
TemplateName TN = Arg.getAsTemplate();
if (isa<ConceptDecl>(TN.getAsTemplateDecl()))
Key.push_back((void *)&Arg);
}
};

if (CSE) {
for (auto &&Arg : CSE->getTemplateArguments()) {
if (Arg.getKind() == TemplateArgument::Template)
AddTemplateArgument(Arg);
else if (Arg.getKind() == TemplateArgument::Pack) {
for (auto &PArg : Arg.pack_elements())
AddTemplateArgument(PArg);
}
}
}


auto CacheEntry = NormalizationCache.find(Key);
if (CacheEntry == NormalizationCache.end()) {
auto Normalized =
NormalizedConstraint::fromConstraintExprs(*this, ConstrainedDecl,
AssociatedConstraints);
AssociatedConstraints, CSE);
CacheEntry =
NormalizationCache
.try_emplace(ConstrainedDecl,
.try_emplace(Key,
Normalized
? new (Context) NormalizedConstraint(
std::move(*Normalized))
Expand Down Expand Up @@ -1481,6 +1504,10 @@ substituteParameterMappings(Sema &S, NormalizedConstraint &N,
ArgsAsWritten);
}

if(N.isConceptDependent()) {
return false;
}

TemplateParameterList *TemplateParams = Concept->getTemplateParameters();

AtomicConstraint &Atomic = *N.getAtomicConstraint();
Expand Down Expand Up @@ -1589,13 +1616,13 @@ NormalizedConstraint &NormalizedConstraint::getRHS() const {

std::optional<NormalizedConstraint>
NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D,
ArrayRef<const Expr *> E) {
ArrayRef<const Expr *> E, const ConceptSpecializationExpr *CSE) {
assert(E.size() != 0);
auto Conjunction = fromConstraintExpr(S, D, E[0]);
auto Conjunction = fromConstraintExpr(S, D, E[0], CSE);
if (!Conjunction)
return std::nullopt;
for (unsigned I = 1; I < E.size(); ++I) {
auto Next = fromConstraintExpr(S, D, E[I]);
auto Next = fromConstraintExpr(S, D, E[I], CSE);
if (!Next)
return std::nullopt;
*Conjunction = NormalizedConstraint(S.Context, std::move(*Conjunction),
Expand All @@ -1605,16 +1632,24 @@ NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D,
}

std::optional<NormalizedConstraint>
NormalizedConstraint::BuildConceptDependentConstraint(Sema &S, NamedDecl *D, const UnresolvedLookupExpr *E) {
NormalizedConstraint::BuildConceptDependentConstraint(Sema &S, NamedDecl *D,
const UnresolvedLookupExpr *E,
const ConceptSpecializationExpr *CSE) {

Sema::ContextRAII savedContext(S, cast<FunctionDecl>(D));
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=*/std::nullopt,
/*Final=*/false, /*Innermost=*/InnerMostArgs,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);

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

Expand Down Expand Up @@ -1642,7 +1677,8 @@ NormalizedConstraint::BuildConceptDependentConstraint(Sema &S, NamedDecl *D, con
}

std::optional<NormalizedConstraint>
NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E,
const ConceptSpecializationExpr *CSE) {
assert(E != nullptr);

// C++ [temp.constr.normal]p1.1
Expand All @@ -1657,22 +1693,22 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
// See http://cplusplus.github.io/concepts-ts/ts-active.html#28

if (LogicalBinOp BO = E) {
auto LHS = fromConstraintExpr(S, D, BO.getLHS());
auto LHS = fromConstraintExpr(S, D, BO.getLHS(), CSE);
if (!LHS)
return std::nullopt;
auto RHS = fromConstraintExpr(S, D, BO.getRHS());
auto RHS = fromConstraintExpr(S, D, BO.getRHS(), CSE);
if (!RHS)
return std::nullopt;

return NormalizedConstraint(S.Context, std::move(*LHS), std::move(*RHS),
BO.isAnd() ? CCK_Conjunction : CCK_Disjunction);
} else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) {
} else if (auto *ConceptE = dyn_cast<const ConceptSpecializationExpr>(E)) {
const NormalizedConstraint *SubNF;
{
Sema::InstantiatingTemplate Inst(
S, CSE->getExprLoc(),
S, ConceptE->getExprLoc(),
Sema::InstantiatingTemplate::ConstraintNormalization{}, D,
CSE->getSourceRange());
ConceptE->getSourceRange());
if (Inst.isInvalid())
return std::nullopt;
// C++ [temp.constr.normal]p1.1
Expand All @@ -1684,17 +1720,18 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
// constraint. If any such substitution results in an invalid type or
// expression, the program is ill-formed; no diagnostic is required.
// [...]
ConceptDecl *CD = CSE->getNamedConcept();
ConceptDecl *CD = ConceptE->getNamedConcept();
ConceptE->getTemplateArgsAsWritten();
SubNF = S.getNormalizedAssociatedConstraints(CD,
{CD->getConstraintExpr()});
{CD->getConstraintExpr()}, ConceptE);
if (!SubNF)
return std::nullopt;
}

std::optional<NormalizedConstraint> New;
New.emplace(S.Context, *SubNF);

if (substituteParameterMappings(S, *New, CSE))
if (substituteParameterMappings(S, *New, ConceptE))
return std::nullopt;

return New;
Expand All @@ -1711,8 +1748,8 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
: FoldExpandedConstraint::FoldOperatorKind::Or;

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

Expand All @@ -1728,13 +1765,13 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
FE->getOperator() == BinaryOperatorKind::BO_LAnd ? CCK_Conjunction
: CCK_Disjunction);
}
auto Sub = fromConstraintExpr(S, D, FE->getPattern());
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()}};
} else if (auto* ULE = dyn_cast<UnresolvedLookupExpr>(E); ULE && ULE->isConceptReference()) {
return BuildConceptDependentConstraint(S, D, ULE);
return BuildConceptDependentConstraint(S, D, ULE, CSE);
}

return NormalizedConstraint{new (S.Context) AtomicConstraint(E, D)};
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
Expand Down

0 comments on commit 793a862

Please sign in to comment.