[clang] support pack expansions for trailing requires clauses (#133190)

This commit is contained in:
Matheus Izvekov 2025-04-03 12:36:15 -03:00 committed by GitHub
parent c1ada72b09
commit 49fd0bf35d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 204 additions and 133 deletions

View File

@ -100,9 +100,9 @@ computeReferencedDecls(const clang::Expr *Expr) {
TraverseLambdaCapture(LExpr, &Capture, Initializer); TraverseLambdaCapture(LExpr, &Capture, Initializer);
} }
if (clang::Expr *const RequiresClause = if (const clang::Expr *RequiresClause =
LExpr->getTrailingRequiresClause()) { LExpr->getTrailingRequiresClause().ConstraintExpr) {
TraverseStmt(RequiresClause); TraverseStmt(const_cast<clang::Expr *>(RequiresClause));
} }
for (auto *const TemplateParam : LExpr->getExplicitTemplateParameters()) for (auto *const TemplateParam : LExpr->getExplicitTemplateParameters())

View File

@ -385,6 +385,8 @@ Bug Fixes to C++ Support
- Improved fix for an issue with pack expansions of type constraints, where this - 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. now also works if the constraint has non-type or template template parameters.
(#GH131798) (#GH131798)
- Fix crash when evaluating the trailing requires clause of generic lambdas which are part of
a pack expansion.
- Fixes matching of nested template template parameters. (#GH130362) - Fixes matching of nested template template parameters. (#GH130362)
- Correctly diagnoses template template paramters which have a pack parameter - Correctly diagnoses template template paramters which have a pack parameter
not in the last position. not in the last position.

View File

@ -2907,6 +2907,14 @@ public:
/// that they may be used in declarations of the same template. /// that they may be used in declarations of the same template.
bool isSameTemplateParameter(const NamedDecl *X, const NamedDecl *Y) const; bool isSameTemplateParameter(const NamedDecl *X, const NamedDecl *Y) const;
/// Determine whether two 'requires' expressions are similar enough that they
/// may be used in re-declarations.
///
/// Use of 'requires' isn't mandatory, works with constraints expressed in
/// other ways too.
bool isSameAssociatedConstraint(const AssociatedConstraint &ACX,
const AssociatedConstraint &ACY) const;
/// Determine whether two 'requires' expressions are similar enough that they /// Determine whether two 'requires' expressions are similar enough that they
/// may be used in re-declarations. /// may be used in re-declarations.
/// ///

View File

@ -538,8 +538,8 @@ public:
for (const auto *Parameter : D->parameters()) for (const auto *Parameter : D->parameters())
Visit(Parameter); Visit(Parameter);
if (const Expr *TRC = D->getTrailingRequiresClause()) if (const AssociatedConstraint &TRC = D->getTrailingRequiresClause())
Visit(TRC); Visit(TRC.ConstraintExpr);
if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isDefaulted()) if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isDefaulted())
return; return;

View File

@ -81,13 +81,19 @@ enum class ImplicitParamKind;
// Holds a constraint expression along with a pack expansion index, if // Holds a constraint expression along with a pack expansion index, if
// expanded. // expanded.
struct AssociatedConstraint { struct AssociatedConstraint {
const Expr *ConstraintExpr; const Expr *ConstraintExpr = nullptr;
int ArgumentPackSubstitutionIndex; int ArgumentPackSubstitutionIndex = -1;
constexpr AssociatedConstraint() = default;
explicit AssociatedConstraint(const Expr *ConstraintExpr, explicit AssociatedConstraint(const Expr *ConstraintExpr,
int ArgumentPackSubstitutionIndex = -1) int ArgumentPackSubstitutionIndex = -1)
: ConstraintExpr(ConstraintExpr), : ConstraintExpr(ConstraintExpr),
ArgumentPackSubstitutionIndex(ArgumentPackSubstitutionIndex) {} ArgumentPackSubstitutionIndex(ArgumentPackSubstitutionIndex) {}
explicit operator bool() const { return ConstraintExpr != nullptr; }
bool isNull() const { return !operator bool(); }
}; };
/// The top declaration context. /// The top declaration context.
@ -754,7 +760,7 @@ class DeclaratorDecl : public ValueDecl {
// and constrained function decls. // and constrained function decls.
struct ExtInfo : public QualifierInfo { struct ExtInfo : public QualifierInfo {
TypeSourceInfo *TInfo = nullptr; TypeSourceInfo *TInfo = nullptr;
Expr *TrailingRequiresClause = nullptr; AssociatedConstraint TrailingRequiresClause;
}; };
llvm::PointerUnion<TypeSourceInfo *, ExtInfo *> DeclInfo; llvm::PointerUnion<TypeSourceInfo *, ExtInfo *> DeclInfo;
@ -823,17 +829,12 @@ public:
/// \brief Get the constraint-expression introduced by the trailing /// \brief Get the constraint-expression introduced by the trailing
/// requires-clause in the function/member declaration, or null if no /// requires-clause in the function/member declaration, or null if no
/// requires-clause was provided. /// requires-clause was provided.
Expr *getTrailingRequiresClause() { const AssociatedConstraint &getTrailingRequiresClause() const {
return hasExtInfo() ? getExtInfo()->TrailingRequiresClause static constexpr AssociatedConstraint Null;
: nullptr; return hasExtInfo() ? getExtInfo()->TrailingRequiresClause : Null;
} }
const Expr *getTrailingRequiresClause() const { void setTrailingRequiresClause(const AssociatedConstraint &AC);
return hasExtInfo() ? getExtInfo()->TrailingRequiresClause
: nullptr;
}
void setTrailingRequiresClause(Expr *TrailingRequiresClause);
unsigned getNumTemplateParameterLists() const { unsigned getNumTemplateParameterLists() const {
return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0; return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0;
@ -2102,7 +2103,7 @@ protected:
const DeclarationNameInfo &NameInfo, QualType T, const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, StorageClass S, bool UsesFPIntrin, TypeSourceInfo *TInfo, StorageClass S, bool UsesFPIntrin,
bool isInlineSpecified, ConstexprSpecKind ConstexprKind, bool isInlineSpecified, ConstexprSpecKind ConstexprKind,
Expr *TrailingRequiresClause = nullptr); const AssociatedConstraint &TrailingRequiresClause);
using redeclarable_base = Redeclarable<FunctionDecl>; using redeclarable_base = Redeclarable<FunctionDecl>;
@ -2138,7 +2139,7 @@ public:
TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin = false, TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin = false,
bool isInlineSpecified = false, bool hasWrittenPrototype = true, bool isInlineSpecified = false, bool hasWrittenPrototype = true,
ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified, ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified,
Expr *TrailingRequiresClause = nullptr) { const AssociatedConstraint &TrailingRequiresClause = {}) {
DeclarationNameInfo NameInfo(N, NLoc); DeclarationNameInfo NameInfo(N, NLoc);
return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, SC, return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, SC,
UsesFPIntrin, isInlineSpecified, UsesFPIntrin, isInlineSpecified,
@ -2151,7 +2152,7 @@ public:
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
StorageClass SC, bool UsesFPIntrin, bool isInlineSpecified, StorageClass SC, bool UsesFPIntrin, bool isInlineSpecified,
bool hasWrittenPrototype, ConstexprSpecKind ConstexprKind, bool hasWrittenPrototype, ConstexprSpecKind ConstexprKind,
Expr *TrailingRequiresClause); const AssociatedConstraint &TrailingRequiresClause);
static FunctionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); static FunctionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
@ -2644,9 +2645,9 @@ public:
/// Use this instead of getTrailingRequiresClause for concepts APIs that /// Use this instead of getTrailingRequiresClause for concepts APIs that
/// accept an ArrayRef of constraint expressions. /// accept an ArrayRef of constraint expressions.
void void
getAssociatedConstraints(SmallVectorImpl<AssociatedConstraint> &AC) const { getAssociatedConstraints(SmallVectorImpl<AssociatedConstraint> &ACs) const {
if (auto *TRC = getTrailingRequiresClause()) if (const AssociatedConstraint &AC = getTrailingRequiresClause())
AC.emplace_back(TRC); ACs.emplace_back(AC);
} }
/// Get the message that indicates why this function was deleted. /// Get the message that indicates why this function was deleted.

