Index: clang/include/clang/AST/ASTNodeTraverser.h =================================================================== --- clang/include/clang/AST/ASTNodeTraverser.h +++ clang/include/clang/AST/ASTNodeTraverser.h @@ -623,7 +623,14 @@ Visit(D->getConstraintExpr()); } + void VisitImplicitConceptSpecializationDecl( + const ImplicitConceptSpecializationDecl *CSD) { + for (const TemplateArgument &Arg : CSD->getTemplateArguments()) + Visit(Arg); + } + void VisitConceptSpecializationExpr(const ConceptSpecializationExpr *CSE) { + Visit(CSE->getSpecializationDecl()); if (CSE->hasExplicitTemplateArgs()) for (const auto &ArgLoc : CSE->getTemplateArgsAsWritten()->arguments()) dumpTemplateArgumentLoc(ArgLoc); Index: clang/include/clang/AST/DeclTemplate.h =================================================================== --- clang/include/clang/AST/DeclTemplate.h +++ clang/include/clang/AST/DeclTemplate.h @@ -3259,7 +3259,7 @@ static bool classofKind(Kind K) { return K == VarTemplate; } }; -/// Declaration of a C++2a concept. +/// Declaration of a C++20 concept. class ConceptDecl : public TemplateDecl, public Mergeable { protected: Expr *ConstraintExpr; @@ -3304,6 +3304,40 @@ friend class ASTDeclWriter; }; +// An implementation detail of ConceptSpecialicationExpr that holds the template +// arguments, so we can later use this to reconstitute the template arguments +// during constraint checking. +class ImplicitConceptSpecializationDecl final + : public Decl, + private llvm::TrailingObjects { + unsigned NumTemplateArgs; + + ImplicitConceptSpecializationDecl(DeclContext *DC, SourceLocation SL, + ArrayRef ConvertedArgs); + ImplicitConceptSpecializationDecl(EmptyShell Empty, unsigned NumTemplateArgs); + +public: + static ImplicitConceptSpecializationDecl * + Create(const ASTContext &C, DeclContext *DC, SourceLocation SL, + ArrayRef ConvertedArgs); + static ImplicitConceptSpecializationDecl * + CreateDeserialized(const ASTContext &C, unsigned ID, + unsigned NumTemplateArgs); + + ArrayRef getTemplateArguments() const { + return ArrayRef(getTrailingObjects(), + NumTemplateArgs); + } + void setTemplateArguments(ArrayRef Converted); + + static bool classofKind(Kind K) { return K == ImplicitConceptSpecialization; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + + friend TrailingObjects; + friend class ASTDeclReader; +}; + /// A template parameter object. /// /// Template parameter objects represent values of class type used as template Index: clang/include/clang/AST/ExprConcepts.h =================================================================== --- clang/include/clang/AST/ExprConcepts.h +++ clang/include/clang/AST/ExprConcepts.h @@ -37,18 +37,16 @@ /// /// According to C++2a [expr.prim.id]p3 an id-expression that denotes the /// specialization of a concept results in a prvalue of type bool. -class ConceptSpecializationExpr final : public Expr, public ConceptReference, - private llvm::TrailingObjects { +class ConceptSpecializationExpr final : public Expr, public ConceptReference { + friend class ASTReader; friend class ASTStmtReader; - friend TrailingObjects; public: using SubstitutionDiagnostic = std::pair; protected: - /// \brief The number of template arguments in the tail-allocated list of - /// converted template arguments. - unsigned NumTemplateArgs; + /// \brief The Implicit Concept Specialization Decl, which holds the template + /// arguments for this specialization. + ImplicitConceptSpecializationDecl *SpecDecl; /// \brief Information about the satisfaction of the named concept with the /// given arguments. If this expression is value dependent, this is to be @@ -60,44 +58,39 @@ DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef ConvertedArgs, + ImplicitConceptSpecializationDecl *SpecDecl, const ConstraintSatisfaction *Satisfaction); ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept, - ArrayRef ConvertedArgs, + ImplicitConceptSpecializationDecl *SpecDecl, const ConstraintSatisfaction *Satisfaction, bool Dependent, bool ContainsUnexpandedParameterPack); - - ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs); + ConceptSpecializationExpr(EmptyShell Empty); public: - static ConceptSpecializationExpr * Create(const ASTContext &C, NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef ConvertedArgs, + ImplicitConceptSpecializationDecl *SpecDecl, const ConstraintSatisfaction *Satisfaction); static ConceptSpecializationExpr * Create(const ASTContext &C, ConceptDecl *NamedConcept, - ArrayRef ConvertedArgs, - const ConstraintSatisfaction *Satisfaction, - bool Dependent, + ImplicitConceptSpecializationDecl *SpecDecl, + const ConstraintSatisfaction *Satisfaction, bool Dependent, bool ContainsUnexpandedParameterPack); - static ConceptSpecializationExpr * - Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs); - ArrayRef getTemplateArguments() const { - return ArrayRef(getTrailingObjects(), - NumTemplateArgs); + return SpecDecl->getTemplateArguments(); } - /// \brief Set new template arguments for this concept specialization. - void setTemplateArguments(ArrayRef Converted); + const ImplicitConceptSpecializationDecl *getSpecializationDecl() const { + assert(SpecDecl && "Template Argument Decl not initialized"); + return SpecDecl; + } /// \brief Whether or not the concept with the given arguments was satisfied /// when the expression was created. Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -2304,6 +2304,11 @@ DEF_TRAVERSE_DECL(RequiresExprBodyDecl, {}) +DEF_TRAVERSE_DECL(ImplicitConceptSpecializationDecl, { + TRY_TO(TraverseTemplateArguments(D->getTemplateArguments().data(), + D->getTemplateArguments().size())); +}) + #undef DEF_TRAVERSE_DECL // ----------------- Stmt traversal ----------------- Index: clang/include/clang/Basic/DeclNodes.td =================================================================== --- clang/include/clang/Basic/DeclNodes.td +++ clang/include/clang/Basic/DeclNodes.td @@ -90,6 +90,7 @@ def ObjCImplementation : DeclNode; def ObjCProperty : DeclNode; def ObjCCompatibleAlias : DeclNode; +def ImplicitConceptSpecialization : DeclNode; def LinkageSpec : DeclNode, DeclContext; def Export : DeclNode, DeclContext; def ObjCPropertyImpl : DeclNode; Index: clang/include/clang/Serialization/ASTBitCodes.h =================================================================== --- clang/include/clang/Serialization/ASTBitCodes.h +++ clang/include/clang/Serialization/ASTBitCodes.h @@ -1514,7 +1514,10 @@ /// A HLSLBufferDecl record. DECL_HLSL_BUFFER, - DECL_LAST = DECL_HLSL_BUFFER + /// An ImplicitConceptSpecializationDecl record. + DECL_IMPLICIT_CONCEPT_SPECIALIZATION, + + DECL_LAST = DECL_IMPLICIT_CONCEPT_SPECIALIZATION }; /// Record codes for each kind of statement or expression. Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -761,9 +761,13 @@ NewConverted.push_back(ConstrainedType); llvm::append_range(NewConverted, OldConverted.drop_front(1)); } + auto *CSD = ImplicitConceptSpecializationDecl::Create( + C, CSE->getNamedConcept()->getDeclContext(), + CSE->getNamedConcept()->getLocation(), NewConverted); + Expr *NewIDC = ConceptSpecializationExpr::Create( - C, CSE->getNamedConcept(), NewConverted, nullptr, - CSE->isInstantiationDependent(), CSE->containsUnexpandedParameterPack()); + C, CSE->getNamedConcept(), CSD, nullptr, CSE->isInstantiationDependent(), + CSE->containsUnexpandedParameterPack()); if (auto *OrigFold = dyn_cast(IDC)) NewIDC = new (C) CXXFoldExpr( Index: clang/lib/AST/DeclBase.cpp =================================================================== --- clang/lib/AST/DeclBase.cpp +++ clang/lib/AST/DeclBase.cpp @@ -874,6 +874,7 @@ case Empty: case LifetimeExtendedTemporary: case RequiresExprBody: + case ImplicitConceptSpecialization: // Never looked up by name. return 0; } Index: clang/lib/AST/DeclTemplate.cpp =================================================================== --- clang/lib/AST/DeclTemplate.cpp +++ clang/lib/AST/DeclTemplate.cpp @@ -1052,6 +1052,44 @@ return Result; } +//===----------------------------------------------------------------------===// +// ImplicitConceptSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +ImplicitConceptSpecializationDecl::ImplicitConceptSpecializationDecl( + DeclContext *DC, SourceLocation SL, + ArrayRef ConvertedArgs) + : Decl(ImplicitConceptSpecialization, DC, SL), + NumTemplateArgs(ConvertedArgs.size()) { + setTemplateArguments(ConvertedArgs); +} + +ImplicitConceptSpecializationDecl::ImplicitConceptSpecializationDecl( + EmptyShell Empty, unsigned NumTemplateArgs) + : Decl(ImplicitConceptSpecialization, Empty), + NumTemplateArgs(NumTemplateArgs) {} + +ImplicitConceptSpecializationDecl *ImplicitConceptSpecializationDecl::Create( + const ASTContext &C, DeclContext *DC, SourceLocation SL, + ArrayRef ConvertedArgs) { + return new (C, DC, + additionalSizeToAlloc(ConvertedArgs.size())) + ImplicitConceptSpecializationDecl(DC, SL, ConvertedArgs); +} + +ImplicitConceptSpecializationDecl * +ImplicitConceptSpecializationDecl::CreateDeserialized( + const ASTContext &C, unsigned ID, unsigned NumTemplateArgs) { + return new (C, ID, additionalSizeToAlloc(NumTemplateArgs)) + ImplicitConceptSpecializationDecl(EmptyShell{}, NumTemplateArgs); +} + +void ImplicitConceptSpecializationDecl::setTemplateArguments( + ArrayRef Converted) { + assert(Converted.size() == NumTemplateArgs); + std::uninitialized_copy(Converted.begin(), Converted.end(), + getTrailingObjects()); +} + //===----------------------------------------------------------------------===// // ClassTemplatePartialSpecializationDecl Implementation //===----------------------------------------------------------------------===// Index: clang/lib/AST/ExprConcepts.cpp =================================================================== --- clang/lib/AST/ExprConcepts.cpp +++ clang/lib/AST/ExprConcepts.cpp @@ -35,16 +35,15 @@ SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef ConvertedArgs, + ImplicitConceptSpecializationDecl *SpecDecl, const ConstraintSatisfaction *Satisfaction) : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary), ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, ArgsAsWritten), - NumTemplateArgs(ConvertedArgs.size()), + SpecDecl(SpecDecl), Satisfaction(Satisfaction ? ASTConstraintSatisfaction::Create(C, *Satisfaction) : nullptr) { - setTemplateArguments(ConvertedArgs); setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction)); // Currently guaranteed by the fact concepts can only be at namespace-scope. @@ -56,50 +55,34 @@ "should not be value-dependent"); } -ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty, - unsigned NumTemplateArgs) - : Expr(ConceptSpecializationExprClass, Empty), - NumTemplateArgs(NumTemplateArgs) {} +ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty) + : Expr(ConceptSpecializationExprClass, Empty) {} -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, - SourceLocation TemplateKWLoc, - DeclarationNameInfo ConceptNameInfo, - NamedDecl *FoundDecl, - ConceptDecl *NamedConcept, - const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef ConvertedArgs, - const ConstraintSatisfaction *Satisfaction) { - void *Buffer = C.Allocate(totalSizeToAlloc( - ConvertedArgs.size())); - return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc, - ConceptNameInfo, FoundDecl, - NamedConcept, ArgsAsWritten, - ConvertedArgs, Satisfaction); +ConceptSpecializationExpr *ConceptSpecializationExpr::Create( + const ASTContext &C, NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, + NamedDecl *FoundDecl, ConceptDecl *NamedConcept, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + ImplicitConceptSpecializationDecl *SpecDecl, + const ConstraintSatisfaction *Satisfaction) { + return new (C) ConceptSpecializationExpr( + C, NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, + ArgsAsWritten, SpecDecl, Satisfaction); } ConceptSpecializationExpr::ConceptSpecializationExpr( const ASTContext &C, ConceptDecl *NamedConcept, - ArrayRef ConvertedArgs, + ImplicitConceptSpecializationDecl *SpecDecl, const ConstraintSatisfaction *Satisfaction, bool Dependent, bool ContainsUnexpandedParameterPack) : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary), ConceptReference(NestedNameSpecifierLoc(), SourceLocation(), DeclarationNameInfo(), NamedConcept, NamedConcept, nullptr), - NumTemplateArgs(ConvertedArgs.size()), + SpecDecl(SpecDecl), Satisfaction(Satisfaction ? ASTConstraintSatisfaction::Create(C, *Satisfaction) : nullptr) { - setTemplateArguments(ConvertedArgs); ExprDependence D = ExprDependence::None; if (!Satisfaction) D |= ExprDependence::Value; @@ -110,26 +93,14 @@ setDependence(D); } -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) { - void *Buffer = C.Allocate(totalSizeToAlloc( - NumTemplateArgs)); - return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs); +ConceptSpecializationExpr *ConceptSpecializationExpr::Create( + const ASTContext &C, ConceptDecl *NamedConcept, + ImplicitConceptSpecializationDecl *SpecDecl, + const ConstraintSatisfaction *Satisfaction, bool Dependent, + bool ContainsUnexpandedParameterPack) { + return new (C) + ConceptSpecializationExpr(C, NamedConcept, SpecDecl, Satisfaction, + Dependent, ContainsUnexpandedParameterPack); } const TypeConstraint * Index: clang/lib/CodeGen/CGDecl.cpp =================================================================== --- clang/lib/CodeGen/CGDecl.cpp +++ clang/lib/CodeGen/CGDecl.cpp @@ -127,6 +127,7 @@ case Decl::OMPRequires: case Decl::Empty: case Decl::Concept: + case Decl::ImplicitConceptSpecialization: case Decl::LifetimeExtendedTemporary: case Decl::RequiresExprBody: // None of these decls require codegen support. Index: clang/lib/Sema/SemaConcept.cpp =================================================================== --- clang/lib/Sema/SemaConcept.cpp +++ clang/lib/Sema/SemaConcept.cpp @@ -265,7 +265,8 @@ return calculateConstraintSatisfaction( S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) { EnterExpressionEvaluationContext ConstantEvaluated( - S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + S, Sema::ExpressionEvaluationContext::ConstantEvaluated, + Sema::ReuseLambdaContextDecl); // Atomic constraint - substitute arguments and check satisfaction. ExprResult SubstitutedExpression; Index: clang/lib/Sema/SemaLambda.cpp =================================================================== --- clang/lib/Sema/SemaLambda.cpp +++ clang/lib/Sema/SemaLambda.cpp @@ -282,7 +282,8 @@ DataMember, StaticDataMember, InlineVariable, - VariableTemplate + VariableTemplate, + Concept } Kind = Normal; // Default arguments of member function parameters that appear in a class @@ -307,6 +308,8 @@ } } else if (isa(ManglingContextDecl)) { Kind = DataMember; + } else if (isa(ManglingContextDecl)) { + Kind = Concept; } } @@ -330,6 +333,11 @@ return std::make_tuple(nullptr, nullptr); } + case Concept: + // Concept definitions aren't code generated and thus aren't mangled, + // however the ManglingContextDecl is important for the purposes of + // re-forming the template argument list of the lambda for constraint + // evaluation. case StaticDataMember: // -- the initializers of nonspecialized static members of template classes if (!IsInNonspecializedTemplate) Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -4866,6 +4866,9 @@ /*UpdateArgsWithConversions=*/false)) return ExprError(); + auto *CSD = ImplicitConceptSpecializationDecl::Create( + Context, NamedConcept->getDeclContext(), NamedConcept->getLocation(), + Converted); ConstraintSatisfaction Satisfaction; bool AreArgsDependent = TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs, @@ -4873,6 +4876,10 @@ MultiLevelTemplateArgumentList MLTAL; MLTAL.addOuterTemplateArguments(NamedConcept, Converted); LocalInstantiationScope Scope(*this); + + EnterExpressionEvaluationContext EECtx{ + *this, ExpressionEvaluationContext::ConstantEvaluated, CSD}; + if (!AreArgsDependent && CheckConstraintSatisfaction( NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL, @@ -4881,10 +4888,11 @@ Satisfaction)) return ExprError(); - return ConceptSpecializationExpr::Create(Context, + return ConceptSpecializationExpr::Create( + Context, SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{}, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, - ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted, + ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), CSD, AreArgsDependent ? nullptr : &Satisfaction); } Index: clang/lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiate.cpp +++ clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -231,6 +231,15 @@ return Response::UseNextDecl(Rec); } +Response HandleImplicitConceptSpecializationDecl( + const ImplicitConceptSpecializationDecl *CSD, + MultiLevelTemplateArgumentList &Result) { + Result.addOuterTemplateArguments( + const_cast(CSD), + CSD->getTemplateArguments()); + return Response::UseNextDecl(CSD); +} + Response HandleGenericDeclContext(const Decl *CurDecl) { return Response::UseNextDecl(CurDecl); } @@ -289,6 +298,9 @@ ForConstraintInstantiation); } else if (const auto *Rec = dyn_cast(CurDecl)) { R = HandleRecordDecl(Rec, Result, Context, ForConstraintInstantiation); + } else if (const auto *CSD = + dyn_cast(CurDecl)) { + R = HandleImplicitConceptSpecializationDecl(CSD, Result); } else if (!isa(CurDecl)) { R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl); if (CurDecl->getDeclContext()->isTranslationUnit()) { Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3965,6 +3965,11 @@ llvm_unreachable("Concept definitions cannot reside inside a template"); } +Decl *TemplateDeclInstantiator::VisitImplicitConceptSpecializationDecl( + ImplicitConceptSpecializationDecl *D) { + llvm_unreachable("Concept specializations cannot reside inside a template"); +} + Decl * TemplateDeclInstantiator::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { return RequiresExprBodyDecl::Create(SemaRef.Context, D->getDeclContext(), Index: clang/lib/Sema/TreeTransform.h =================================================================== --- clang/lib/Sema/TreeTransform.h +++ clang/lib/Sema/TreeTransform.h @@ -12606,7 +12606,8 @@ // C++2a [expr.prim.req]p2 // Expressions appearing within a requirement-body are unevaluated operands. EnterExpressionEvaluationContext Ctx( - SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated, + Sema::ReuseLambdaContextDecl); RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create( getSema().Context, getSema().CurContext, Index: clang/lib/Serialization/ASTCommon.cpp =================================================================== --- clang/lib/Serialization/ASTCommon.cpp +++ clang/lib/Serialization/ASTCommon.cpp @@ -430,6 +430,7 @@ case Decl::Decomposition: case Decl::Binding: case Decl::Concept: + case Decl::ImplicitConceptSpecialization: case Decl::LifetimeExtendedTemporary: case Decl::RequiresExprBody: case Decl::UnresolvedUsingIfExists: Index: clang/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- clang/lib/Serialization/ASTReaderDecl.cpp +++ clang/lib/Serialization/ASTReaderDecl.cpp @@ -384,6 +384,8 @@ void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); void VisitTemplateDecl(TemplateDecl *D); void VisitConceptDecl(ConceptDecl *D); + void VisitImplicitConceptSpecializationDecl( + ImplicitConceptSpecializationDecl *D); void VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D); RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); void VisitClassTemplateDecl(ClassTemplateDecl *D); @@ -2234,6 +2236,17 @@ mergeMergeable(D); } +void ASTDeclReader::VisitImplicitConceptSpecializationDecl( + ImplicitConceptSpecializationDecl *D) { + // The size of the template list was read during creation of the Decl, so we + // don't have to re-read it here. + VisitDecl(D); + llvm::SmallVector Args; + for (unsigned I = 0; I < D->NumTemplateArgs; ++I) + Args.push_back(Record.readTemplateArgument(/*Canonicalize=*/true)); + D->setTemplateArguments(Args); +} + void ASTDeclReader::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { } @@ -3900,6 +3913,10 @@ case DECL_HLSL_BUFFER: D = HLSLBufferDecl::CreateDeserialized(Context, ID); break; + case DECL_IMPLICIT_CONCEPT_SPECIALIZATION: + D = ImplicitConceptSpecializationDecl::CreateDeserialized(Context, ID, + Record.readInt()); + break; } assert(D && "Unknown declaration reading AST file"); Index: clang/lib/Serialization/ASTReaderStmt.cpp =================================================================== --- clang/lib/Serialization/ASTReaderStmt.cpp +++ clang/lib/Serialization/ASTReaderStmt.cpp @@ -794,17 +794,13 @@ void ASTStmtReader::VisitConceptSpecializationExpr( ConceptSpecializationExpr *E) { VisitExpr(E); - unsigned NumTemplateArgs = Record.readInt(); E->NestedNameSpec = Record.readNestedNameSpecifierLoc(); E->TemplateKWLoc = Record.readSourceLocation(); E->ConceptName = Record.readDeclarationNameInfo(); E->NamedConcept = readDeclAs(); E->FoundDecl = Record.readDeclAs(); + E->SpecDecl = Record.readDeclAs(); E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); - llvm::SmallVector Args; - for (unsigned I = 0; I < NumTemplateArgs; ++I) - Args.push_back(Record.readTemplateArgument(/*Canonicalize*/ true)); - E->setTemplateArguments(Args); E->Satisfaction = E->isValueDependent() ? nullptr : ASTConstraintSatisfaction::Create(Record.getContext(), readConstraintSatisfaction(Record)); @@ -4003,8 +3999,7 @@ break; case EXPR_CONCEPT_SPECIALIZATION: { - unsigned numTemplateArgs = Record[ASTStmtReader::NumExprFields]; - S = ConceptSpecializationExpr::Create(Context, Empty, numTemplateArgs); + S = new (Context) ConceptSpecializationExpr(Empty); break; } Index: clang/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- clang/lib/Serialization/ASTWriterDecl.cpp +++ clang/lib/Serialization/ASTWriterDecl.cpp @@ -107,6 +107,8 @@ void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); void VisitTemplateDecl(TemplateDecl *D); void VisitConceptDecl(ConceptDecl *D); + void VisitImplicitConceptSpecializationDecl( + ImplicitConceptSpecializationDecl *D); void VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D); void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); void VisitClassTemplateDecl(ClassTemplateDecl *D); @@ -1517,6 +1519,15 @@ Code = serialization::DECL_CONCEPT; } +void ASTDeclWriter::VisitImplicitConceptSpecializationDecl( + ImplicitConceptSpecializationDecl *D) { + Record.push_back(D->getTemplateArguments().size()); + VisitDecl(D); + for (const TemplateArgument &Arg : D->getTemplateArguments()) + Record.AddTemplateArgument(Arg); + Code = serialization::DECL_IMPLICIT_CONCEPT_SPECIALIZATION; +} + void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { Code = serialization::DECL_REQUIRES_EXPR_BODY; } Index: clang/lib/Serialization/ASTWriterStmt.cpp =================================================================== --- clang/lib/Serialization/ASTWriterStmt.cpp +++ clang/lib/Serialization/ASTWriterStmt.cpp @@ -433,16 +433,13 @@ void ASTStmtWriter::VisitConceptSpecializationExpr( ConceptSpecializationExpr *E) { VisitExpr(E); - ArrayRef TemplateArgs = E->getTemplateArguments(); - Record.push_back(TemplateArgs.size()); Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc()); Record.AddSourceLocation(E->getTemplateKWLoc()); Record.AddDeclarationNameInfo(E->getConceptNameInfo()); Record.AddDeclRef(E->getNamedConcept()); Record.AddDeclRef(E->getFoundDecl()); + Record.AddDeclRef(E->getSpecializationDecl()); Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten()); - for (const TemplateArgument &Arg : TemplateArgs) - Record.AddTemplateArgument(Arg); if (!E->isValueDependent()) addConstraintSatisfaction(Record, E->getSatisfaction()); Index: clang/test/AST/ast-dump-concepts.cpp =================================================================== --- clang/test/AST/ast-dump-concepts.cpp +++ clang/test/AST/ast-dump-concepts.cpp @@ -19,6 +19,11 @@ struct Foo { // CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'binary_concept' // CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} 'bool' Concept {{.*}} 'binary_concept' + // CHECK-NEXT: |-ConceptSpecializationDecl {{.*}} col:9 + // CHECK-NEXT: | |-TemplateArgument type 'type-parameter-1-0' + // CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent {{.*}}depth 1 index 0 + // CHECK-NEXT: | `-TemplateArgument type 'int' + // CHECK-NEXT: | `-BuiltinType {{.*}} 'int' // CHECK-NEXT: |-TemplateArgument {{.*}} type 'R' // CHECK-NEXT: | `-TemplateTypeParmType {{.*}} 'R' // CHECK-NEXT: | `-TemplateTypeParm {{.*}} 'R' @@ -29,6 +34,9 @@ // CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'unary_concept' // CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} 'bool' + // CHECK-NEXT: |-ConceptSpecializationDecl {{.*}} col:9 + // CHECK-NEXT: | `-TemplateArgument type 'type-parameter-1-0' + // CHECK-NEXT: | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent {{.*}}depth 1 index 0 template Foo(R); Index: clang/test/SemaTemplate/concepts-lambda.cpp =================================================================== --- clang/test/SemaTemplate/concepts-lambda.cpp +++ clang/test/SemaTemplate/concepts-lambda.cpp @@ -55,3 +55,39 @@ using function_ptr = void(*)(int); function_ptr ptr = f; } + +// GH58368: A lambda defined in a concept requires we store +// the concept as a part of the lambda context. +namespace LambdaInConcept { +using size_t = unsigned long; + +template +struct IdxSeq{}; + +template +concept NotLike = true; + +template +struct AnyExcept { + template T> operator T&() const; + template T> operator T&&() const; +}; + +template + concept ConstructibleWithN = (requires { + [] + (IdxSeq) + requires requires { T{AnyExcept{}}; } + { } + (IdxSeq<1,2,3>{}); + }); + +struct Foo { + int i; + double j; + char k; +}; + +static_assert(ConstructibleWithN); + +} Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -6700,6 +6700,7 @@ case Decl::PragmaDetectMismatch: case Decl::UsingPack: case Decl::Concept: + case Decl::ImplicitConceptSpecialization: case Decl::LifetimeExtendedTemporary: case Decl::RequiresExprBody: case Decl::UnresolvedUsingIfExists: