diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h index 2a64326e8604b8..271d487e2fc9ba 100644 --- a/clang/include/clang/AST/ExprConcepts.h +++ b/clang/include/clang/AST/ExprConcepts.h @@ -63,6 +63,12 @@ class ConceptSpecializationExpr final : public Expr, public ConceptReference, ArrayRef ConvertedArgs, const ConstraintSatisfaction *Satisfaction); + ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept, + ArrayRef ConvertedArgs, + const ConstraintSatisfaction *Satisfaction, + bool Dependent, + bool ContainsUnexpandedParameterPack); + ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs); public: @@ -75,6 +81,13 @@ class ConceptSpecializationExpr final : public Expr, public ConceptReference, ArrayRef ConvertedArgs, const ConstraintSatisfaction *Satisfaction); + static ConceptSpecializationExpr * + Create(const ASTContext &C, ConceptDecl *NamedConcept, + ArrayRef ConvertedArgs, + const ConstraintSatisfaction *Satisfaction, + bool Dependent, + bool ContainsUnexpandedParameterPack); + static ConceptSpecializationExpr * Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 72969490e32d34..c80d3948d00344 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -731,12 +731,8 @@ canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC, NewConverted.push_back(Arg); } Expr *NewIDC = ConceptSpecializationExpr::Create( - C, NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(), - CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(), - CSE->getNamedConcept(), - // Actually canonicalizing a TemplateArgumentLoc is difficult so we - // simply omit the ArgsAsWritten - /*ArgsAsWritten=*/nullptr, NewConverted, nullptr); + C, CSE->getNamedConcept(), NewConverted, nullptr, + CSE->isInstantiationDependent(), CSE->containsUnexpandedParameterPack()); if (auto *OrigFold = dyn_cast(IDC)) NewIDC = new (C) CXXFoldExpr(OrigFold->getType(), SourceLocation(), NewIDC, diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp index 76d57ed5d5b1f9..b5a3686dc99a54 100644 --- a/clang/lib/AST/ExprConcepts.cpp +++ b/clang/lib/AST/ExprConcepts.cpp @@ -46,24 +46,12 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(const ASTContext &C, ASTConstraintSatisfaction::Create(C, *Satisfaction) : nullptr) { setTemplateArguments(ConvertedArgs); -} - -ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty, - unsigned NumTemplateArgs) - : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(), - NumTemplateArgs(NumTemplateArgs) { } - -void ConceptSpecializationExpr::setTemplateArguments( - ArrayRef Converted) { - assert(Converted.size() == NumTemplateArgs); - std::uninitialized_copy(Converted.begin(), Converted.end(), - getTrailingObjects()); bool IsInstantiationDependent = false; bool ContainsUnexpandedParameterPack = false; - for (const TemplateArgument& Arg : Converted) { - if (Arg.isInstantiationDependent()) + for (const TemplateArgumentLoc& ArgLoc : ArgsAsWritten->arguments()) { + if (ArgLoc.getArgument().isInstantiationDependent()) IsInstantiationDependent = true; - if (Arg.containsUnexpandedParameterPack()) + if (ArgLoc.getArgument().containsUnexpandedParameterPack()) ContainsUnexpandedParameterPack = true; if (ContainsUnexpandedParameterPack && IsInstantiationDependent) break; @@ -80,6 +68,18 @@ void ConceptSpecializationExpr::setTemplateArguments( "should not be value-dependent"); } +ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty, + unsigned NumTemplateArgs) + : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(), + NumTemplateArgs(NumTemplateArgs) { } + +void ConceptSpecializationExpr::setTemplateArguments( + ArrayRef Converted) { + assert(Converted.size() == NumTemplateArgs); + std::uninitialized_copy(Converted.begin(), Converted.end(), + getTrailingObjects()); +} + ConceptSpecializationExpr * ConceptSpecializationExpr::Create(const ASTContext &C, NestedNameSpecifierLoc NNS, @@ -98,6 +98,39 @@ ConceptSpecializationExpr::Create(const ASTContext &C, ConvertedArgs, Satisfaction); } +ConceptSpecializationExpr::ConceptSpecializationExpr( + const ASTContext &C, ConceptDecl *NamedConcept, + ArrayRef ConvertedArgs, + const ConstraintSatisfaction *Satisfaction, bool Dependent, + bool ContainsUnexpandedParameterPack) + : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, + /*ValueDependent=*/!Satisfaction, Dependent, + ContainsUnexpandedParameterPack), + ConceptReference(NestedNameSpecifierLoc(), SourceLocation(), + DeclarationNameInfo(), NamedConcept, + NamedConcept, nullptr), + NumTemplateArgs(ConvertedArgs.size()), + Satisfaction(Satisfaction ? + ASTConstraintSatisfaction::Create(C, *Satisfaction) : + nullptr) { + setTemplateArguments(ConvertedArgs); +} + +ConceptSpecializationExpr * +ConceptSpecializationExpr::Create(const ASTContext &C, + ConceptDecl *NamedConcept, + ArrayRef ConvertedArgs, + const ConstraintSatisfaction *Satisfaction, + bool Dependent, + bool ContainsUnexpandedParameterPack) { + void *Buffer = C.Allocate(totalSizeToAlloc( + ConvertedArgs.size())); + return new (Buffer) ConceptSpecializationExpr( + C, NamedConcept, ConvertedArgs, Satisfaction, Dependent, + ContainsUnexpandedParameterPack); +} + ConceptSpecializationExpr * ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs) { diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp index fb3978240af2fc..30ec2a3ab70f7d 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp @@ -183,3 +183,18 @@ concept C8 = sizeof(T) > sizeof(U); template constexpr bool B8 = C8; // expected-error@-1{{pack expansion used as argument for non-pack parameter of concept}} + + +// Make sure we correctly check for containsUnexpandedParameterPack + +template +concept C9 = true; + +template +using invoke = typename Fn::template invoke; + +template +// The converted argument here will not containsUnexpandedParameterPack, but the +// as-written one will. +requires (C9> &&...) +struct S { };