View File

@ -1974,7 +1974,7 @@ private:
const DeclarationNameInfo &NameInfo, QualType T, const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, SourceLocation EndLocation, TypeSourceInfo *TInfo, SourceLocation EndLocation,
CXXConstructorDecl *Ctor, DeductionCandidate Kind, CXXConstructorDecl *Ctor, DeductionCandidate Kind,
Expr *TrailingRequiresClause, const AssociatedConstraint &TrailingRequiresClause,
const CXXDeductionGuideDecl *GeneratedFrom, const CXXDeductionGuideDecl *GeneratedFrom,
SourceDeductionGuideKind SourceKind) SourceDeductionGuideKind SourceKind)
: FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo, : FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
@ -2007,7 +2007,7 @@ public:
TypeSourceInfo *TInfo, SourceLocation EndLocation, TypeSourceInfo *TInfo, SourceLocation EndLocation,
CXXConstructorDecl *Ctor = nullptr, CXXConstructorDecl *Ctor = nullptr,
DeductionCandidate Kind = DeductionCandidate::Normal, DeductionCandidate Kind = DeductionCandidate::Normal,
Expr *TrailingRequiresClause = nullptr, const AssociatedConstraint &TrailingRequiresClause = {},
const CXXDeductionGuideDecl *SourceDG = nullptr, const CXXDeductionGuideDecl *SourceDG = nullptr,
SourceDeductionGuideKind SK = SourceDeductionGuideKind::None); SourceDeductionGuideKind SK = SourceDeductionGuideKind::None);
@ -2115,7 +2115,7 @@ protected:
QualType T, TypeSourceInfo *TInfo, StorageClass SC, QualType T, TypeSourceInfo *TInfo, StorageClass SC,
bool UsesFPIntrin, bool isInline, bool UsesFPIntrin, bool isInline,
ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
Expr *TrailingRequiresClause = nullptr) const AssociatedConstraint &TrailingRequiresClause = {})
: FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin, : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin,
isInline, ConstexprKind, TrailingRequiresClause) { isInline, ConstexprKind, TrailingRequiresClause) {
if (EndLocation.isValid()) if (EndLocation.isValid())
@ -2128,7 +2128,7 @@ public:
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
StorageClass SC, bool UsesFPIntrin, bool isInline, StorageClass SC, bool UsesFPIntrin, bool isInline,
ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
Expr *TrailingRequiresClause = nullptr); const AssociatedConstraint &TrailingRequiresClause = {});
static CXXMethodDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); static CXXMethodDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
@ -2596,7 +2596,7 @@ class CXXConstructorDecl final
bool UsesFPIntrin, bool isInline, bool UsesFPIntrin, bool isInline,
bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
InheritedConstructor Inherited, InheritedConstructor Inherited,
Expr *TrailingRequiresClause); const AssociatedConstraint &TrailingRequiresClause);
void anchor() override; void anchor() override;
@ -2639,7 +2639,7 @@ public:
ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline,
bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
InheritedConstructor Inherited = InheritedConstructor(), InheritedConstructor Inherited = InheritedConstructor(),
Expr *TrailingRequiresClause = nullptr); const AssociatedConstraint &TrailingRequiresClause = {});
void setExplicitSpecifier(ExplicitSpecifier ES) { void setExplicitSpecifier(ExplicitSpecifier ES) {
assert((!ES.getExpr() || assert((!ES.getExpr() ||
@ -2859,7 +2859,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
const DeclarationNameInfo &NameInfo, QualType T, const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, bool UsesFPIntrin, bool isInline, TypeSourceInfo *TInfo, bool UsesFPIntrin, bool isInline,
bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
Expr *TrailingRequiresClause = nullptr) const AssociatedConstraint &TrailingRequiresClause = {})
: CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo, : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo,
SC_None, UsesFPIntrin, isInline, ConstexprKind, SC_None, UsesFPIntrin, isInline, ConstexprKind,
SourceLocation(), TrailingRequiresClause) { SourceLocation(), TrailingRequiresClause) {
@ -2874,7 +2874,7 @@ public:
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared, bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared,
ConstexprSpecKind ConstexprKind, ConstexprSpecKind ConstexprKind,
Expr *TrailingRequiresClause = nullptr); const AssociatedConstraint &TrailingRequiresClause = {});
static CXXDestructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); static CXXDestructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
void setOperatorDelete(FunctionDecl *OD, Expr *ThisArg); void setOperatorDelete(FunctionDecl *OD, Expr *ThisArg);
@ -2925,7 +2925,7 @@ class CXXConversionDecl : public CXXMethodDecl {
TypeSourceInfo *TInfo, bool UsesFPIntrin, bool isInline, TypeSourceInfo *TInfo, bool UsesFPIntrin, bool isInline,
ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind, ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind,
SourceLocation EndLocation, SourceLocation EndLocation,
Expr *TrailingRequiresClause = nullptr) const AssociatedConstraint &TrailingRequiresClause = {})
: CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo, : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
SC_None, UsesFPIntrin, isInline, ConstexprKind, SC_None, UsesFPIntrin, isInline, ConstexprKind,
EndLocation, TrailingRequiresClause), EndLocation, TrailingRequiresClause),
@ -2943,7 +2943,7 @@ public:
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES,
ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
Expr *TrailingRequiresClause = nullptr); const AssociatedConstraint &TrailingRequiresClause = {});
static CXXConversionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); static CXXConversionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
ExplicitSpecifier getExplicitSpecifier() { ExplicitSpecifier getExplicitSpecifier() {

View File

@ -2129,7 +2129,7 @@ public:
ArrayRef<NamedDecl *> getExplicitTemplateParameters() const; ArrayRef<NamedDecl *> getExplicitTemplateParameters() const;
/// Get the trailing requires clause, if any. /// Get the trailing requires clause, if any.
Expr *getTrailingRequiresClause() const; const AssociatedConstraint &getTrailingRequiresClause() const;
/// Whether this is a generic lambda. /// Whether this is a generic lambda.
bool isGenericLambda() const { return getTemplateParameterList(); } bool isGenericLambda() const { return getTemplateParameterList(); }

View File

@ -2253,8 +2253,10 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
} }
// Visit the trailing requires clause, if any. // Visit the trailing requires clause, if any.
if (Expr *TrailingRequiresClause = D->getTrailingRequiresClause()) { if (const AssociatedConstraint &TrailingRequiresClause =
TRY_TO(TraverseStmt(TrailingRequiresClause)); D->getTrailingRequiresClause()) {
TRY_TO(TraverseStmt(
const_cast<Expr *>(TrailingRequiresClause.ConstraintExpr)));
} }
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
@ -2768,7 +2770,8 @@ DEF_TRAVERSE_STMT(LambdaExpr, {
if (S->hasExplicitResultType()) if (S->hasExplicitResultType())
TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); TRY_TO(TraverseTypeLoc(Proto.getReturnLoc()));
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getTrailingRequiresClause()); TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(
const_cast<Expr *>(S->getTrailingRequiresClause().ConstraintExpr));
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody()); TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody());
} }

