[libcxx-commits] [clang] [libcxx] [Clang] Normalize constraints before checking for satisfaction (PR #141776)
Erich Keane via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Sep 18 11:14:52 PDT 2025
================
@@ -16,130 +16,385 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprConcepts.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Sema/Ownership.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVector.h"
#include <optional>
#include <utility>
namespace clang {
class Sema;
+class MultiLevelTemplateArgumentList;
-enum { ConstraintAlignment = 8 };
+/// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is
+/// either an atomic constraint, a conjunction of normalized constraints or a
+/// disjunction of normalized constraints.
+struct NormalizedConstraint {
+
+ enum class ConstraintKind : unsigned char {
+ Atomic = 0,
+ ConceptId,
+ FoldExpanded,
+ Compound,
+ };
+
+ enum CompoundConstraintKind : unsigned char {
+ CCK_Conjunction,
+ CCK_Disjunction
+ };
+ enum class FoldOperatorKind : unsigned char { And, Or };
+
+ using OccurenceList = llvm::SmallBitVector;
+
+ friend bool
+ substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+ const MultiLevelTemplateArgumentList &MLTAL,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ TemplateParameterList *TemplateParams,
+ const NamedDecl *D);
+
+protected:
+ using ExprOrConcept =
+ llvm::PointerUnion<const Expr *, const ConceptReference *>;
+
+ struct AtomicConstraintBits {
+ // Kind is the first member of all union members,
+ // as we rely on their initial common sequence.
+ LLVM_PREFERRED_TYPE(ConstraintKind)
+ unsigned Kind : 5;
+ unsigned Placeholder : 1;
+ unsigned PackSubstitutionIndex : 26;
+ // Indexes and Args are part of the common initial sequences
+ // of constraints that do have a mapping.
+ OccurenceList Indexes;
+ TemplateArgumentLoc *Args;
+ TemplateParameterList *ParamList;
+ ExprOrConcept ConstraintExpr;
+ const NamedDecl *ConstraintDecl;
+ };
+
+ struct FoldExpandedConstraintBits {
+ LLVM_PREFERRED_TYPE(ConstraintKind)
+ unsigned Kind : 5;
+ LLVM_PREFERRED_TYPE(FoldOperatorKind)
+ unsigned FoldOperator : 1;
+ unsigned Placeholder : 26;
+ OccurenceList Indexes;
+ TemplateArgumentLoc *Args;
+ TemplateParameterList *ParamList;
+ const Expr *Pattern;
+ const NamedDecl *ConstraintDecl;
+ NormalizedConstraint *Constraint;
+ };
+
+ struct ConceptIdBits : AtomicConstraintBits {
+ NormalizedConstraint *Sub;
+
+ // Only used for parameter mapping.
+ const ConceptSpecializationExpr *CSE;
+ };
+
+ struct CompoundConstraintBits {
+ LLVM_PREFERRED_TYPE(ConstraintKind)
+ unsigned Kind : 5;
+ LLVM_PREFERRED_TYPE(CompoundConstraintKind)
+ unsigned CCK : 1;
+ NormalizedConstraint *LHS;
+ NormalizedConstraint *RHS;
+ };
+
+ union {
+ AtomicConstraintBits Atomic;
+ FoldExpandedConstraintBits FoldExpanded;
+ ConceptIdBits ConceptId;
+ CompoundConstraintBits Compound;
+ };
+
+ ~NormalizedConstraint() {
+ if (getKind() != ConstraintKind::Compound)
+ Atomic.Indexes.llvm::SmallBitVector::~SmallBitVector();
+ }
+
+ NormalizedConstraint(const Expr *ConstraintExpr,
+ const NamedDecl *ConstraintDecl,
+ UnsignedOrNone PackIndex)
+ : Atomic{llvm::to_underlying(ConstraintKind::Atomic),
+ /*Placeholder=*/0,
+ PackIndex.toInternalRepresentation(),
+ /*Indexes=*/{},
+ /*Args=*/nullptr,
+ /*ParamList=*/nullptr,
+ ConstraintExpr,
+ ConstraintDecl} {}
+
+ NormalizedConstraint(const Expr *Pattern, FoldOperatorKind OpKind,
+ NormalizedConstraint *Constraint,
+ const NamedDecl *ConstraintDecl)
+ : FoldExpanded{llvm::to_underlying(ConstraintKind::FoldExpanded),
+ llvm::to_underlying(OpKind),
+ /*Placeholder=*/0,
+ /*Indexes=*/{},
+ /*Args=*/nullptr,
+ /*ParamList=*/nullptr,
+ Pattern,
+ ConstraintDecl,
+ Constraint} {}
+
+ NormalizedConstraint(const ConceptReference *ConceptId,
+ const NamedDecl *ConstraintDecl,
+ NormalizedConstraint *SubConstraint,
+ const ConceptSpecializationExpr *CSE,
+ UnsignedOrNone PackIndex)
+ : ConceptId{{llvm::to_underlying(ConstraintKind::ConceptId),
+ /*Placeholder=*/0, PackIndex.toInternalRepresentation(),
+ /*Indexes=*/{},
+ /*Args=*/nullptr, /*ParamList=*/nullptr, ConceptId,
+ ConstraintDecl},
+ SubConstraint,
+ CSE} {}
+
+ NormalizedConstraint(NormalizedConstraint *LHS, CompoundConstraintKind CCK,
+ NormalizedConstraint *RHS)
+ : Compound{llvm::to_underlying(ConstraintKind::Compound),
+ llvm::to_underlying(CCK), LHS, RHS} {}
+
+ bool hasParameterMapping() const {
+ // compound constraints do not have a mapping
+ // and Args is not part of their common initial sequence.
+ return getKind() != ConstraintKind::Compound && Atomic.Args != nullptr;
+ }
-struct alignas(ConstraintAlignment) AtomicConstraint {
- const Expr *ConstraintExpr;
- const NamedDecl *ConstraintDecl;
- std::optional<ArrayRef<TemplateArgumentLoc>> ParameterMapping;
+ const OccurenceList &mappingOccurenceList() const {
+ assert(hasParameterMapping() && "This constraint has no parameter mapping");
+ return Atomic.Indexes;
----------------
erichkeane wrote:
Not there yet, but exposing the `OccurenceList` outside of this type seems like a mistake. Can we instead have this interface let you 'ask' the questions you mean?
https://github.com/llvm/llvm-project/pull/141776
More information about the libcxx-commits
mailing list