[clang] ad1ca5f - [clang] Concepts: support pack expansions for type constraints (#132626)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 1 17:12:00 PDT 2025
Author: Matheus Izvekov
Date: 2025-04-01T21:11:56-03:00
New Revision: ad1ca5f4a2bc09f99fd82e5444f5da37c2985e97
URL: https://github.com/llvm/llvm-project/commit/ad1ca5f4a2bc09f99fd82e5444f5da37c2985e97
DIFF: https://github.com/llvm/llvm-project/commit/ad1ca5f4a2bc09f99fd82e5444f5da37c2985e97.diff
LOG: [clang] Concepts: support pack expansions for type constraints (#132626)
This reverts an earlier attempt
(adb0d8ddceb143749c519d14b8b31b481071da77 and
50e5411e4247421fd606f0a206682fcdf0303ae3) to support these expansions,
which was limited to type arguments and which subverted the purpose
of SubstTemplateTypeParmType.
This propagates the ArgumentPackSubstitutionIndex along with the
AssociatedConstraint, so that the pack expansion works, without
needing any new transforms or otherwise any changes to the template
instantiation process.
This keeps the tests from the reverted commits, and adds a few more
showing the new solution also works for NTTPs.
Fixes https://github.com/llvm/llvm-project/issues/131798
Added:
Modified:
clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/ASTConcept.h
clang/include/clang/AST/ASTContext.h
clang/include/clang/AST/Decl.h
clang/include/clang/AST/DeclTemplate.h
clang/include/clang/AST/PropertiesBase.td
clang/include/clang/AST/Type.h
clang/include/clang/AST/TypeProperties.td
clang/include/clang/Sema/Sema.h
clang/include/clang/Sema/SemaConcept.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/DeclTemplate.cpp
clang/lib/AST/Type.cpp
clang/lib/Sema/SemaCodeComplete.cpp
clang/lib/Sema/SemaConcept.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaOverload.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/SemaType.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
clang/test/SemaCXX/fold_lambda_with_variadics.cpp
clang/unittests/AST/SourceLocationTest.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp
index ea4d99586c711..fb82efb4dd211 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp
@@ -356,7 +356,7 @@ static std::vector<FixItHint> handleReturnType(const FunctionDecl *Function,
if (!TypeText)
return {};
- SmallVector<const Expr *, 3> ExistingConstraints;
+ SmallVector<AssociatedConstraint, 3> ExistingConstraints;
Function->getAssociatedConstraints(ExistingConstraints);
if (!ExistingConstraints.empty()) {
// FIXME - Support adding new constraints to existing ones. Do we need to
@@ -404,7 +404,7 @@ handleTrailingTemplateType(const FunctionTemplateDecl *FunctionTemplate,
if (!ConditionText)
return {};
- SmallVector<const Expr *, 3> ExistingConstraints;
+ SmallVector<AssociatedConstraint, 3> ExistingConstraints;
Function->getAssociatedConstraints(ExistingConstraints);
if (!ExistingConstraints.empty()) {
// FIXME - Support adding new constraints to existing ones. Do we need to
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index c3b64d84a1b1c..c4e82678949ff 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -370,6 +370,9 @@ Bug Fixes to C++ Support
- Clang now uses the parameter location for abbreviated function templates in ``extern "C"``. (#GH46386)
- Clang will emit an error instead of crash when use co_await or co_yield in
C++26 braced-init-list template parameter initialization. (#GH78426)
+- Improved fix for an issue with pack expansions of type constraints, where this
+ now also works if the constraint has non-type or template template parameters.
+ (#GH131798)
- Fixes matching of nested template template parameters. (#GH130362)
- Correctly diagnoses template template paramters which have a pack parameter
not in the last position.
diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h
index 00500e214f4ce..f89899c3ea7b1 100644
--- a/clang/include/clang/AST/ASTConcept.h
+++ b/clang/include/clang/AST/ASTConcept.h
@@ -229,12 +229,15 @@ class TypeConstraint {
/// type-constraint.
Expr *ImmediatelyDeclaredConstraint = nullptr;
ConceptReference *ConceptRef;
+ int ArgumentPackSubstitutionIndex;
public:
TypeConstraint(ConceptReference *ConceptRef,
- Expr *ImmediatelyDeclaredConstraint)
+ Expr *ImmediatelyDeclaredConstraint,
+ int ArgumentPackSubstitutionIndex)
: ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint),
- ConceptRef(ConceptRef) {}
+ ConceptRef(ConceptRef),
+ ArgumentPackSubstitutionIndex(ArgumentPackSubstitutionIndex) {}
/// \brief Get the immediately-declared constraint expression introduced by
/// this type-constraint, that is - the constraint expression that is added to
@@ -245,6 +248,10 @@ class TypeConstraint {
ConceptReference *getConceptReference() const { return ConceptRef; }
+ int getArgumentPackSubstitutionIndex() const {
+ return ArgumentPackSubstitutionIndex;
+ }
+
// FIXME: Instead of using these concept related functions the callers should
// directly work with the corresponding ConceptReference.
ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); }
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index f386282890b5a..a24f30815e6b9 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1798,9 +1798,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType
getSubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl,
unsigned Index,
- std::optional<unsigned> PackIndex,
- SubstTemplateTypeParmTypeFlag Flag =
- SubstTemplateTypeParmTypeFlag::None) const;
+ std::optional<unsigned> PackIndex) const;
QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
unsigned Index, bool Final,
const TemplateArgument &ArgPack);
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index efac36e49351e..9e7e93d98c9d1 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -78,6 +78,18 @@ class UnresolvedSetImpl;
class VarTemplateDecl;
enum class ImplicitParamKind;
+// Holds a constraint expression along with a pack expansion index, if
+// expanded.
+struct AssociatedConstraint {
+ const Expr *ConstraintExpr;
+ int ArgumentPackSubstitutionIndex;
+
+ explicit AssociatedConstraint(const Expr *ConstraintExpr,
+ int ArgumentPackSubstitutionIndex = -1)
+ : ConstraintExpr(ConstraintExpr),
+ ArgumentPackSubstitutionIndex(ArgumentPackSubstitutionIndex) {}
+};
+
/// The top declaration context.
class TranslationUnitDecl : public Decl,
public DeclContext,
@@ -2631,9 +2643,10 @@ class FunctionDecl : public DeclaratorDecl,
///
/// Use this instead of getTrailingRequiresClause for concepts APIs that
/// accept an ArrayRef of constraint expressions.
- void getAssociatedConstraints(SmallVectorImpl<const Expr *> &AC) const {
+ void
+ getAssociatedConstraints(SmallVectorImpl<AssociatedConstraint> &AC) const {
if (auto *TRC = getTrailingRequiresClause())
- AC.push_back(TRC);
+ AC.emplace_back(TRC);
}
/// Get the message that indicates why this function was deleted.
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index b27e698236c02..37fe0acf5d4d5 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -195,7 +195,8 @@ class TemplateParameterList final
///
/// The constraints in the resulting list are to be treated as if in a
/// conjunction ("and").
- void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const;
+ void getAssociatedConstraints(
+ llvm::SmallVectorImpl<AssociatedConstraint> &AC) const;
bool hasAssociatedConstraints() const;
@@ -422,7 +423,8 @@ class TemplateDecl : public NamedDecl {
/// including constraint-expressions derived from the requires-clause,
/// trailing requires-clause (for functions and methods) and constrained
/// template parameters.
- void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const;
+ void getAssociatedConstraints(
+ llvm::SmallVectorImpl<AssociatedConstraint> &AC) const;
bool hasAssociatedConstraints() const;
@@ -1341,7 +1343,8 @@ class TemplateTypeParmDecl final : public TypeDecl,
}
void setTypeConstraint(ConceptReference *CR,
- Expr *ImmediatelyDeclaredConstraint);
+ Expr *ImmediatelyDeclaredConstraint,
+ int ArgumentPackSubstitutionIndex);
/// Determine whether this template parameter has a type-constraint.
bool hasTypeConstraint() const {
@@ -1353,9 +1356,11 @@ class TemplateTypeParmDecl final : public TypeDecl,
///
/// Use this instead of getTypeConstraint for concepts APIs that
/// accept an ArrayRef of constraint expressions.
- void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
+ void getAssociatedConstraints(
+ llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
if (HasTypeConstraint)
- AC.push_back(getTypeConstraint()->getImmediatelyDeclaredConstraint());
+ AC.emplace_back(getTypeConstraint()->getImmediatelyDeclaredConstraint(),
+ getTypeConstraint()->getArgumentPackSubstitutionIndex());
}
SourceRange getSourceRange() const override LLVM_READONLY;
@@ -1574,9 +1579,10 @@ class NonTypeTemplateParmDecl final
///
/// Use this instead of getPlaceholderImmediatelyDeclaredConstraint for
/// concepts APIs that accept an ArrayRef of constraint expressions.
- void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
+ void getAssociatedConstraints(
+ llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
if (Expr *E = getPlaceholderTypeConstraint())
- AC.push_back(E);
+ AC.emplace_back(E);
}
// Implement isa/cast/dyncast/etc.
@@ -2169,7 +2175,8 @@ class ClassTemplatePartialSpecializationDecl
///
/// The constraints in the resulting list are to be treated as if in a
/// conjunction ("and").
- void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
+ void getAssociatedConstraints(
+ llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
TemplateParams->getAssociatedConstraints(AC);
}
@@ -2943,7 +2950,8 @@ class VarTemplatePartialSpecializationDecl
///
/// The constraints in the resulting list are to be treated as if in a
/// conjunction ("and").
- void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
+ void getAssociatedConstraints(
+ llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
TemplateParams->getAssociatedConstraints(AC);
}
diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td
index 178308a24e1a0..5171555008ac9 100644
--- a/clang/include/clang/AST/PropertiesBase.td
+++ b/clang/include/clang/AST/PropertiesBase.td
@@ -137,7 +137,6 @@ def Selector : PropertyType;
def SourceLocation : PropertyType;
def StmtRef : RefPropertyType<"Stmt"> { let ConstWhenWriting = 1; }
def ExprRef : SubclassPropertyType<"Expr", StmtRef>;
-def SubstTemplateTypeParmTypeFlag : EnumPropertyType;
def TemplateArgument : PropertyType;
def TemplateArgumentKind : EnumPropertyType<"TemplateArgument::ArgKind">;
def TemplateName : DefaultValuePropertyType;
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 988362787a452..cfd417068abb7 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1786,15 +1786,6 @@ enum class AutoTypeKeyword {
GNUAutoType
};
-enum class SubstTemplateTypeParmTypeFlag {
- None,
-
- /// Whether to expand the pack using the stored PackIndex in place. This is
- /// useful for e.g. substituting into an atomic constraint expression, where
- /// that expression is part of an unexpanded pack.
- ExpandPacksInPlace,
-};
-
enum class ArraySizeModifier;
enum class ElaboratedTypeKeyword;
enum class VectorKind;
@@ -2164,9 +2155,6 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
LLVM_PREFERRED_TYPE(bool)
unsigned HasNonCanonicalUnderlyingType : 1;
- LLVM_PREFERRED_TYPE(SubstTemplateTypeParmTypeFlag)
- unsigned SubstitutionFlag : 1;
-
// The index of the template parameter this substitution represents.
unsigned Index : 15;
@@ -6409,8 +6397,7 @@ class SubstTemplateTypeParmType final
Decl *AssociatedDecl;
SubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl,
- unsigned Index, std::optional<unsigned> PackIndex,
- SubstTemplateTypeParmTypeFlag Flag);
+ unsigned Index, std::optional<unsigned> PackIndex);
public:
/// Gets the type that was substituted for the template
@@ -6439,31 +6426,21 @@ class SubstTemplateTypeParmType final
return SubstTemplateTypeParmTypeBits.PackIndex - 1;
}
- SubstTemplateTypeParmTypeFlag getSubstitutionFlag() const {
- return static_cast<SubstTemplateTypeParmTypeFlag>(
- SubstTemplateTypeParmTypeBits.SubstitutionFlag);
- }
-
bool isSugared() const { return true; }
QualType desugar() const { return getReplacementType(); }
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getReplacementType(), getAssociatedDecl(), getIndex(),
- getPackIndex(), getSubstitutionFlag());
+ getPackIndex());
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement,
const Decl *AssociatedDecl, unsigned Index,
- std::optional<unsigned> PackIndex,
- SubstTemplateTypeParmTypeFlag Flag) {
+ std::optional<unsigned> PackIndex) {
Replacement.Profile(ID);
ID.AddPointer(AssociatedDecl);
ID.AddInteger(Index);
ID.AddInteger(PackIndex ? *PackIndex - 1 : 0);
- ID.AddInteger(llvm::to_underlying(Flag));
- assert((Flag != SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace ||
- PackIndex) &&
- "ExpandPacksInPlace needs a valid PackIndex");
}
static bool classof(const Type *T) {
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index 10eb40dc90ad4..391fd26a086f7 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -842,14 +842,11 @@ let Class = SubstTemplateTypeParmType in {
def : Property<"PackIndex", Optional<UInt32>> {
let Read = [{ node->getPackIndex() }];
}
- def : Property<"SubstitutionFlag", SubstTemplateTypeParmTypeFlag> {
- let Read = [{ node->getSubstitutionFlag() }];
- }
// The call to getCanonicalType here existed in ASTReader.cpp, too.
def : Creator<[{
return ctx.getSubstTemplateTypeParmType(
- replacementType, associatedDecl, Index, PackIndex, SubstitutionFlag);
+ replacementType, associatedDecl, Index, PackIndex);
}]>;
}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 09168218a9e36..822cae99ddae7 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11351,7 +11351,6 @@ class Sema final : public SemaBase {
ConceptDecl *NamedConcept, NamedDecl *FoundDecl,
const TemplateArgumentListInfo *TemplateArgs,
TemplateTypeParmDecl *ConstrainedParameter,
- QualType ConstrainedType,
SourceLocation EllipsisLoc);
bool AttachTypeConstraint(AutoTypeLoc TL,
@@ -14552,13 +14551,14 @@ class Sema final : public SemaBase {
/// \returns true if an error occurred and satisfaction could not be checked,
/// false otherwise.
bool CheckConstraintSatisfaction(
- const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+ const NamedDecl *Template,
+ ArrayRef<AssociatedConstraint> AssociatedConstraints,
const MultiLevelTemplateArgumentList &TemplateArgLists,
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
llvm::SmallVector<Expr *, 4> Converted;
- return CheckConstraintSatisfaction(Template, ConstraintExprs, Converted,
- TemplateArgLists, TemplateIDRange,
- Satisfaction);
+ return CheckConstraintSatisfaction(Template, AssociatedConstraints,
+ Converted, TemplateArgLists,
+ TemplateIDRange, Satisfaction);
}
/// \brief Check whether the given list of constraint expressions are
@@ -14584,7 +14584,8 @@ class Sema final : public SemaBase {
/// \returns true if an error occurred and satisfaction could not be checked,
/// false otherwise.
bool CheckConstraintSatisfaction(
- const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+ const NamedDecl *Template,
+ ArrayRef<AssociatedConstraint> AssociatedConstraints,
llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
const MultiLevelTemplateArgumentList &TemplateArgList,
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction);
@@ -14662,7 +14663,7 @@ class Sema final : public SemaBase {
const NormalizedConstraint *getNormalizedAssociatedConstraints(
const NamedDecl *ConstrainedDecl,
- ArrayRef<const Expr *> AssociatedConstraints);
+ ArrayRef<AssociatedConstraint> AssociatedConstraints);
/// \brief Check whether the given declaration's associated constraints are
/// at least as constrained than another declaration's according to the
@@ -14673,17 +14674,18 @@ class Sema final : public SemaBase {
///
/// \returns true if an error occurred, false otherwise.
bool IsAtLeastAsConstrained(const NamedDecl *D1,
- MutableArrayRef<const Expr *> AC1,
+ MutableArrayRef<AssociatedConstraint> AC1,
const NamedDecl *D2,
- MutableArrayRef<const Expr *> AC2, bool &Result);
+ MutableArrayRef<AssociatedConstraint> AC2,
+ bool &Result);
/// If D1 was not at least as constrained as D2, but would've been if a pair
/// of atomic constraints involved had been declared in a concept and not
/// repeated in two separate places in code.
/// \returns true if such a diagnostic was emitted, false otherwise.
bool MaybeEmitAmbiguousAtomicConstraintsDiagnostic(
- const NamedDecl *D1, ArrayRef<const Expr *> AC1, const NamedDecl *D2,
- ArrayRef<const Expr *> AC2);
+ const NamedDecl *D1, ArrayRef<AssociatedConstraint> AC1,
+ const NamedDecl *D2, ArrayRef<AssociatedConstraint> AC2);
private:
/// Caches pairs of template-like decls whose associated constraints were
diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h
index cbb3720c30ee2..648a9c51ae6c1 100644
--- a/clang/include/clang/Sema/SemaConcept.h
+++ b/clang/include/clang/Sema/SemaConcept.h
@@ -114,7 +114,8 @@ struct NormalizedConstraint {
private:
static std::optional<NormalizedConstraint>
- fromConstraintExprs(Sema &S, const NamedDecl *D, ArrayRef<const Expr *> E);
+ fromAssociatedConstraints(Sema &S, const NamedDecl *D,
+ ArrayRef<AssociatedConstraint> ACs);
static std::optional<NormalizedConstraint>
fromConstraintExpr(Sema &S, const NamedDecl *D, const Expr *E);
};
@@ -138,7 +139,7 @@ struct alignas(ConstraintAlignment) FoldExpandedConstraint {
const NormalizedConstraint *getNormalizedAssociatedConstraints(
Sema &S, const NamedDecl *ConstrainedDecl,
- ArrayRef<const Expr *> AssociatedConstraints);
+ ArrayRef<AssociatedConstraint> AssociatedConstraints);
/// \brief SubsumptionChecker establishes subsumption
/// between two set of constraints.
@@ -149,8 +150,10 @@ class SubsumptionChecker {
SubsumptionChecker(Sema &SemaRef, SubsumptionCallable Callable = {});
- std::optional<bool> Subsumes(const NamedDecl *DP, ArrayRef<const Expr *> P,
- const NamedDecl *DQ, ArrayRef<const Expr *> Q);
+ std::optional<bool> Subsumes(const NamedDecl *DP,
+ ArrayRef<AssociatedConstraint> P,
+ const NamedDecl *DQ,
+ ArrayRef<AssociatedConstraint> Q);
bool Subsumes(const NormalizedConstraint *P, const NormalizedConstraint *Q);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 089d01839e1cf..552b5823add36 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5447,11 +5447,10 @@ QualType ASTContext::getHLSLAttributedResourceType(
/// Retrieve a substitution-result type.
QualType ASTContext::getSubstTemplateTypeParmType(
QualType Replacement, Decl *AssociatedDecl, unsigned Index,
- std::optional<unsigned> PackIndex,
- SubstTemplateTypeParmTypeFlag Flag) const {
+ std::optional<unsigned> PackIndex) const {
llvm::FoldingSetNodeID ID;
SubstTemplateTypeParmType::Profile(ID, Replacement, AssociatedDecl, Index,
- PackIndex, Flag);
+ PackIndex);
void *InsertPos = nullptr;
SubstTemplateTypeParmType *SubstParm =
SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -5461,7 +5460,7 @@ QualType ASTContext::getSubstTemplateTypeParmType(
!Replacement.isCanonical()),
alignof(SubstTemplateTypeParmType));
SubstParm = new (Mem) SubstTemplateTypeParmType(Replacement, AssociatedDecl,
- Index, PackIndex, Flag);
+ Index, PackIndex);
Types.push_back(SubstParm);
SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
}
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 9a84e402e3d69..81acb013b0f7d 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1631,8 +1631,8 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType(
return ToReplacementTypeOrErr.takeError();
return Importer.getToContext().getSubstTemplateTypeParmType(
- *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex(), T->getPackIndex(),
- T->getSubstitutionFlag());
+ *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex(),
+ T->getPackIndex());
}
ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType(
@@ -5975,7 +5975,8 @@ ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
if (Err)
return std::move(Err);
- ToD->setTypeConstraint(ToConceptRef, ToIDC);
+ ToD->setTypeConstraint(ToConceptRef, ToIDC,
+ TC->getArgumentPackSubstitutionIndex());
}
if (Error Err = importTemplateParameterDefaultArgument(D, ToD))
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index c0f5be51db5f3..8f6916aeb4bd6 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -223,20 +223,21 @@ static bool AdoptTemplateParameterList(TemplateParameterList *Params,
return Invalid;
}
-void TemplateParameterList::
-getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
+void TemplateParameterList::getAssociatedConstraints(
+ llvm::SmallVectorImpl<AssociatedConstraint> &ACs) const {
if (HasConstrainedParameters)
for (const NamedDecl *Param : *this) {
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
if (const auto *TC = TTP->getTypeConstraint())
- AC.push_back(TC->getImmediatelyDeclaredConstraint());
+ ACs.emplace_back(TC->getImmediatelyDeclaredConstraint(),
+ TC->getArgumentPackSubstitutionIndex());
} else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
if (const Expr *E = NTTP->getPlaceholderTypeConstraint())
- AC.push_back(E);
+ ACs.emplace_back(E);
}
}
if (HasRequiresClause)
- AC.push_back(getRequiresClause());
+ ACs.emplace_back(getRequiresClause());
}
bool TemplateParameterList::hasAssociatedConstraints() const {
@@ -286,12 +287,12 @@ TemplateDecl::TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
void TemplateDecl::anchor() {}
-void TemplateDecl::
-getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
- TemplateParams->getAssociatedConstraints(AC);
+void TemplateDecl::getAssociatedConstraints(
+ llvm::SmallVectorImpl<AssociatedConstraint> &ACs) const {
+ TemplateParams->getAssociatedConstraints(ACs);
if (auto *FD = dyn_cast_or_null<FunctionDecl>(getTemplatedDecl()))
if (const Expr *TRC = FD->getTrailingRequiresClause())
- AC.push_back(TRC);
+ ACs.emplace_back(TRC);
}
bool TemplateDecl::hasAssociatedConstraints() const {
@@ -748,14 +749,15 @@ bool TemplateTypeParmDecl::isParameterPack() const {
}
void TemplateTypeParmDecl::setTypeConstraint(
- ConceptReference *Loc, Expr *ImmediatelyDeclaredConstraint) {
+ ConceptReference *Loc, Expr *ImmediatelyDeclaredConstraint,
+ int ArgumentPackSubstitutionIndex) {
assert(HasTypeConstraint &&
"HasTypeConstraint=true must be passed at construction in order to "
"call setTypeConstraint");
assert(!TypeConstraintInitialized &&
"TypeConstraint was already initialized!");
- new (getTrailingObjects<TypeConstraint>())
- TypeConstraint(Loc, ImmediatelyDeclaredConstraint);
+ new (getTrailingObjects<TypeConstraint>()) TypeConstraint(
+ Loc, ImmediatelyDeclaredConstraint, ArgumentPackSubstitutionIndex);
TypeConstraintInitialized = true;
}
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 9fda02b430e48..667ffc0e599a6 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4263,7 +4263,7 @@ static const TemplateTypeParmDecl *getReplacedParameter(Decl *D,
SubstTemplateTypeParmType::SubstTemplateTypeParmType(
QualType Replacement, Decl *AssociatedDecl, unsigned Index,
- std::optional<unsigned> PackIndex, SubstTemplateTypeParmTypeFlag Flag)
+ std::optional<unsigned> PackIndex)
: Type(SubstTemplateTypeParm, Replacement.getCanonicalType(),
Replacement->getDependence()),
AssociatedDecl(AssociatedDecl) {
@@ -4274,10 +4274,6 @@ SubstTemplateTypeParmType::SubstTemplateTypeParmType(
SubstTemplateTypeParmTypeBits.Index = Index;
SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0;
- SubstTemplateTypeParmTypeBits.SubstitutionFlag = llvm::to_underlying(Flag);
- assert((Flag != SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace ||
- PackIndex) &&
- "ExpandPacksInPlace needs a valid PackIndex");
assert(AssociatedDecl != nullptr);
}
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 54cafc2010f09..44a49a6e3148e 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -5463,8 +5463,9 @@ class ConceptInfo {
// that T is attached to in order to gather the relevant constraints.
ConceptInfo(const TemplateTypeParmType &BaseType, Scope *S) {
auto *TemplatedEntity = getTemplatedEntity(BaseType.getDecl(), S);
- for (const Expr *E : constraintsForTemplatedEntity(TemplatedEntity))
- believe(E, &BaseType);
+ for (const AssociatedConstraint &AC :
+ constraintsForTemplatedEntity(TemplatedEntity))
+ believe(AC.ConstraintExpr, &BaseType);
}
std::vector<Member> members() {
@@ -5696,9 +5697,9 @@ class ConceptInfo {
// Gets all the type constraint expressions that might apply to the type
// variables associated with DC (as returned by getTemplatedEntity()).
- static SmallVector<const Expr *, 1>
+ static SmallVector<AssociatedConstraint, 1>
constraintsForTemplatedEntity(DeclContext *DC) {
- SmallVector<const Expr *, 1> Result;
+ SmallVector<AssociatedConstraint, 1> Result;
if (DC == nullptr)
return Result;
// Primary templates can have constraints.
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index ebee5994bfed2..e6117f97ad1f4 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -567,11 +567,12 @@ static ExprResult calculateConstraintSatisfaction(
}
static bool CheckConstraintSatisfaction(
- Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+ Sema &S, const NamedDecl *Template,
+ ArrayRef<AssociatedConstraint> AssociatedConstraints,
llvm::SmallVectorImpl<Expr *> &Converted,
const MultiLevelTemplateArgumentList &TemplateArgsLists,
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
- if (ConstraintExprs.empty()) {
+ if (AssociatedConstraints.empty()) {
Satisfaction.IsSatisfied = true;
return false;
}
@@ -592,10 +593,12 @@ static bool CheckConstraintSatisfaction(
if (Inst.isInvalid())
return true;
- for (const Expr *ConstraintExpr : ConstraintExprs) {
+ for (const AssociatedConstraint &AC : AssociatedConstraints) {
+ Sema::ArgumentPackSubstitutionIndexRAII _(S,
+ AC.ArgumentPackSubstitutionIndex);
ExprResult Res = calculateConstraintSatisfaction(
S, Template, TemplateIDRange.getBegin(), TemplateArgsLists,
- ConstraintExpr, Satisfaction);
+ AC.ConstraintExpr, Satisfaction);
if (Res.isInvalid())
return true;
@@ -603,7 +606,8 @@ static bool CheckConstraintSatisfaction(
if (!Satisfaction.IsSatisfied) {
// Backfill the 'converted' list with nulls so we can keep the Converted
// and unconverted lists in sync.
- Converted.append(ConstraintExprs.size() - Converted.size(), nullptr);
+ Converted.append(AssociatedConstraints.size() - Converted.size(),
+ nullptr);
// [temp.constr.op] p2
// [...] To determine if a conjunction is satisfied, the satisfaction
// of the first operand is checked. If that is not satisfied, the
@@ -615,17 +619,18 @@ static bool CheckConstraintSatisfaction(
}
bool Sema::CheckConstraintSatisfaction(
- const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+ const NamedDecl *Template,
+ ArrayRef<AssociatedConstraint> AssociatedConstraints,
llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
const MultiLevelTemplateArgumentList &TemplateArgsLists,
SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) {
- if (ConstraintExprs.empty()) {
+ if (AssociatedConstraints.empty()) {
OutSatisfaction.IsSatisfied = true;
return false;
}
if (!Template) {
return ::CheckConstraintSatisfaction(
- *this, nullptr, ConstraintExprs, ConvertedConstraints,
+ *this, nullptr, AssociatedConstraints, ConvertedConstraints,
TemplateArgsLists, TemplateIDRange, OutSatisfaction);
}
// Invalid templates could make their way here. Substituting them could result
@@ -654,7 +659,7 @@ bool Sema::CheckConstraintSatisfaction(
auto Satisfaction =
std::make_unique<ConstraintSatisfaction>(Template, FlattenedArgs);
- if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
+ if (::CheckConstraintSatisfaction(*this, Template, AssociatedConstraints,
ConvertedConstraints, TemplateArgsLists,
TemplateIDRange, *Satisfaction)) {
OutSatisfaction = *Satisfaction;
@@ -923,8 +928,10 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
ForOverloadResolution);
return CheckConstraintSatisfaction(
- FD, {FD->getTrailingRequiresClause()}, *MLTAL,
- SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
+ FD,
+ AssociatedConstraint(FD->getTrailingRequiresClause(),
+ ArgumentPackSubstitutionIndex),
+ *MLTAL, SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
Satisfaction);
}
@@ -1099,13 +1106,13 @@ bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
assert(FD->getDescribedFunctionTemplate() &&
"Non-function templates don't need to be checked");
- SmallVector<const Expr *, 3> ACs;
+ SmallVector<AssociatedConstraint, 3> ACs;
FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
- for (const Expr *Constraint : ACs)
+ for (const AssociatedConstraint &AC : ACs)
if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
- Constraint))
+ AC.ConstraintExpr))
return true;
return false;
@@ -1115,7 +1122,7 @@ bool Sema::EnsureTemplateArgumentListConstraints(
TemplateDecl *TD, const MultiLevelTemplateArgumentList &TemplateArgsLists,
SourceRange TemplateIDRange) {
ConstraintSatisfaction Satisfaction;
- llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
+ llvm::SmallVector<AssociatedConstraint, 3> AssociatedConstraints;
TD->getAssociatedConstraints(AssociatedConstraints);
if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgsLists,
TemplateIDRange, Satisfaction))
@@ -1146,7 +1153,7 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
FunctionTemplateDecl *Template = Decl->getPrimaryTemplate();
// Note - code synthesis context for the constraints check is created
// inside CheckConstraintsSatisfaction.
- SmallVector<const Expr *, 3> TemplateAC;
+ SmallVector<AssociatedConstraint, 3> TemplateAC;
Template->getAssociatedConstraints(TemplateAC);
if (TemplateAC.empty()) {
Satisfaction.IsSatisfied = true;
@@ -1438,7 +1445,7 @@ void Sema::DiagnoseUnsatisfiedConstraint(
const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints(
const NamedDecl *ConstrainedDecl,
- ArrayRef<const Expr *> AssociatedConstraints) {
+ ArrayRef<AssociatedConstraint> AssociatedConstraints) {
// In case the ConstrainedDecl comes from modules, it is necessary to use
// the canonical decl to avoid
diff erent atomic constraints with the 'same'
// declarations.
@@ -1446,9 +1453,8 @@ const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints(
auto CacheEntry = NormalizationCache.find(ConstrainedDecl);
if (CacheEntry == NormalizationCache.end()) {
- auto Normalized =
- NormalizedConstraint::fromConstraintExprs(*this, ConstrainedDecl,
- AssociatedConstraints);
+ auto Normalized = NormalizedConstraint::fromAssociatedConstraints(
+ *this, ConstrainedDecl, AssociatedConstraints);
CacheEntry =
NormalizationCache
.try_emplace(ConstrainedDecl,
@@ -1463,7 +1469,7 @@ const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints(
const NormalizedConstraint *clang::getNormalizedAssociatedConstraints(
Sema &S, const NamedDecl *ConstrainedDecl,
- ArrayRef<const Expr *> AssociatedConstraints) {
+ ArrayRef<AssociatedConstraint> AssociatedConstraints) {
return S.getNormalizedAssociatedConstraints(ConstrainedDecl,
AssociatedConstraints);
}
@@ -1593,14 +1599,14 @@ NormalizedConstraint &NormalizedConstraint::getRHS() const {
}
std::optional<NormalizedConstraint>
-NormalizedConstraint::fromConstraintExprs(Sema &S, const NamedDecl *D,
- ArrayRef<const Expr *> E) {
- assert(E.size() != 0);
- auto Conjunction = fromConstraintExpr(S, D, E[0]);
+NormalizedConstraint::fromAssociatedConstraints(
+ Sema &S, const NamedDecl *D, ArrayRef<AssociatedConstraint> ACs) {
+ assert(ACs.size() != 0);
+ auto Conjunction = fromConstraintExpr(S, D, ACs[0].ConstraintExpr);
if (!Conjunction)
return std::nullopt;
- for (unsigned I = 1; I < E.size(); ++I) {
- auto Next = fromConstraintExpr(S, D, E[I]);
+ for (unsigned I = 1; I < ACs.size(); ++I) {
+ auto Next = fromConstraintExpr(S, D, ACs[I].ConstraintExpr);
if (!Next)
return std::nullopt;
*Conjunction = NormalizedConstraint(S.Context, std::move(*Conjunction),
@@ -1655,8 +1661,8 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, const NamedDecl *D,
// expression, the program is ill-formed; no diagnostic is required.
// [...]
ConceptDecl *CD = CSE->getNamedConcept();
- SubNF = S.getNormalizedAssociatedConstraints(CD,
- {CD->getConstraintExpr()});
+ SubNF = S.getNormalizedAssociatedConstraints(
+ CD, AssociatedConstraint(CD->getConstraintExpr()));
if (!SubNF)
return std::nullopt;
}
@@ -1731,9 +1737,9 @@ bool FoldExpandedConstraint::AreCompatibleForSubsumption(
}
bool Sema::IsAtLeastAsConstrained(const NamedDecl *D1,
- MutableArrayRef<const Expr *> AC1,
+ MutableArrayRef<AssociatedConstraint> AC1,
const NamedDecl *D2,
- MutableArrayRef<const Expr *> AC2,
+ MutableArrayRef<AssociatedConstraint> AC2,
bool &Result) {
#ifndef NDEBUG
if (const auto *FD1 = dyn_cast<FunctionDecl>(D1)) {
@@ -1771,13 +1777,15 @@ bool Sema::IsAtLeastAsConstrained(const NamedDecl *D1,
for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) {
if (Depth2 > Depth1) {
- AC1[I] = AdjustConstraintDepth(*this, Depth2 - Depth1)
- .TransformExpr(const_cast<Expr *>(AC1[I]))
- .get();
+ AC1[I].ConstraintExpr =
+ AdjustConstraintDepth(*this, Depth2 - Depth1)
+ .TransformExpr(const_cast<Expr *>(AC1[I].ConstraintExpr))
+ .get();
} else if (Depth1 > Depth2) {
- AC2[I] = AdjustConstraintDepth(*this, Depth1 - Depth2)
- .TransformExpr(const_cast<Expr *>(AC2[I]))
- .get();
+ AC2[I].ConstraintExpr =
+ AdjustConstraintDepth(*this, Depth1 - Depth2)
+ .TransformExpr(const_cast<Expr *>(AC2[I].ConstraintExpr))
+ .get();
}
}
@@ -1793,9 +1801,8 @@ bool Sema::IsAtLeastAsConstrained(const NamedDecl *D1,
}
bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(
- const NamedDecl *D1, ArrayRef<const Expr *> AC1, const NamedDecl *D2,
- ArrayRef<const Expr *> AC2) {
-
+ const NamedDecl *D1, ArrayRef<AssociatedConstraint> AC1,
+ const NamedDecl *D2, ArrayRef<AssociatedConstraint> AC2) {
if (isSFINAEContext())
// No need to work here because our notes would be discarded.
return false;
@@ -2106,10 +2113,9 @@ void SubsumptionChecker::AddUniqueClauseToFormula(Formula &F, Clause C) {
F.push_back(C);
}
-std::optional<bool> SubsumptionChecker::Subsumes(const NamedDecl *DP,
- ArrayRef<const Expr *> P,
- const NamedDecl *DQ,
- ArrayRef<const Expr *> Q) {
+std::optional<bool> SubsumptionChecker::Subsumes(
+ const NamedDecl *DP, ArrayRef<AssociatedConstraint> P, const NamedDecl *DQ,
+ ArrayRef<AssociatedConstraint> Q) {
const NormalizedConstraint *PNormalized =
getNormalizedAssociatedConstraints(SemaRef, DP, P);
if (!PNormalized)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 2246f0f1b3121..bbefbbf294dd1 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -19130,8 +19130,9 @@ static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record,
AnotherMethodIsMoreConstrained = true;
break;
}
- if (S.IsAtLeastAsConstrained(OtherMethod, {OtherConstraints}, OrigMethod,
- {Constraints},
+ AssociatedConstraint Other(OtherConstraints);
+ AssociatedConstraint Orig(Constraints);
+ if (S.IsAtLeastAsConstrained(OtherMethod, {Other}, OrigMethod, {Orig},
AnotherMethodIsMoreConstrained)) {
// There was an error with the constraints comparison. Exit the loop
// and don't consider this function eligible.
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 19fd51134d160..fa492bc124abd 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -9551,7 +9551,8 @@ concepts::NestedRequirement *
Sema::BuildNestedRequirement(Expr *Constraint) {
ConstraintSatisfaction Satisfaction;
if (!Constraint->isInstantiationDependent() &&
- CheckConstraintSatisfaction(nullptr, {Constraint}, /*TemplateArgs=*/{},
+ CheckConstraintSatisfaction(nullptr, AssociatedConstraint(Constraint),
+ /*TemplateArgs=*/{},
Constraint->getSourceRange(), Satisfaction))
return nullptr;
return new (Context) concepts::NestedRequirement(Context, Constraint,
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 6d8006b35dcf4..1802f8f4e1f91 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -11280,12 +11280,12 @@ MaybeDiagnoseAmbiguousConstraints(Sema &S, ArrayRef<OverloadCandidate> Cands) {
// source-level construct. This behavior is quite confusing and we should try
// to help the user figure out what happened.
- SmallVector<const Expr *, 3> FirstAC, SecondAC;
+ SmallVector<AssociatedConstraint, 3> FirstAC, SecondAC;
FunctionDecl *FirstCand = nullptr, *SecondCand = nullptr;
for (auto I = Cands.begin(), E = Cands.end(); I != E; ++I) {
if (!I->Function)
continue;
- SmallVector<const Expr *, 3> AC;
+ SmallVector<AssociatedConstraint, 3> AC;
if (auto *Template = I->Function->getPrimaryTemplate())
Template->getAssociatedConstraints(AC);
else
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index de2b1fdbc44e2..eace9b87a5bfe 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1133,8 +1133,7 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS,
SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(),
ConceptName, CD, /*FoundDecl=*/USD ? cast<NamedDecl>(USD) : CD,
TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr,
- ConstrainedParameter, Context.getTypeDeclType(ConstrainedParameter),
- EllipsisLoc);
+ ConstrainedParameter, EllipsisLoc);
}
template <typename ArgumentLocAppender>
@@ -1191,7 +1190,6 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
ConceptDecl *NamedConcept, NamedDecl *FoundDecl,
const TemplateArgumentListInfo *TemplateArgs,
TemplateTypeParmDecl *ConstrainedParameter,
- QualType ConstrainedType,
SourceLocation EllipsisLoc) {
// C++2a [temp.param]p4:
// [...] If Q is of the form C<A1, ..., An>, then let E' be
@@ -1200,7 +1198,7 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
TemplateArgs ? ASTTemplateArgumentListInfo::Create(Context,
*TemplateArgs) : nullptr;
- QualType ParamAsArgument = ConstrainedType;
+ QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0);
ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint(
*this, NS, NameInfo, NamedConcept, FoundDecl,
@@ -1223,7 +1221,8 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
/*NamedConcept=*/NamedConcept,
/*ArgsWritten=*/ArgsAsWritten);
ConstrainedParameter->setTypeConstraint(CL,
- ImmediatelyDeclaredConstraint.get());
+ ImmediatelyDeclaredConstraint.get(),
+ /*ArgumentPackSubstitutionIndex=*/-1);
return false;
}
@@ -4062,7 +4061,7 @@ static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) {
}
S.NoteTemplateLocation(*Template);
- SmallVector<const Expr *, 3> PartialAC, TemplateAC;
+ SmallVector<AssociatedConstraint, 3> PartialAC, TemplateAC;
Template->getAssociatedConstraints(TemplateAC);
Partial->getAssociatedConstraints(PartialAC);
S.MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Partial, PartialAC, Template,
@@ -4604,7 +4603,8 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
if (!AreArgsDependent &&
CheckConstraintSatisfaction(
- NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL,
+ NamedConcept, AssociatedConstraint(NamedConcept->getConstraintExpr()),
+ MLTAL,
SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(),
TemplateArgs->getRAngleLoc()),
Satisfaction))
@@ -7432,7 +7432,7 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
// C++20[temp.func.order]p2
// [...] If both deductions succeed, the partial ordering selects the
// more constrained template (if one exists) as determined below.
- SmallVector<const Expr *, 3> ParamsAC, TemplateAC;
+ SmallVector<AssociatedConstraint, 3> ParamsAC, TemplateAC;
Params->getAssociatedConstraints(ParamsAC);
// C++20[temp.arg.template]p3
// [...] In this comparison, if P is unconstrained, the constraints on A
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index b39eb8fd5512e..9969f1762fe36 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3255,7 +3255,7 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
ArrayRef<TemplateArgument> SugaredDeducedArgs,
ArrayRef<TemplateArgument> CanonicalDeducedArgs,
TemplateDeductionInfo &Info) {
- llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
+ llvm::SmallVector<AssociatedConstraint, 3> AssociatedConstraints;
Template->getAssociatedConstraints(AssociatedConstraints);
std::optional<ArrayRef<TemplateArgument>> Innermost;
@@ -5245,9 +5245,9 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
ImplicitConceptSpecializationDecl::Create(
S.getASTContext(), Concept->getDeclContext(), Concept->getLocation(),
CTAI.CanonicalConverted));
- if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
- MLTAL, TypeLoc.getLocalSourceRange(),
- Satisfaction))
+ if (S.CheckConstraintSatisfaction(
+ Concept, AssociatedConstraint(Concept->getConstraintExpr()), MLTAL,
+ TypeLoc.getLocalSourceRange(), Satisfaction))
return true;
if (!Satisfaction.IsSatisfied) {
std::string Buf;
@@ -6121,7 +6121,7 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
!Context.hasSameType(FD1->getReturnType(), FD2->getReturnType()))
return nullptr;
- llvm::SmallVector<const Expr *, 3> AC1, AC2;
+ llvm::SmallVector<AssociatedConstraint, 3> AC1, AC2;
FT1->getAssociatedConstraints(AC1);
FT2->getAssociatedConstraints(AC2);
bool AtLeastAsConstrained1, AtLeastAsConstrained2;
@@ -6226,7 +6226,7 @@ FunctionDecl *Sema::getMoreConstrainedFunction(FunctionDecl *FD1,
if (FunctionDecl *P = FD2->getTemplateInstantiationPattern(false))
F2 = P;
- llvm::SmallVector<const Expr *, 1> AC1, AC2;
+ llvm::SmallVector<AssociatedConstraint, 1> AC1, AC2;
F1->getAssociatedConstraints(AC1);
F2->getAssociatedConstraints(AC2);
bool AtLeastAsConstrained1, AtLeastAsConstrained2;
@@ -6458,7 +6458,7 @@ getMoreSpecialized(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P1,
if (!TemplateArgumentListAreEqual(S.getASTContext())(P1, P2))
return nullptr;
- llvm::SmallVector<const Expr *, 3> AC1, AC2;
+ llvm::SmallVector<AssociatedConstraint, 3> AC1, AC2;
P1->getAssociatedConstraints(AC1);
P2->getAssociatedConstraints(AC2);
bool AtLeastAsConstrained1, AtLeastAsConstrained2;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 00dcadb41e8fb..9f5ca9dca8e89 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1717,24 +1717,6 @@ namespace {
SubstTemplateTypeParmPackTypeLoc TL,
bool SuppressObjCLifetime);
- QualType
- TransformSubstTemplateTypeParmType(TypeLocBuilder &TLB,
- SubstTemplateTypeParmTypeLoc TL) {
- const SubstTemplateTypeParmType *Type = TL.getTypePtr();
- if (Type->getSubstitutionFlag() !=
- SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace)
- return inherited::TransformSubstTemplateTypeParmType(TLB, TL);
-
- assert(Type->getPackIndex());
- TemplateArgument TA = TemplateArgs(
- Type->getReplacedParameter()->getDepth(), Type->getIndex());
- assert(*Type->getPackIndex() + 1 <= TA.pack_size());
- Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(
- SemaRef, TA.pack_size() - 1 - *Type->getPackIndex());
-
- return inherited::TransformSubstTemplateTypeParmType(TLB, TL);
- }
-
CXXRecordDecl::LambdaDependencyKind
ComputeLambdaDependency(LambdaScopeInfo *LSI) {
if (auto TypeAlias =
@@ -2894,8 +2876,11 @@ TemplateInstantiator::TransformNestedRequirement(
return nullptr;
llvm::SmallVector<Expr *> Result;
if (!SemaRef.CheckConstraintSatisfaction(
- nullptr, {Req->getConstraintExpr()}, Result, TemplateArgs,
- Req->getConstraintExpr()->getSourceRange(), Satisfaction) &&
+ nullptr,
+ AssociatedConstraint(Req->getConstraintExpr(),
+ SemaRef.ArgumentPackSubstitutionIndex),
+ Result, TemplateArgs, Req->getConstraintExpr()->getSourceRange(),
+ Satisfaction) &&
!Result.empty())
TransConstraint = Result[0];
assert(!Trap.hasErrorOccurred() && "Substitution failures must be handled "
@@ -3169,68 +3154,6 @@ namespace {
} // namespace
-namespace {
-
-struct ExpandPackedTypeConstraints
- : TreeTransform<ExpandPackedTypeConstraints> {
-
- using inherited = TreeTransform<ExpandPackedTypeConstraints>;
-
- const MultiLevelTemplateArgumentList &TemplateArgs;
-
- ExpandPackedTypeConstraints(
- Sema &SemaRef, const MultiLevelTemplateArgumentList &TemplateArgs)
- : inherited(SemaRef), TemplateArgs(TemplateArgs) {}
-
- using inherited::TransformTemplateTypeParmType;
-
- QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
- TemplateTypeParmTypeLoc TL, bool) {
- const TemplateTypeParmType *T = TL.getTypePtr();
- if (!T->isParameterPack()) {
- TemplateTypeParmTypeLoc NewTL =
- TLB.push<TemplateTypeParmTypeLoc>(TL.getType());
- NewTL.setNameLoc(TL.getNameLoc());
- return TL.getType();
- }
-
- assert(SemaRef.ArgumentPackSubstitutionIndex != -1);
-
- TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex());
-
- std::optional<unsigned> PackIndex;
- if (Arg.getKind() == TemplateArgument::Pack)
- PackIndex = Arg.pack_size() - 1 - SemaRef.ArgumentPackSubstitutionIndex;
-
- QualType Result = SemaRef.Context.getSubstTemplateTypeParmType(
- TL.getType(), T->getDecl(), T->getIndex(), PackIndex,
- SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace);
- SubstTemplateTypeParmTypeLoc NewTL =
- TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
- return Result;
- }
-
- QualType TransformSubstTemplateTypeParmType(TypeLocBuilder &TLB,
- SubstTemplateTypeParmTypeLoc TL) {
- const SubstTemplateTypeParmType *T = TL.getTypePtr();
- if (T->getPackIndex()) {
- SubstTemplateTypeParmTypeLoc TypeLoc =
- TLB.push<SubstTemplateTypeParmTypeLoc>(TL.getType());
- TypeLoc.setNameLoc(TL.getNameLoc());
- return TypeLoc.getType();
- }
- return inherited::TransformSubstTemplateTypeParmType(TLB, TL);
- }
-
- bool SubstTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
- TemplateArgumentListInfo &Out) {
- return inherited::TransformTemplateArguments(Args.begin(), Args.end(), Out);
- }
-};
-
-} // namespace
-
bool Sema::SubstTypeConstraint(
TemplateTypeParmDecl *Inst, const TypeConstraint *TC,
const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -3239,61 +3162,11 @@ bool Sema::SubstTypeConstraint(
TC->getTemplateArgsAsWritten();
if (!EvaluateConstraints) {
- bool ShouldExpandExplicitTemplateArgs =
- TemplArgInfo && ArgumentPackSubstitutionIndex != -1 &&
- llvm::any_of(TemplArgInfo->arguments(), [](auto &Arg) {
- return Arg.getArgument().containsUnexpandedParameterPack();
- });
-
- // We want to transform the packs into Subst* nodes for type constraints
- // inside a pack expansion. For example,
- //
- // template <class... Ts> void foo() {
- // bar([](C<Ts> auto value) {}...);
- // }
- //
- // As we expand Ts in the process of instantiating foo(), and retain
- // the original template depths of Ts until the constraint evaluation, we
- // would otherwise have no chance to expand Ts by the time of evaluating
- // C<auto, Ts>.
- //
- // So we form a Subst* node for Ts along with a proper substitution index
- // here, and substitute the node with a complete MLTAL later in evaluation.
- if (ShouldExpandExplicitTemplateArgs) {
- TemplateArgumentListInfo InstArgs;
- InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
- InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
- if (ExpandPackedTypeConstraints(*this, TemplateArgs)
- .SubstTemplateArguments(TemplArgInfo->arguments(), InstArgs))
- return true;
-
- // The type of the original parameter.
- auto *ConstraintExpr = TC->getImmediatelyDeclaredConstraint();
- QualType ConstrainedType;
-
- if (auto *FE = dyn_cast<CXXFoldExpr>(ConstraintExpr)) {
- assert(FE->getLHS());
- ConstraintExpr = FE->getLHS();
- }
- auto *CSE = cast<ConceptSpecializationExpr>(ConstraintExpr);
- assert(!CSE->getTemplateArguments().empty() &&
- "Empty template arguments?");
- ConstrainedType = CSE->getTemplateArguments()[0].getAsType();
- assert(!ConstrainedType.isNull() &&
- "Failed to extract the original ConstrainedType?");
-
- return AttachTypeConstraint(
- TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
- TC->getNamedConcept(),
- /*FoundDecl=*/TC->getConceptReference()->getFoundDecl(), &InstArgs,
- Inst, ConstrainedType,
- Inst->isParameterPack()
- ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
- ->getEllipsisLoc()
- : SourceLocation());
- }
+ auto Index = TC->getArgumentPackSubstitutionIndex();
+ if (Index == -1)
+ Index = SemaRef.ArgumentPackSubstitutionIndex;
Inst->setTypeConstraint(TC->getConceptReference(),
- TC->getImmediatelyDeclaredConstraint());
+ TC->getImmediatelyDeclaredConstraint(), Index);
return false;
}
@@ -3310,7 +3183,6 @@ bool Sema::SubstTypeConstraint(
TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
TC->getNamedConcept(),
/*FoundDecl=*/TC->getConceptReference()->getFoundDecl(), &InstArgs, Inst,
- Context.getTypeDeclType(Inst),
Inst->isParameterPack()
? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
->getEllipsisLoc()
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 776d6e55acc18..2df961a48c7c3 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -3052,9 +3052,7 @@ InventTemplateParameter(TypeProcessingState &state, QualType T,
AutoLoc.getNestedNameSpecifierLoc(), AutoLoc.getConceptNameInfo(),
AutoLoc.getNamedConcept(), /*FoundDecl=*/AutoLoc.getFoundDecl(),
AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr,
- InventedTemplateParam,
- S.Context.getTypeDeclType(InventedTemplateParam),
- D.getEllipsisLoc());
+ InventedTemplateParam, D.getEllipsisLoc());
}
} else {
// The 'auto' appears in the decl-specifiers; we've not finished forming
@@ -3091,9 +3089,7 @@ InventTemplateParameter(TypeProcessingState &state, QualType T,
/*FoundDecl=*/
USD ? cast<NamedDecl>(USD) : CD,
TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr,
- InventedTemplateParam,
- S.Context.getTypeDeclType(InventedTemplateParam),
- D.getEllipsisLoc());
+ InventedTemplateParam, D.getEllipsisLoc());
}
}
}
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index c3341e00bacef..77daeaee5dd1f 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2706,8 +2706,10 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
if (Record.readBool())
CR = Record.readConceptReference();
Expr *ImmediatelyDeclaredConstraint = Record.readExpr();
+ int ArgumentPackSubstitutionIndex = Record.readInt();
- D->setTypeConstraint(CR, ImmediatelyDeclaredConstraint);
+ D->setTypeConstraint(CR, ImmediatelyDeclaredConstraint,
+ ArgumentPackSubstitutionIndex);
if ((D->ExpandedParameterPack = Record.readInt()))
D->NumExpanded = Record.readInt();
}
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index f377c145a4204..b896a04a0b14b 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -2036,6 +2036,7 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
if (CR)
Record.AddConceptReference(CR);
Record.AddStmt(TC->getImmediatelyDeclaredConstraint());
+ Record.push_back(TC->getArgumentPackSubstitutionIndex());
Record.push_back(D->isExpandedParameterPack());
if (D->isExpandedParameterPack())
Record.push_back(D->getNumExpansionParameters());
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 832ce15e66250..c863cc841af42 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -485,7 +485,7 @@ struct Out {
A(T2);
};
A(int) -> A<T1>;
-
+
template <typename T3>
using B = A<T3>;
};
diff --git a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp
index 69572bea3664a..106da7d0e2663 100644
--- a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp
+++ b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp
@@ -238,4 +238,51 @@ static_assert(bar<int, float>()(123));
// expected-note@#C {{evaluated to false}}
// expected-note@#same_as 2{{evaluated to false}}
+template <class T, auto U>
+concept same_as_v = __is_same(T, decltype(U)); // #same_as_v
+
+template <auto... Vs> constexpr auto baz() {
+ return Overloaded{[](same_as_v<Vs> auto value) { return value; }...}; // #baz
+}
+
+static_assert(baz<1, 1.>()(123) == 123);
+static_assert(baz<1, 1.>()(2.718) == 2.718);
+
+static_assert(baz<1, 1.>()('c'));
+// expected-error at -1 {{no matching function}}
+
+// expected-note@#baz {{constraints not satisfied}}
+// expected-note@#baz {{'same_as_v<char, 1>' evaluated to false}}
+// expected-note@#same_as_v {{evaluated to false}}
+
+// expected-note@#baz {{constraints not satisfied}}
+// expected-note@#baz {{'same_as_v<char, 1.>' evaluated to false}}
+// expected-note@#same_as_v {{evaluated to false}}
+
+template <auto... Ts> constexpr auto bazz() {
+ return Overloaded{[](same_as_v<Ts> auto value) { return Ts; }...}; // #bazz
+}
+
+static_assert(bazz<1, 2>()(1));
+// expected-error at -1 {{is ambiguous}}
+// expected-note@#bazz 2{{candidate function [with value:auto = int]}}
+
} // namespace GH101754
+
+namespace GH131798 {
+ template <class T0>
+ struct tuple { T0 elem0; };
+
+ template <class, class>
+ concept C = true;
+
+ template <int>
+ struct Foo {};
+
+ template <int... Vals>
+ constexpr tuple fs{[] (C<Foo<Vals>> auto) {}...};
+
+ int main() {
+ fs<0>.elem0(1);
+ }
+} // namspace GH131798
diff --git a/clang/unittests/AST/SourceLocationTest.cpp b/clang/unittests/AST/SourceLocationTest.cpp
index daea2d62fe496..5b461d1cf4400 100644
--- a/clang/unittests/AST/SourceLocationTest.cpp
+++ b/clang/unittests/AST/SourceLocationTest.cpp
@@ -1094,11 +1094,11 @@ class ConceptSpecializationExprConceptReferenceRangeVerifier
protected:
SourceRange getRange(const VarTemplateDecl &Node) override {
assert(Node.hasAssociatedConstraints());
- SmallVector<const Expr *, 3> ACs;
+ SmallVector<AssociatedConstraint, 3> ACs;
Node.getAssociatedConstraints(ACs);
- for (const Expr *Constraint : ACs) {
+ for (const AssociatedConstraint &AC : ACs) {
if (const ConceptSpecializationExpr *CSConstraint =
- dyn_cast<ConceptSpecializationExpr>(Constraint)) {
+ dyn_cast<ConceptSpecializationExpr>(AC.ConstraintExpr)) {
return CSConstraint->getConceptReference()->getSourceRange();
}
}
More information about the cfe-commits
mailing list