View File

@ -8867,12 +8867,14 @@ public:
CXXMethodDecl *CallOperator, CXXRecordDecl *Class, CXXMethodDecl *CallOperator, CXXRecordDecl *Class,
TemplateParameterList *TemplateParams); TemplateParameterList *TemplateParams);
void CompleteLambdaCallOperator( void
CXXMethodDecl *Method, SourceLocation LambdaLoc, CompleteLambdaCallOperator(CXXMethodDecl *Method, SourceLocation LambdaLoc,
SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause, SourceLocation CallOperatorLoc,
TypeSourceInfo *MethodTyInfo, ConstexprSpecKind ConstexprKind, const AssociatedConstraint &TrailingRequiresClause,
StorageClass SC, ArrayRef<ParmVarDecl *> Params, TypeSourceInfo *MethodTyInfo,
bool HasExplicitResultType); ConstexprSpecKind ConstexprKind, StorageClass SC,
ArrayRef<ParmVarDecl *> Params,
bool HasExplicitResultType);
/// Returns true if the explicit object parameter was invalid. /// Returns true if the explicit object parameter was invalid.
bool DiagnoseInvalidExplicitObjectParameterInLambda(CXXMethodDecl *Method, bool DiagnoseInvalidExplicitObjectParameterInLambda(CXXMethodDecl *Method,

View File

@ -7070,6 +7070,15 @@ bool ASTContext::hasSameTemplateName(const TemplateName &X,
getCanonicalTemplateName(Y, IgnoreDeduced); getCanonicalTemplateName(Y, IgnoreDeduced);
} }
bool ASTContext::isSameAssociatedConstraint(
const AssociatedConstraint &ACX, const AssociatedConstraint &ACY) const {
if (ACX.ArgumentPackSubstitutionIndex != ACY.ArgumentPackSubstitutionIndex)
return false;
if (!isSameConstraintExpr(ACX.ConstraintExpr, ACY.ConstraintExpr))
return false;
return true;
}
bool ASTContext::isSameConstraintExpr(const Expr *XCE, const Expr *YCE) const { bool ASTContext::isSameConstraintExpr(const Expr *XCE, const Expr *YCE) const {
if (!XCE != !YCE) if (!XCE != !YCE)
return false; return false;
@ -7386,8 +7395,8 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const {
return false; return false;
} }
if (!isSameConstraintExpr(FuncX->getTrailingRequiresClause(), if (!isSameAssociatedConstraint(FuncX->getTrailingRequiresClause(),
FuncY->getTrailingRequiresClause())) FuncY->getTrailingRequiresClause()))
return false; return false;
auto GetTypeAsWritten = [](const FunctionDecl *FD) { auto GetTypeAsWritten = [](const FunctionDecl *FD) {

View File

@ -3915,8 +3915,9 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
auto ToEndLoc = importChecked(Err, D->getEndLoc()); auto ToEndLoc = importChecked(Err, D->getEndLoc());
auto ToDefaultLoc = importChecked(Err, D->getDefaultLoc()); auto ToDefaultLoc = importChecked(Err, D->getDefaultLoc());
auto ToQualifierLoc = importChecked(Err, D->getQualifierLoc()); auto ToQualifierLoc = importChecked(Err, D->getQualifierLoc());
auto TrailingRequiresClause = AssociatedConstraint TrailingRequiresClause = D->getTrailingRequiresClause();
importChecked(Err, D->getTrailingRequiresClause()); TrailingRequiresClause.ConstraintExpr =
importChecked(Err, TrailingRequiresClause.ConstraintExpr);
if (Err) if (Err)
return std::move(Err); return std::move(Err);

View File

@ -2009,8 +2009,8 @@ void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
} }
} }
void DeclaratorDecl::setTrailingRequiresClause(Expr *TrailingRequiresClause) { void DeclaratorDecl::setTrailingRequiresClause(const AssociatedConstraint &AC) {
assert(TrailingRequiresClause); assert(AC);
// Make sure the extended decl info is allocated. // Make sure the extended decl info is allocated.
if (!hasExtInfo()) { if (!hasExtInfo()) {
// Save (non-extended) type source info pointer. // Save (non-extended) type source info pointer.
@ -2021,7 +2021,7 @@ void DeclaratorDecl::setTrailingRequiresClause(Expr *TrailingRequiresClause) {
getExtInfo()->TInfo = savedTInfo; getExtInfo()->TInfo = savedTInfo;
} }
// Set requires clause info. // Set requires clause info.
getExtInfo()->TrailingRequiresClause = TrailingRequiresClause; getExtInfo()->TrailingRequiresClause = AC;
} }
void DeclaratorDecl::setTemplateParameterListsInfo( void DeclaratorDecl::setTemplateParameterListsInfo(
@ -3047,7 +3047,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
TypeSourceInfo *TInfo, StorageClass S, TypeSourceInfo *TInfo, StorageClass S,
bool UsesFPIntrin, bool isInlineSpecified, bool UsesFPIntrin, bool isInlineSpecified,
ConstexprSpecKind ConstexprKind, ConstexprSpecKind ConstexprKind,
Expr *TrailingRequiresClause) const AssociatedConstraint &TrailingRequiresClause)
: DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
StartLoc), StartLoc),
DeclContext(DK), redeclarable_base(C), Body(), ODRHash(0), DeclContext(DK), redeclarable_base(C), Body(), ODRHash(0),
@ -3571,7 +3571,7 @@ bool FunctionDecl::isMemberLikeConstrainedFriend() const {
// If these friends don't have constraints, they aren't constrained, and // If these friends don't have constraints, they aren't constrained, and
// thus don't fall under temp.friend p9. Else the simple presence of a // thus don't fall under temp.friend p9. Else the simple presence of a
// constraint makes them unique. // constraint makes them unique.
return getTrailingRequiresClause(); return !getTrailingRequiresClause().isNull();
} }
return FriendConstraintRefersToEnclosingTemplate(); return FriendConstraintRefersToEnclosingTemplate();
@ -5453,7 +5453,7 @@ FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin, TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin,
bool isInlineSpecified, bool hasWrittenPrototype, bool isInlineSpecified, bool hasWrittenPrototype,
ConstexprSpecKind ConstexprKind, ConstexprSpecKind ConstexprKind,
Expr *TrailingRequiresClause) { const AssociatedConstraint &TrailingRequiresClause) {
FunctionDecl *New = new (C, DC) FunctionDecl( FunctionDecl *New = new (C, DC) FunctionDecl(
Function, C, DC, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin, Function, C, DC, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin,
isInlineSpecified, ConstexprKind, TrailingRequiresClause); isInlineSpecified, ConstexprKind, TrailingRequiresClause);
@ -5464,7 +5464,8 @@ FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
return new (C, ID) FunctionDecl( return new (C, ID) FunctionDecl(
Function, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), Function, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(),
nullptr, SC_None, false, false, ConstexprSpecKind::Unspecified, nullptr); nullptr, SC_None, false, false, ConstexprSpecKind::Unspecified,
/*TrailingRequiresClause=*/{});
} }
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {

View File

@ -2304,7 +2304,7 @@ CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
ASTContext &C, DeclContext *DC, SourceLocation StartLoc, ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T, ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, SourceLocation EndLocation, CXXConstructorDecl *Ctor, TypeSourceInfo *TInfo, SourceLocation EndLocation, CXXConstructorDecl *Ctor,
DeductionCandidate Kind, Expr *TrailingRequiresClause, DeductionCandidate Kind, const AssociatedConstraint &TrailingRequiresClause,
const CXXDeductionGuideDecl *GeneratedFrom, const CXXDeductionGuideDecl *GeneratedFrom,
SourceDeductionGuideKind SourceKind) { SourceDeductionGuideKind SourceKind) {
return new (C, DC) CXXDeductionGuideDecl( return new (C, DC) CXXDeductionGuideDecl(
@ -2318,7 +2318,7 @@ CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
C, /*DC=*/nullptr, SourceLocation(), ExplicitSpecifier(), C, /*DC=*/nullptr, SourceLocation(), ExplicitSpecifier(),
DeclarationNameInfo(), QualType(), /*TInfo=*/nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), /*TInfo=*/nullptr, SourceLocation(),
/*Ctor=*/nullptr, DeductionCandidate::Normal, /*Ctor=*/nullptr, DeductionCandidate::Normal,
/*TrailingRequiresClause=*/nullptr, /*TrailingRequiresClause=*/{},
/*GeneratedFrom=*/nullptr, SourceDeductionGuideKind::None); /*GeneratedFrom=*/nullptr, SourceDeductionGuideKind::None);
} }
@ -2427,7 +2427,7 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin, TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin,
bool isInline, ConstexprSpecKind ConstexprKind, bool isInline, ConstexprSpecKind ConstexprKind,
SourceLocation EndLocation, SourceLocation EndLocation,
Expr *TrailingRequiresClause) { const AssociatedConstraint &TrailingRequiresClause) {
return new (C, RD) CXXMethodDecl( return new (C, RD) CXXMethodDecl(
CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin, CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin,
isInline, ConstexprKind, EndLocation, TrailingRequiresClause); isInline, ConstexprKind, EndLocation, TrailingRequiresClause);
@ -2435,10 +2435,11 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C,
GlobalDeclID ID) { GlobalDeclID ID) {
return new (C, ID) CXXMethodDecl( return new (C, ID)
CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(), CXXMethodDecl(CXXMethod, C, nullptr, SourceLocation(),
QualType(), nullptr, SC_None, false, false, DeclarationNameInfo(), QualType(), nullptr, SC_None, false,
ConstexprSpecKind::Unspecified, SourceLocation(), nullptr); false, ConstexprSpecKind::Unspecified, SourceLocation(),
/*TrailingRequiresClause=*/{});
} }
CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base, CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
@ -2834,7 +2835,8 @@ CXXConstructorDecl::CXXConstructorDecl(
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline,
bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
InheritedConstructor Inherited, Expr *TrailingRequiresClause) InheritedConstructor Inherited,
const AssociatedConstraint &TrailingRequiresClause)
: CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo, : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
SC_None, UsesFPIntrin, isInline, ConstexprKind, SC_None, UsesFPIntrin, isInline, ConstexprKind,
SourceLocation(), TrailingRequiresClause) { SourceLocation(), TrailingRequiresClause) {
@ -2861,7 +2863,7 @@ CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C,
auto *Result = new (C, ID, Extra) CXXConstructorDecl( auto *Result = new (C, ID, Extra) CXXConstructorDecl(
C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
ExplicitSpecifier(), false, false, false, ConstexprSpecKind::Unspecified, ExplicitSpecifier(), false, false, false, ConstexprSpecKind::Unspecified,
InheritedConstructor(), nullptr); InheritedConstructor(), /*TrailingRequiresClause=*/{});
Result->setInheritingConstructor(isInheritingConstructor); Result->setInheritingConstructor(isInheritingConstructor);
Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier = Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier =
hasTrailingExplicit; hasTrailingExplicit;
@ -2874,7 +2876,8 @@ CXXConstructorDecl *CXXConstructorDecl::Create(
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline,
bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
InheritedConstructor Inherited, Expr *TrailingRequiresClause) { InheritedConstructor Inherited,
const AssociatedConstraint &TrailingRequiresClause) {
assert(NameInfo.getName().getNameKind() assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConstructorName && == DeclarationName::CXXConstructorName &&
"Name must refer to a constructor"); "Name must refer to a constructor");
@ -3000,14 +3003,16 @@ CXXDestructorDecl *CXXDestructorDecl::CreateDeserialized(ASTContext &C,
GlobalDeclID ID) { GlobalDeclID ID) {
return new (C, ID) CXXDestructorDecl( return new (C, ID) CXXDestructorDecl(
C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
false, false, false, ConstexprSpecKind::Unspecified, nullptr); false, false, false, ConstexprSpecKind::Unspecified,
/*TrailingRequiresClause=*/{});
} }
CXXDestructorDecl *CXXDestructorDecl::Create( CXXDestructorDecl *CXXDestructorDecl::Create(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared, bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared,
ConstexprSpecKind ConstexprKind, Expr *TrailingRequiresClause) { ConstexprSpecKind ConstexprKind,
const AssociatedConstraint &TrailingRequiresClause) {
assert(NameInfo.getName().getNameKind() assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXDestructorName && == DeclarationName::CXXDestructorName &&
"Name must refer to a destructor"); "Name must refer to a destructor");
@ -3062,7 +3067,7 @@ CXXConversionDecl *CXXConversionDecl::CreateDeserialized(ASTContext &C,
return new (C, ID) CXXConversionDecl( return new (C, ID) CXXConversionDecl(
C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
false, false, ExplicitSpecifier(), ConstexprSpecKind::Unspecified, false, false, ExplicitSpecifier(), ConstexprSpecKind::Unspecified,
SourceLocation(), nullptr); SourceLocation(), /*TrailingRequiresClause=*/{});
} }
CXXConversionDecl *CXXConversionDecl::Create( CXXConversionDecl *CXXConversionDecl::Create(
@ -3070,7 +3075,7 @@ CXXConversionDecl *CXXConversionDecl::Create(
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES,
ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
Expr *TrailingRequiresClause) { const AssociatedConstraint &TrailingRequiresClause) {
assert(NameInfo.getName().getNameKind() assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConversionFunctionName && == DeclarationName::CXXConversionFunctionName &&
"Name must refer to a conversion function"); "Name must refer to a conversion function");

View File

@ -842,10 +842,14 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
} }
Out << Proto; Out << Proto;
if (Expr *TrailingRequiresClause = D->getTrailingRequiresClause()) { if (const AssociatedConstraint &TrailingRequiresClause =
D->getTrailingRequiresClause()) {
Out << " requires "; Out << " requires ";
TrailingRequiresClause->printPretty(Out, nullptr, SubPolicy, Indentation, // FIXME: The printer could support printing expressions and types as if
"\n", &Context); // expanded by an index. Pass in the ArgumentPackSubstitutionIndex when
// that's supported.
TrailingRequiresClause.ConstraintExpr->printPretty(
Out, nullptr, SubPolicy, Indentation, "\n", &Context);
} }
} else { } else {
Ty.print(Out, Policy, Proto); Ty.print(Out, Policy, Proto);

View File

@ -291,7 +291,7 @@ void TemplateDecl::getAssociatedConstraints(
llvm::SmallVectorImpl<AssociatedConstraint> &ACs) const { llvm::SmallVectorImpl<AssociatedConstraint> &ACs) const {
TemplateParams->getAssociatedConstraints(ACs); TemplateParams->getAssociatedConstraints(ACs);
if (auto *FD = dyn_cast_or_null<FunctionDecl>(getTemplatedDecl())) if (auto *FD = dyn_cast_or_null<FunctionDecl>(getTemplatedDecl()))
if (const Expr *TRC = FD->getTrailingRequiresClause()) if (const AssociatedConstraint &TRC = FD->getTrailingRequiresClause())
ACs.emplace_back(TRC); ACs.emplace_back(TRC);
} }
@ -299,7 +299,7 @@ bool TemplateDecl::hasAssociatedConstraints() const {
if (TemplateParams->hasAssociatedConstraints()) if (TemplateParams->hasAssociatedConstraints())
return true; return true;
if (auto *FD = dyn_cast_or_null<FunctionDecl>(getTemplatedDecl())) if (auto *FD = dyn_cast_or_null<FunctionDecl>(getTemplatedDecl()))
return FD->getTrailingRequiresClause(); return static_cast<bool>(FD->getTrailingRequiresClause());
return false; return false;
} }

