diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index edd441beba4444..657fc85a5d216e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14524,7 +14524,8 @@ class Sema final : public SemaBase { bool First = true); const NormalizedConstraint *getNormalizedAssociatedConstraints(NamedDecl *ConstrainedDecl, - ArrayRef AssociatedConstraints); + ArrayRef 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 @@ -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 NormalizationCache; - + std::map, NormalizedConstraint *> NormalizationCache; llvm::ContextualFoldingSet SatisfactionCache; diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h index 801f3dbc1ab78f..6ef94fb0b73cdc 100644 --- a/clang/include/clang/Sema/SemaConcept.h +++ b/clang/include/clang/Sema/SemaConcept.h @@ -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" @@ -178,11 +179,11 @@ struct NormalizedConstraint { private: static std::optional - fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef E); + fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef E, const ConceptSpecializationExpr* CSE = nullptr); static std::optional - fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E); + fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E, const ConceptSpecializationExpr* CSE = nullptr); static std::optional - BuildConceptDependentConstraint(Sema &S, NamedDecl *D, const UnresolvedLookupExpr *E); + BuildConceptDependentConstraint(Sema &S, NamedDecl *D, const UnresolvedLookupExpr *E, const ConceptSpecializationExpr *CSE); }; struct alignas(ConstraintAlignment) NormalizedConstraintPair { diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index e5f582c7e4c96a..41dbbaf6f86976 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -1430,20 +1430,43 @@ void Sema::DiagnoseUnsatisfiedConstraint( const NormalizedConstraint * Sema::getNormalizedAssociatedConstraints( - NamedDecl *ConstrainedDecl, ArrayRef AssociatedConstraints) { + NamedDecl *ConstrainedDecl, ArrayRef 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(ConstrainedDecl->getCanonicalDecl()); - auto CacheEntry = NormalizationCache.find(ConstrainedDecl); + llvm::SmallVector Key = {ConstrainedDecl}; + + auto AddTemplateArgument = [&](const TemplateArgument &Arg) { + if (Arg.getKind() == TemplateArgument::Template) { + TemplateName TN = Arg.getAsTemplate(); + if (isa(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)) @@ -1481,6 +1504,10 @@ substituteParameterMappings(Sema &S, NormalizedConstraint &N, ArgsAsWritten); } + if(N.isConceptDependent()) { + return false; + } + TemplateParameterList *TemplateParams = Concept->getTemplateParameters(); AtomicConstraint &Atomic = *N.getAtomicConstraint(); @@ -1589,13 +1616,13 @@ NormalizedConstraint &NormalizedConstraint::getRHS() const { std::optional NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D, - ArrayRef E) { + ArrayRef 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), @@ -1605,16 +1632,24 @@ NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D, } std::optional -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(D)); + Sema::ContextRAII SavedContext(S, D->getDeclContext()); LocalInstantiationScope Scope(S); + std::optional> 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(D)) S.SetupConstraintScope(FD, {}, MLTAL, Scope); @@ -1642,7 +1677,8 @@ NormalizedConstraint::BuildConceptDependentConstraint(Sema &S, NamedDecl *D, con } std::optional -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 @@ -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(E)) { + } else if (auto *ConceptE = dyn_cast(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 @@ -1684,9 +1720,10 @@ 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; } @@ -1694,7 +1731,7 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { std::optional New; New.emplace(S.Context, *SubNF); - if (substituteParameterMappings(S, *New, CSE)) + if (substituteParameterMappings(S, *New, ConceptE)) return std::nullopt; return New; @@ -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; @@ -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(E); ULE && ULE->isConceptReference()) { - return BuildConceptDependentConstraint(S, D, ULE); + return BuildConceptDependentConstraint(S, D, ULE, CSE); } return NormalizedConstraint{new (S.Context) AtomicConstraint(E, D)}; diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 30fb6e0e3734be..18ff74df56d373 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -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"