Skip to content

Commit a436ed4

Browse files
committed
[Clang][WIP] Normalize constraints before checking for satisfaction
In the standard, constraint satisfaction checking is done on the normalized form of a constraint. Clang instead substitute on the non-normalized form, which cause us to report substitution failures in template arguments or concept ids, which is non-conforming but unavoidable witjout a parameter mapping This patch normalizes before satisfaction checking. However, we preserve concept-id nodes in the normalized form, solely for diagnostics purposes. This is a very incomplete attempt at addressing #61811 and related concepts related conformance bugs, ideally to make the implementation of concept template parameters easier There is stil ~20 failing test files, mostly caused by poor adjustement of the template depth.
1 parent 3e1931d commit a436ed4

23 files changed

+1703
-1249
lines changed

clang/include/clang/AST/ASTConcept.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@
2727
namespace clang {
2828

2929
class ConceptDecl;
30+
class ConceptReference;
3031
class Expr;
3132
class NamedDecl;
3233
struct PrintingPolicy;
3334

3435
/// The result of a constraint satisfaction check, containing the necessary
3536
/// information to diagnose an unsatisfied constraint.
3637
class ConstraintSatisfaction : public llvm::FoldingSetNode {
38+
private:
3739
// The template-like entity that 'owns' the constraint checked here (can be a
3840
// constrained entity or a concept).
3941
const NamedDecl *ConstraintOwner = nullptr;
@@ -48,7 +50,7 @@ class ConstraintSatisfaction : public llvm::FoldingSetNode {
4850
: ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs) {}
4951

5052
using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
51-
using Detail = llvm::PointerUnion<Expr *, SubstitutionDiagnostic *>;
53+
using Detail = llvm::PointerUnion<const Expr *, SubstitutionDiagnostic *>;
5254

5355
bool IsSatisfied = false;
5456
bool ContainsErrors = false;
@@ -79,7 +81,7 @@ class ConstraintSatisfaction : public llvm::FoldingSetNode {
7981
/// substituted into them, or a diagnostic if substitution resulted in
8082
/// an invalid expression.
8183
using UnsatisfiedConstraintRecord =
82-
llvm::PointerUnion<Expr *, std::pair<SourceLocation, StringRef> *>;
84+
llvm::PointerUnion<const Expr *, std::pair<SourceLocation, StringRef> *>;
8385

8486
/// \brief The result of a constraint satisfaction check, containing the
8587
/// necessary information to diagnose an unsatisfied constraint.

clang/include/clang/AST/TemplateBase.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,6 @@ class TemplateArgument {
473473
/// Used to insert TemplateArguments into FoldingSets.
474474
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const;
475475
};
476-
477476
/// Location information for a TemplateArgument.
478477
struct TemplateArgumentLocInfo {
479478
private:

clang/include/clang/Sema/Sema.h

Lines changed: 23 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11751,7 +11751,8 @@ class Sema final : public SemaBase {
1175111751
CheckConceptTemplateId(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
1175211752
const DeclarationNameInfo &ConceptNameInfo,
1175311753
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
11754-
const TemplateArgumentListInfo *TemplateArgs);
11754+
const TemplateArgumentListInfo *TemplateArgs,
11755+
bool DoCheckConstraintSatisfaction = true);
1175511756

1175611757
void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc);
1175711758
void diagnoseMissingTemplateArguments(const CXXScopeSpec &SS,
@@ -12833,6 +12834,9 @@ class Sema final : public SemaBase {
1283312834
void MarkUsedTemplateParameters(ArrayRef<TemplateArgument> TemplateArgs,
1283412835
unsigned Depth, llvm::SmallBitVector &Used);
1283512836

12837+
void MarkUsedTemplateParameters(ArrayRef<TemplateArgumentLoc> TemplateArgs,
12838+
unsigned Depth, llvm::SmallBitVector &Used);
12839+
1283612840
void
1283712841
MarkDeducedTemplateParameters(const FunctionTemplateDecl *FunctionTemplate,
1283812842
llvm::SmallBitVector &Deduced) {
@@ -13395,6 +13399,11 @@ class Sema final : public SemaBase {
1339513399
const MultiLevelTemplateArgumentList &TemplateArgs,
1339613400
TemplateArgumentListInfo &Outputs);
1339713401

13402+
bool SubstTemplateArgumentsInParameterMapping(
13403+
ArrayRef<TemplateArgumentLoc> Args,
13404+
const MultiLevelTemplateArgumentList &TemplateArgs,
13405+
TemplateArgumentListInfo &Out);
13406+
1339813407
/// Retrieve the template argument list(s) that should be used to
1339913408
/// instantiate the definition of the given declaration.
1340013409
///
@@ -14744,6 +14753,10 @@ class Sema final : public SemaBase {
1474414753
SatisfactionStack.swap(NewSS);
1474514754
}
1474614755

14756+
using ConstrainedDeclOrNestedRequirement =
14757+
llvm::PointerUnion<const NamedDecl *,
14758+
const concepts::NestedRequirement *>;
14759+
1474714760
/// Check whether the given expression is a valid constraint expression.
1474814761
/// A diagnostic is emitted if it is not, false is returned, and
1474914762
/// PossibleNonPrimary will be set to true if the failure might be due to a
@@ -14768,44 +14781,11 @@ class Sema final : public SemaBase {
1476814781
/// \returns true if an error occurred and satisfaction could not be checked,
1476914782
/// false otherwise.
1477014783
bool CheckConstraintSatisfaction(
14771-
const NamedDecl *Template,
14784+
ConstrainedDeclOrNestedRequirement Entity,
1477214785
ArrayRef<AssociatedConstraint> AssociatedConstraints,
1477314786
const MultiLevelTemplateArgumentList &TemplateArgLists,
14774-
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
14775-
llvm::SmallVector<Expr *, 4> Converted;
14776-
return CheckConstraintSatisfaction(Template, AssociatedConstraints,
14777-
Converted, TemplateArgLists,
14778-
TemplateIDRange, Satisfaction);
14779-
}
14780-
14781-
/// \brief Check whether the given list of constraint expressions are
14782-
/// satisfied (as if in a 'conjunction') given template arguments.
14783-
/// Additionally, takes an empty list of Expressions which is populated with
14784-
/// the instantiated versions of the ConstraintExprs.
14785-
/// \param Template the template-like entity that triggered the constraints
14786-
/// check (either a concept or a constrained entity).
14787-
/// \param ConstraintExprs a list of constraint expressions, treated as if
14788-
/// they were 'AND'ed together.
14789-
/// \param ConvertedConstraints a out parameter that will get populated with
14790-
/// the instantiated version of the ConstraintExprs if we successfully checked
14791-
/// satisfaction.
14792-
/// \param TemplateArgList the multi-level list of template arguments to
14793-
/// substitute into the constraint expression. This should be relative to the
14794-
/// top-level (hence multi-level), since we need to instantiate fully at the
14795-
/// time of checking.
14796-
/// \param TemplateIDRange The source range of the template id that
14797-
/// caused the constraints check.
14798-
/// \param Satisfaction if true is returned, will contain details of the
14799-
/// satisfaction, with enough information to diagnose an unsatisfied
14800-
/// expression.
14801-
/// \returns true if an error occurred and satisfaction could not be checked,
14802-
/// false otherwise.
14803-
bool CheckConstraintSatisfaction(
14804-
const NamedDecl *Template,
14805-
ArrayRef<AssociatedConstraint> AssociatedConstraints,
14806-
llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
14807-
const MultiLevelTemplateArgumentList &TemplateArgList,
14808-
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction);
14787+
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction,
14788+
const ConceptReference *TopLevelConceptId = nullptr);
1480914789

1481014790
/// \brief Check whether the given non-dependent constraint expression is
1481114791
/// satisfied. Returns false and updates Satisfaction with the satisfaction
@@ -14871,16 +14851,16 @@ class Sema final : public SemaBase {
1487114851
/// \param First whether this is the first time an unsatisfied constraint is
1487214852
/// diagnosed for this error.
1487314853
void DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction &Satisfaction,
14854+
SourceLocation Loc = {},
1487414855
bool First = true);
1487514856

1487614857
/// \brief Emit diagnostics explaining why a constraint expression was deemed
1487714858
/// unsatisfied.
14878-
void
14879-
DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction &Satisfaction,
14880-
bool First = true);
14859+
void DiagnoseUnsatisfiedConstraint(
14860+
const ConceptSpecializationExpr *ConstraintExpr);
1488114861

1488214862
const NormalizedConstraint *getNormalizedAssociatedConstraints(
14883-
const NamedDecl *ConstrainedDecl,
14863+
ConstrainedDeclOrNestedRequirement Entity,
1488414864
ArrayRef<AssociatedConstraint> AssociatedConstraints);
1488514865

1488614866
/// \brief Check whether the given declaration's associated constraints are
@@ -14915,7 +14895,8 @@ class Sema final : public SemaBase {
1491514895
/// constrained declarations). If an error occurred while normalizing the
1491614896
/// associated constraints of the template or concept, nullptr will be cached
1491714897
/// here.
14918-
llvm::DenseMap<const NamedDecl *, NormalizedConstraint *> NormalizationCache;
14898+
llvm::DenseMap<ConstrainedDeclOrNestedRequirement, NormalizedConstraint *>
14899+
NormalizationCache;
1491914900

1492014901
llvm::ContextualFoldingSet<ConstraintSatisfaction, const ASTContext &>
1492114902
SatisfactionCache;

0 commit comments

Comments
 (0)