View File

@ -1402,7 +1402,7 @@ ArrayRef<NamedDecl *> LambdaExpr::getExplicitTemplateParameters() const {
return Record->getLambdaExplicitTemplateParameters(); return Record->getLambdaExplicitTemplateParameters();
} }
Expr *LambdaExpr::getTrailingRequiresClause() const { const AssociatedConstraint &LambdaExpr::getTrailingRequiresClause() const {
return getCallOperator()->getTrailingRequiresClause(); return getCallOperator()->getTrailingRequiresClause();
} }

View File

@ -3781,7 +3781,7 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionProtoType *Proto,
if (FD) { if (FD) {
FunctionTypeDepth.enterResultType(); FunctionTypeDepth.enterResultType();
mangleRequiresClause(FD->getTrailingRequiresClause()); mangleRequiresClause(FD->getTrailingRequiresClause().ConstraintExpr);
} }
FunctionTypeDepth.pop(saved); FunctionTypeDepth.pop(saved);

View File

@ -584,7 +584,8 @@ public:
if (LE->hasExplicitResultType()) if (LE->hasExplicitResultType())
TraverseTypeLoc(Proto.getReturnLoc()); TraverseTypeLoc(Proto.getReturnLoc());
TraverseStmt(LE->getTrailingRequiresClause()); TraverseStmt(
const_cast<Expr *>(LE->getTrailingRequiresClause().ConstraintExpr));
} }
TraverseStmt(LE->getBody()); TraverseStmt(LE->getBody());

View File

@ -132,8 +132,8 @@ public:
} }
} }
} }
if (auto *C = D->getTrailingRequiresClause()) if (const AssociatedConstraint &C = D->getTrailingRequiresClause())
IndexCtx.indexBody(C, Parent); IndexCtx.indexBody(C.ConstraintExpr, Parent);
} }
bool handleObjCMethod(const ObjCMethodDecl *D, bool handleObjCMethod(const ObjCMethodDecl *D,

View File

@ -848,10 +848,8 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
ForOverloadResolution); ForOverloadResolution);
return CheckConstraintSatisfaction( return CheckConstraintSatisfaction(
FD, FD, FD->getTrailingRequiresClause(), *MLTAL,
AssociatedConstraint(FD->getTrailingRequiresClause(), SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
ArgumentPackSubstitutionIndex),
*MLTAL, SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
Satisfaction); Satisfaction);
} }

View File

@ -9353,7 +9353,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC, SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC,
SemaRef.getCurFPFeatures().isFPConstrained(), isInline, HasPrototype, SemaRef.getCurFPFeatures().isFPConstrained(), isInline, HasPrototype,
ConstexprSpecKind::Unspecified, ConstexprSpecKind::Unspecified,
/*TrailingRequiresClause=*/nullptr); /*TrailingRequiresClause=*/{});
if (D.isInvalidType()) if (D.isInvalidType())
NewFD->setInvalidDecl(); NewFD->setInvalidDecl();
@ -9361,7 +9361,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
} }
ExplicitSpecifier ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier(); ExplicitSpecifier ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier();
Expr *TrailingRequiresClause = D.getTrailingRequiresClause(); AssociatedConstraint TrailingRequiresClause(D.getTrailingRequiresClause());
SemaRef.CheckExplicitObjectMemberFunction(DC, D, Name, R); SemaRef.CheckExplicitObjectMemberFunction(DC, D, Name, R);
@ -10531,7 +10531,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
diag::ext_operator_new_delete_declared_inline) diag::ext_operator_new_delete_declared_inline)
<< NewFD->getDeclName(); << NewFD->getDeclName();
if (Expr *TRC = NewFD->getTrailingRequiresClause()) { if (const Expr *TRC = NewFD->getTrailingRequiresClause().ConstraintExpr) {
// C++20 [dcl.decl.general]p4: // C++20 [dcl.decl.general]p4:
// The optional requires-clause in an init-declarator or // The optional requires-clause in an init-declarator or
// member-declarator shall be present only if the declarator declares a // member-declarator shall be present only if the declarator declares a
@ -12261,7 +12261,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (Method->isVirtual() && NewFD->getTrailingRequiresClause()) if (Method->isVirtual() && NewFD->getTrailingRequiresClause())
// C++2a [class.virtual]p6 // C++2a [class.virtual]p6
// A virtual method shall not have a requires-clause. // A virtual method shall not have a requires-clause.
Diag(NewFD->getTrailingRequiresClause()->getBeginLoc(), Diag(NewFD->getTrailingRequiresClause().ConstraintExpr->getBeginLoc(),
diag::err_constrained_virtual_method); diag::err_constrained_virtual_method);
if (Method->isStatic()) if (Method->isStatic())
@ -19085,8 +19085,7 @@ static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record,
SmallVector<bool, 4> SatisfactionStatus; SmallVector<bool, 4> SatisfactionStatus;
for (CXXMethodDecl *Method : Methods) { for (CXXMethodDecl *Method : Methods) {
const Expr *Constraints = Method->getTrailingRequiresClause(); if (!Method->getTrailingRequiresClause())
if (!Constraints)
SatisfactionStatus.push_back(true); SatisfactionStatus.push_back(true);
else { else {
ConstraintSatisfaction Satisfaction; ConstraintSatisfaction Satisfaction;
@ -19105,7 +19104,7 @@ static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record,
if (FunctionDecl *MF = OrigMethod->getInstantiatedFromMemberFunction()) if (FunctionDecl *MF = OrigMethod->getInstantiatedFromMemberFunction())
OrigMethod = cast<CXXMethodDecl>(MF); OrigMethod = cast<CXXMethodDecl>(MF);
const Expr *Constraints = OrigMethod->getTrailingRequiresClause(); AssociatedConstraint Orig = OrigMethod->getTrailingRequiresClause();
bool AnotherMethodIsMoreConstrained = false; bool AnotherMethodIsMoreConstrained = false;
for (size_t j = 0; j < Methods.size(); j++) { for (size_t j = 0; j < Methods.size(); j++) {
if (i == j || !SatisfactionStatus[j]) if (i == j || !SatisfactionStatus[j])
@ -19118,15 +19117,13 @@ static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record,
CSM)) CSM))
continue; continue;
const Expr *OtherConstraints = OtherMethod->getTrailingRequiresClause(); AssociatedConstraint Other = OtherMethod->getTrailingRequiresClause();
if (!OtherConstraints) if (!Other)
continue; continue;
if (!Constraints) { if (!Orig) {
AnotherMethodIsMoreConstrained = true; AnotherMethodIsMoreConstrained = true;
break; break;
} }
AssociatedConstraint Other(OtherConstraints);
AssociatedConstraint Orig(Constraints);
if (S.IsAtLeastAsConstrained(OtherMethod, {Other}, OrigMethod, {Orig}, if (S.IsAtLeastAsConstrained(OtherMethod, {Other}, OrigMethod, {Orig},
AnotherMethodIsMoreConstrained)) { AnotherMethodIsMoreConstrained)) {
// There was an error with the constraints comparison. Exit the loop // There was an error with the constraints comparison. Exit the loop

View File

@ -18995,8 +18995,8 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) {
return true; return true;
// Check the trailing requires clause // Check the trailing requires clause
if (Expr *E = Method->getTrailingRequiresClause()) if (const AssociatedConstraint &TRC = Method->getTrailingRequiresClause())
if (!Finder.TraverseStmt(E)) if (!Finder.TraverseStmt(const_cast<Expr *>(TRC.ConstraintExpr)))
return true; return true;
return checkThisInStaticMemberFunctionAttributes(Method); return checkThisInStaticMemberFunctionAttributes(Method);

View File

@ -990,7 +990,7 @@ private:
followDestructor(dyn_cast<CXXRecordDecl>(Dtor->getParent()), Dtor); followDestructor(dyn_cast<CXXRecordDecl>(Dtor->getParent()), Dtor);
if (auto *FD = dyn_cast<FunctionDecl>(CurrentCaller.CDecl)) { if (auto *FD = dyn_cast<FunctionDecl>(CurrentCaller.CDecl)) {
TrailingRequiresClause = FD->getTrailingRequiresClause(); TrailingRequiresClause = FD->getTrailingRequiresClause().ConstraintExpr;
// Note that FD->getType->getAs<FunctionProtoType>() can yield a // Note that FD->getType->getAs<FunctionProtoType>() can yield a
// noexcept Expr which has been boiled down to a constant expression. // noexcept Expr which has been boiled down to a constant expression.

View File

@ -1015,7 +1015,7 @@ CXXMethodDecl *Sema::CreateLambdaCallOperator(SourceRange IntroducerRange,
QualType(), /*Tinfo=*/nullptr, SC_None, QualType(), /*Tinfo=*/nullptr, SC_None,
getCurFPFeatures().isFPConstrained(), getCurFPFeatures().isFPConstrained(),
/*isInline=*/true, ConstexprSpecKind::Unspecified, SourceLocation(), /*isInline=*/true, ConstexprSpecKind::Unspecified, SourceLocation(),
/*TrailingRequiresClause=*/nullptr); /*TrailingRequiresClause=*/{});
Method->setAccess(AS_public); Method->setAccess(AS_public);
return Method; return Method;
} }
@ -1033,7 +1033,8 @@ void Sema::AddTemplateParametersToLambdaCallOperator(
void Sema::CompleteLambdaCallOperator( void Sema::CompleteLambdaCallOperator(
CXXMethodDecl *Method, SourceLocation LambdaLoc, CXXMethodDecl *Method, SourceLocation LambdaLoc,
SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause, SourceLocation CallOperatorLoc,
const AssociatedConstraint &TrailingRequiresClause,
TypeSourceInfo *MethodTyInfo, ConstexprSpecKind ConstexprKind, TypeSourceInfo *MethodTyInfo, ConstexprSpecKind ConstexprKind,
StorageClass SC, ArrayRef<ParmVarDecl *> Params, StorageClass SC, ArrayRef<ParmVarDecl *> Params,
bool HasExplicitResultType) { bool HasExplicitResultType) {
@ -1461,8 +1462,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
CompleteLambdaCallOperator( CompleteLambdaCallOperator(
Method, Intro.Range.getBegin(), CallOperatorLoc, Method, Intro.Range.getBegin(), CallOperatorLoc,
ParamInfo.getTrailingRequiresClause(), MethodTyInfo, AssociatedConstraint(ParamInfo.getTrailingRequiresClause(),
ParamInfo.getDeclSpec().getConstexprSpecifier(), /*ArgumentPackSubstitutionIndex=*/-1),
MethodTyInfo, ParamInfo.getDeclSpec().getConstexprSpecifier(),
IsLambdaStatic ? SC_Static : SC_None, Params, ExplicitResultType); IsLambdaStatic ? SC_Static : SC_None, Params, ExplicitResultType);
CheckCXXDefaultArguments(Method); CheckCXXDefaultArguments(Method);
@ -1545,7 +1547,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// The optional requires-clause ([temp.pre]) in an init-declarator or // The optional requires-clause ([temp.pre]) in an init-declarator or
// member-declarator shall be present only if the declarator declares a // member-declarator shall be present only if the declarator declares a
// templated function ([dcl.fct]). // templated function ([dcl.fct]).
if (Expr *TRC = Method->getTrailingRequiresClause()) { if (const AssociatedConstraint &TRC = Method->getTrailingRequiresClause()) {
// [temp.pre]/8: // [temp.pre]/8:
// An entity is templated if it is // An entity is templated if it is
// - a template, // - a template,
@ -1568,7 +1570,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// applies to the call operator, which we already know is a member function, // applies to the call operator, which we already know is a member function,
// AND defined. // AND defined.
if (!Method->getDescribedFunctionTemplate() && !Method->isTemplated()) { if (!Method->getDescribedFunctionTemplate() && !Method->isTemplated()) {
Diag(TRC->getBeginLoc(), diag::err_constrained_non_templated_function); Diag(TRC.ConstraintExpr->getBeginLoc(),
diag::err_constrained_non_templated_function);
} }
} }
@ -1791,7 +1794,8 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
// A non-generic lambda may still be a templated entity. We need to preserve // A non-generic lambda may still be a templated entity. We need to preserve
// constraints when converting the lambda to a function pointer. See GH63181. // constraints when converting the lambda to a function pointer. See GH63181.
if (Expr *Requires = CallOperator->getTrailingRequiresClause()) if (const AssociatedConstraint &Requires =
CallOperator->getTrailingRequiresClause())
Conversion->setTrailingRequiresClause(Requires); Conversion->setTrailingRequiresClause(Requires);
if (Class->isGenericLambda()) { if (Class->isGenericLambda()) {

View File

@ -1551,12 +1551,16 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
if (!UseOverrideRules && if (!UseOverrideRules &&
New->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) { New->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) {
Expr *NewRC = New->getTrailingRequiresClause(), AssociatedConstraint NewRC = New->getTrailingRequiresClause(),
*OldRC = Old->getTrailingRequiresClause(); OldRC = Old->getTrailingRequiresClause();
if ((NewRC != nullptr) != (OldRC != nullptr)) if (!NewRC != !OldRC)
return true;
if (NewRC.ArgumentPackSubstitutionIndex !=
OldRC.ArgumentPackSubstitutionIndex)
return true; return true;
if (NewRC && if (NewRC &&
!SemaRef.AreConstraintExpressionsEqual(OldDecl, OldRC, NewDecl, NewRC)) !SemaRef.AreConstraintExpressionsEqual(OldDecl, OldRC.ConstraintExpr,
NewDecl, NewRC.ConstraintExpr))
return true; return true;
} }

View File

@ -200,7 +200,7 @@ buildDeductionGuide(Sema &SemaRef, TemplateDecl *OriginalTemplate,
TypeSourceInfo *TInfo, SourceLocation LocStart, TypeSourceInfo *TInfo, SourceLocation LocStart,
SourceLocation Loc, SourceLocation LocEnd, bool IsImplicit, SourceLocation Loc, SourceLocation LocEnd, bool IsImplicit,
llvm::ArrayRef<TypedefNameDecl *> MaterializedTypedefs = {}, llvm::ArrayRef<TypedefNameDecl *> MaterializedTypedefs = {},
Expr *FunctionTrailingRC = nullptr) { const AssociatedConstraint &FunctionTrailingRC = {}) {
DeclContext *DC = OriginalTemplate->getDeclContext(); DeclContext *DC = OriginalTemplate->getDeclContext();
auto DeductionGuideName = auto DeductionGuideName =
SemaRef.Context.DeclarationNames.getCXXDeductionGuideName( SemaRef.Context.DeclarationNames.getCXXDeductionGuideName(
@ -356,7 +356,8 @@ struct ConvertConstructorToDeductionGuideTransform {
TemplateParameterList *TemplateParams = TemplateParameterList *TemplateParams =
SemaRef.GetTemplateParameterList(Template); SemaRef.GetTemplateParameterList(Template);
SmallVector<TemplateArgument, 16> Depth1Args; SmallVector<TemplateArgument, 16> Depth1Args;
Expr *OuterRC = TemplateParams->getRequiresClause(); AssociatedConstraint OuterRC(TemplateParams->getRequiresClause(),
/*ArgumentPackSubstitutionIndex=*/-1);
if (FTD) { if (FTD) {
TemplateParameterList *InnerParams = FTD->getTemplateParameters(); TemplateParameterList *InnerParams = FTD->getTemplateParameters();
SmallVector<NamedDecl *, 16> AllParams; SmallVector<NamedDecl *, 16> AllParams;
@ -456,18 +457,20 @@ struct ConvertConstructorToDeductionGuideTransform {
// At this point, the function parameters are already 'instantiated' in the // At this point, the function parameters are already 'instantiated' in the
// current scope. Substitute into the constructor's trailing // current scope. Substitute into the constructor's trailing
// requires-clause, if any. // requires-clause, if any.
Expr *FunctionTrailingRC = nullptr; AssociatedConstraint FunctionTrailingRC;
if (Expr *RC = CD->getTrailingRequiresClause()) { if (const AssociatedConstraint &RC = CD->getTrailingRequiresClause()) {
MultiLevelTemplateArgumentList Args; MultiLevelTemplateArgumentList Args;
Args.setKind(TemplateSubstitutionKind::Rewrite); Args.setKind(TemplateSubstitutionKind::Rewrite);
Args.addOuterTemplateArguments(Depth1Args); Args.addOuterTemplateArguments(Depth1Args);
Args.addOuterRetainedLevel(); Args.addOuterRetainedLevel();
if (NestedPattern) if (NestedPattern)
Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth()); Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth());
ExprResult E = SemaRef.SubstConstraintExprWithoutSatisfaction(RC, Args); ExprResult E = SemaRef.SubstConstraintExprWithoutSatisfaction(
const_cast<Expr *>(RC.ConstraintExpr), Args);
if (!E.isUsable()) if (!E.isUsable())
return nullptr; return nullptr;
FunctionTrailingRC = E.get(); FunctionTrailingRC =
AssociatedConstraint(E.get(), RC.ArgumentPackSubstitutionIndex);
} }
// C++ [over.match.class.deduct]p1: // C++ [over.match.class.deduct]p1:
@ -480,13 +483,19 @@ struct ConvertConstructorToDeductionGuideTransform {
if (OuterRC) { if (OuterRC) {
// The outer template parameters are not transformed, so their // The outer template parameters are not transformed, so their
// associated constraints don't need substitution. // associated constraints don't need substitution.
// FIXME: Should simply add another field for the OuterRC, instead of
// combining them like this.
if (!FunctionTrailingRC) if (!FunctionTrailingRC)
FunctionTrailingRC = OuterRC; FunctionTrailingRC = OuterRC;
else else
FunctionTrailingRC = BinaryOperator::Create( FunctionTrailingRC = AssociatedConstraint(
SemaRef.Context, /*lhs=*/OuterRC, /*rhs=*/FunctionTrailingRC, BinaryOperator::Create(
BO_LAnd, SemaRef.Context.BoolTy, VK_PRValue, OK_Ordinary, SemaRef.Context,
TemplateParams->getTemplateLoc(), FPOptionsOverride()); /*lhs=*/const_cast<Expr *>(OuterRC.ConstraintExpr),
/*rhs=*/const_cast<Expr *>(FunctionTrailingRC.ConstraintExpr),
BO_LAnd, SemaRef.Context.BoolTy, VK_PRValue, OK_Ordinary,
TemplateParams->getTemplateLoc(), FPOptionsOverride()),
FunctionTrailingRC.ArgumentPackSubstitutionIndex);
} }
return buildDeductionGuide( return buildDeductionGuide(
@ -1238,14 +1247,20 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
// FIXME: Here the synthesized deduction guide is not a templated // FIXME: Here the synthesized deduction guide is not a templated
// function. Per [dcl.decl]p4, the requires-clause shall be present only // function. Per [dcl.decl]p4, the requires-clause shall be present only
// if the declarator declares a templated function, a bug in standard? // if the declarator declares a templated function, a bug in standard?
auto *Constraint = buildIsDeducibleConstraint( AssociatedConstraint Constraint(
SemaRef, AliasTemplate, Transformed->getReturnType(), {}); buildIsDeducibleConstraint(SemaRef, AliasTemplate,
if (auto *RC = DG->getTrailingRequiresClause()) { Transformed->getReturnType(), {}),
auto Conjunction = /*ArgumentPackSubstitutionIndex=*/-1);
SemaRef.BuildBinOp(SemaRef.getCurScope(), SourceLocation{}, if (const AssociatedConstraint &RC = DG->getTrailingRequiresClause()) {
BinaryOperatorKind::BO_LAnd, RC, Constraint); auto Conjunction = SemaRef.BuildBinOp(
if (!Conjunction.isInvalid()) SemaRef.getCurScope(), SourceLocation{},
Constraint = Conjunction.getAs<Expr>(); BinaryOperatorKind::BO_LAnd, const_cast<Expr *>(RC.ConstraintExpr),
const_cast<Expr *>(Constraint.ConstraintExpr));
if (!Conjunction.isInvalid()) {
Constraint.ConstraintExpr = Conjunction.getAs<Expr>();
Constraint.ArgumentPackSubstitutionIndex =
RC.ArgumentPackSubstitutionIndex;
}
} }
Transformed->setTrailingRequiresClause(Constraint); Transformed->setTrailingRequiresClause(Constraint);
continue; continue;

View File

@ -2671,7 +2671,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
return nullptr; return nullptr;
} }
Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); AssociatedConstraint TrailingRequiresClause = D->getTrailingRequiresClause();
// If we're instantiating a local function declaration, put the result // If we're instantiating a local function declaration, put the result
// in the enclosing namespace; otherwise we need to find the instantiated // in the enclosing namespace; otherwise we need to find the instantiated
@ -3102,7 +3102,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
} }
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); AssociatedConstraint TrailingRequiresClause = D->getTrailingRequiresClause();
DeclarationNameInfo NameInfo DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);

View File

@ -15659,10 +15659,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
auto FPTL = NewCallOpTSI->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>(); auto FPTL = NewCallOpTSI->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>();
assert(FPTL && "Not a FunctionProtoType?"); assert(FPTL && "Not a FunctionProtoType?");
AssociatedConstraint TRC = E->getCallOperator()->getTrailingRequiresClause();
if (TRC.ArgumentPackSubstitutionIndex == -1)
TRC.ArgumentPackSubstitutionIndex = SemaRef.ArgumentPackSubstitutionIndex;
getSema().CompleteLambdaCallOperator( getSema().CompleteLambdaCallOperator(
NewCallOperator, E->getCallOperator()->getLocation(), NewCallOperator, E->getCallOperator()->getLocation(),
E->getCallOperator()->getInnerLocStart(), E->getCallOperator()->getInnerLocStart(), TRC, NewCallOpTSI,
E->getCallOperator()->getTrailingRequiresClause(), NewCallOpTSI,
E->getCallOperator()->getConstexprKind(), E->getCallOperator()->getConstexprKind(),
E->getCallOperator()->getStorageClass(), FPTL.getParams(), E->getCallOperator()->getStorageClass(), FPTL.getParams(),
E->hasExplicitResultType()); E->hasExplicitResultType());

View File

@ -904,7 +904,8 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
if (Record.readInt()) { // hasExtInfo if (Record.readInt()) { // hasExtInfo
auto *Info = new (Reader.getContext()) DeclaratorDecl::ExtInfo(); auto *Info = new (Reader.getContext()) DeclaratorDecl::ExtInfo();
Record.readQualifierInfo(*Info); Record.readQualifierInfo(*Info);
Info->TrailingRequiresClause = Record.readExpr(); Info->TrailingRequiresClause =
AssociatedConstraint(Record.readExpr(), int(Record.readInt()));
DD->DeclInfo = Info; DD->DeclInfo = Info;
} }
QualType TSIType = Record.readType(); QualType TSIType = Record.readType();

View File

@ -728,7 +728,10 @@ void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
if (D->hasExtInfo()) { if (D->hasExtInfo()) {
DeclaratorDecl::ExtInfo *Info = D->getExtInfo(); DeclaratorDecl::ExtInfo *Info = D->getExtInfo();
Record.AddQualifierInfo(*Info); Record.AddQualifierInfo(*Info);
Record.AddStmt(Info->TrailingRequiresClause); Record.AddStmt(
const_cast<Expr *>(Info->TrailingRequiresClause.ConstraintExpr));
Record.push_back(
Info->TrailingRequiresClause.ArgumentPackSubstitutionIndex);
} }
// The location information is deferred until the end of the record. // The location information is deferred until the end of the record.
Record.AddTypeRef(D->getTypeSourceInfo() ? D->getTypeSourceInfo()->getType() Record.AddTypeRef(D->getTypeSourceInfo() ? D->getTypeSourceInfo()->getType()

View File

@ -267,6 +267,15 @@ static_assert(bazz<1, 2>()(1));
// expected-error@-1 {{is ambiguous}} // expected-error@-1 {{is ambiguous}}
// expected-note@#bazz 2{{candidate function [with value:auto = int]}} // expected-note@#bazz 2{{candidate function [with value:auto = int]}}
template <class T> concept C2 = sizeof(T) >= sizeof(int);
template <class... Ts> static constexpr auto trailing() {
return Overloaded{[](auto) requires (C2<Ts> && C2<int>) { return 0; }...}; // #trailing
}
static_assert(trailing<int, long>()(0));
// expected-error@-1 {{is ambiguous}}
// expected-note@#trailing 2{{candidate function [with auto:1 = int]}}
} // namespace GH101754 } // namespace GH101754
namespace GH131798 { namespace GH131798 {

View File

@ -872,7 +872,7 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
// FIXME: Attributes? // FIXME: Attributes?
} }
if (auto *E = ND->getTrailingRequiresClause()) { if (auto *E = ND->getTrailingRequiresClause().ConstraintExpr) {
if (Visit(E)) if (Visit(E))
return true; return true;
} }