Author: Erich Keane Date: 2022-10-24T06:32:18-07:00 New Revision: b7c922607c5ba93db8b893d4ba461052af8317b5
URL: https://github.com/llvm/llvm-project/commit/b7c922607c5ba93db8b893d4ba461052af8317b5 DIFF: https://github.com/llvm/llvm-project/commit/b7c922607c5ba93db8b893d4ba461052af8317b5.diff LOG: GH58368: Correct concept checking in a lambda defined in concept As that bug reports, the problem here is that the lambda's 'context-decl' was not set to the concept, and the lambda picked up template arguments from the concept. SO, we failed to get the correct template arguments in SemaTemplateInstantiate. However, a Concept Specialization is NOT a decl, its an expression, so we weren't able to put the concept in the decl tree like we needed. This patch introduces a ConceptSpecializationDecl, which is the smallest type possible to use for this purpose, containing only the template arguments. The net memory impliciation of this is turning a trailing-objects into a pointer to a type with trailing-objects, so it should be minor. As future work, we may consider giving this type more responsibility, or figuring out how to better merge duplicates, but as this is just a template-argument collection at the moment, there isn't much value to it. Differential Revision: https://reviews.llvm.org/D136451 Added: Modified: clang/include/clang/AST/ASTNodeTraverser.h clang/include/clang/AST/DeclTemplate.h clang/include/clang/AST/ExprConcepts.h clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/Basic/DeclNodes.td clang/include/clang/Serialization/ASTBitCodes.h clang/lib/AST/ASTContext.cpp clang/lib/AST/DeclBase.cpp clang/lib/AST/DeclTemplate.cpp clang/lib/AST/ExprConcepts.cpp clang/lib/CodeGen/CGDecl.cpp clang/lib/Sema/SemaConcept.cpp clang/lib/Sema/SemaLambda.cpp clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaTemplateInstantiate.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTCommon.cpp clang/lib/Serialization/ASTReaderDecl.cpp clang/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTWriterDecl.cpp clang/lib/Serialization/ASTWriterStmt.cpp clang/test/AST/ast-dump-concepts.cpp clang/test/SemaTemplate/concepts-lambda.cpp clang/tools/libclang/CIndex.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 44dc52b419af5..6df3a83b6404a 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -623,7 +623,14 @@ class ASTNodeTraverser 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); diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index ae10744383559..d1dfe73a51182 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -3259,7 +3259,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl { 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<ConceptDecl> { protected: Expr *ConstraintExpr; @@ -3304,6 +3304,40 @@ class ConceptDecl : public TemplateDecl, public Mergeable<ConceptDecl> { 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<ImplicitConceptSpecializationDecl, + TemplateArgument> { + unsigned NumTemplateArgs; + + ImplicitConceptSpecializationDecl(DeclContext *DC, SourceLocation SL, + ArrayRef<TemplateArgument> ConvertedArgs); + ImplicitConceptSpecializationDecl(EmptyShell Empty, unsigned NumTemplateArgs); + +public: + static ImplicitConceptSpecializationDecl * + Create(const ASTContext &C, DeclContext *DC, SourceLocation SL, + ArrayRef<TemplateArgument> ConvertedArgs); + static ImplicitConceptSpecializationDecl * + CreateDeserialized(const ASTContext &C, unsigned ID, + unsigned NumTemplateArgs); + + ArrayRef<TemplateArgument> getTemplateArguments() const { + return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(), + NumTemplateArgs); + } + void setTemplateArguments(ArrayRef<TemplateArgument> 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 diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h index fd9cd31f3b90b..6dedeb5c8ddfa 100644 --- a/clang/include/clang/AST/ExprConcepts.h +++ b/clang/include/clang/AST/ExprConcepts.h @@ -37,18 +37,17 @@ class ASTStmtWriter; /// /// 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<ConceptSpecializationExpr, - TemplateArgument> { +class ConceptSpecializationExpr final : public Expr, public ConceptReference { + friend class ASTReader; friend class ASTStmtReader; - friend TrailingObjects; + public: using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>; 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,51 +59,46 @@ class ConceptSpecializationExpr final : public Expr, public ConceptReference, DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef<TemplateArgument> ConvertedArgs, + ImplicitConceptSpecializationDecl *SpecDecl, const ConstraintSatisfaction *Satisfaction); ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept, - ArrayRef<TemplateArgument> 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<TemplateArgument> ConvertedArgs, + ImplicitConceptSpecializationDecl *SpecDecl, const ConstraintSatisfaction *Satisfaction); static ConceptSpecializationExpr * Create(const ASTContext &C, ConceptDecl *NamedConcept, - ArrayRef<TemplateArgument> 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<TemplateArgument> getTemplateArguments() const { - return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(), - NumTemplateArgs); + return SpecDecl->getTemplateArguments(); } - /// \brief Set new template arguments for this concept specialization. - void setTemplateArguments(ArrayRef<TemplateArgument> 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. /// The expression must not be dependent. bool isSatisfied() const { - assert(!isValueDependent() - && "isSatisfied called on a dependent ConceptSpecializationExpr"); + assert(!isValueDependent() && + "isSatisfied called on a dependent ConceptSpecializationExpr"); return Satisfaction->IsSatisfied; } @@ -112,8 +106,8 @@ class ConceptSpecializationExpr final : public Expr, public ConceptReference, /// satisfaction of the named concept. /// The expression must not be dependent. const ASTConstraintSatisfaction &getSatisfaction() const { - assert(!isValueDependent() - && "getSatisfaction called on dependent ConceptSpecializationExpr"); + assert(!isValueDependent() && + "getSatisfaction called on dependent ConceptSpecializationExpr"); return *Satisfaction; } diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index b5c24e1a7661a..8c5412648bcd4 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2304,6 +2304,11 @@ DEF_TRAVERSE_DECL(ParmVarDecl, { DEF_TRAVERSE_DECL(RequiresExprBodyDecl, {}) +DEF_TRAVERSE_DECL(ImplicitConceptSpecializationDecl, { + TRY_TO(TraverseTemplateArguments(D->getTemplateArguments().data(), + D->getTemplateArguments().size())); +}) + #undef DEF_TRAVERSE_DECL // ----------------- Stmt traversal ----------------- diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index 386c0a1b3dbaa..c94c84ba25370 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -90,6 +90,7 @@ def Named : DeclNode<Decl, "named declarations", 1>; def ObjCImplementation : DeclNode<ObjCImpl>; def ObjCProperty : DeclNode<Named, "Objective-C properties">; def ObjCCompatibleAlias : DeclNode<Named>; +def ImplicitConceptSpecialization : DeclNode<Decl>; def LinkageSpec : DeclNode<Decl>, DeclContext; def Export : DeclNode<Decl>, DeclContext; def ObjCPropertyImpl : DeclNode<Decl>; diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 3bbd2723be676..ff8be544d5a46 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1514,7 +1514,10 @@ enum DeclCode { /// 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. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 16852149792bb..08cbe2a9a5811 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -761,9 +761,13 @@ canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC, 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<CXXFoldExpr>(IDC)) NewIDC = new (C) CXXFoldExpr( diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 72922ef977f92..5cb552372497d 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -874,6 +874,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Empty: case LifetimeExtendedTemporary: case RequiresExprBody: + case ImplicitConceptSpecialization: // Never looked up by name. return 0; } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 9a2932c0bcbd8..deed47ec4a298 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -1052,6 +1052,44 @@ ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C, return Result; } +//===----------------------------------------------------------------------===// +// ImplicitConceptSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +ImplicitConceptSpecializationDecl::ImplicitConceptSpecializationDecl( + DeclContext *DC, SourceLocation SL, + ArrayRef<TemplateArgument> 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<TemplateArgument> ConvertedArgs) { + return new (C, DC, + additionalSizeToAlloc<TemplateArgument>(ConvertedArgs.size())) + ImplicitConceptSpecializationDecl(DC, SL, ConvertedArgs); +} + +ImplicitConceptSpecializationDecl * +ImplicitConceptSpecializationDecl::CreateDeserialized( + const ASTContext &C, unsigned ID, unsigned NumTemplateArgs) { + return new (C, ID, additionalSizeToAlloc<TemplateArgument>(NumTemplateArgs)) + ImplicitConceptSpecializationDecl(EmptyShell{}, NumTemplateArgs); +} + +void ImplicitConceptSpecializationDecl::setTemplateArguments( + ArrayRef<TemplateArgument> Converted) { + assert(Converted.size() == NumTemplateArgs); + std::uninitialized_copy(Converted.begin(), Converted.end(), + getTrailingObjects<TemplateArgument>()); +} + //===----------------------------------------------------------------------===// // ClassTemplatePartialSpecializationDecl Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp index c17453fb45fb8..fc8f1eb2abf14 100644 --- a/clang/lib/AST/ExprConcepts.cpp +++ b/clang/lib/AST/ExprConcepts.cpp @@ -35,16 +35,15 @@ ConceptSpecializationExpr::ConceptSpecializationExpr( SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef<TemplateArgument> 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 @@ ConceptSpecializationExpr::ConceptSpecializationExpr( "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<TemplateArgument> Converted) { - assert(Converted.size() == NumTemplateArgs); - std::uninitialized_copy(Converted.begin(), Converted.end(), - getTrailingObjects<TemplateArgument>()); -} - -ConceptSpecializationExpr * -ConceptSpecializationExpr::Create(const ASTContext &C, - NestedNameSpecifierLoc NNS, - SourceLocation TemplateKWLoc, - DeclarationNameInfo ConceptNameInfo, - NamedDecl *FoundDecl, - ConceptDecl *NamedConcept, - const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef<TemplateArgument> ConvertedArgs, - const ConstraintSatisfaction *Satisfaction) { - void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>( - 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<TemplateArgument> 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 @@ ConceptSpecializationExpr::ConceptSpecializationExpr( setDependence(D); } -ConceptSpecializationExpr * -ConceptSpecializationExpr::Create(const ASTContext &C, - ConceptDecl *NamedConcept, - ArrayRef<TemplateArgument> ConvertedArgs, - const ConstraintSatisfaction *Satisfaction, - bool Dependent, - bool ContainsUnexpandedParameterPack) { - void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>( - 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<TemplateArgument>( - 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 * diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 8f28f96e93785..2bf104b58d947 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -127,6 +127,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { 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. diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 484c02498f20b..e5ee950e67997 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -265,7 +265,8 @@ static ExprResult calculateConstraintSatisfaction( 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; diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 2143b811668af..a22708df5dbed 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -282,7 +282,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) { DataMember, StaticDataMember, InlineVariable, - VariableTemplate + VariableTemplate, + Concept } Kind = Normal; // Default arguments of member function parameters that appear in a class @@ -307,6 +308,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) { } } else if (isa<FieldDecl>(ManglingContextDecl)) { Kind = DataMember; + } else if (isa<ImplicitConceptSpecializationDecl>(ManglingContextDecl)) { + Kind = Concept; } } @@ -330,6 +333,11 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) { 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) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index f6627c9bc53c3..d81ed15f979f1 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -4866,6 +4866,9 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, /*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 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, 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 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, 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); } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 1400693f664ea..7475289745c7d 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -231,6 +231,15 @@ Response HandleRecordDecl(const CXXRecordDecl *Rec, return Response::UseNextDecl(Rec); } +Response HandleImplicitConceptSpecializationDecl( + const ImplicitConceptSpecializationDecl *CSD, + MultiLevelTemplateArgumentList &Result) { + Result.addOuterTemplateArguments( + const_cast<ImplicitConceptSpecializationDecl *>(CSD), + CSD->getTemplateArguments()); + return Response::UseNextDecl(CSD); +} + Response HandleGenericDeclContext(const Decl *CurDecl) { return Response::UseNextDecl(CurDecl); } @@ -289,6 +298,9 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( ForConstraintInstantiation); } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) { R = HandleRecordDecl(Rec, Result, Context, ForConstraintInstantiation); + } else if (const auto *CSD = + dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) { + R = HandleImplicitConceptSpecializationDecl(CSD, Result); } else if (!isa<DeclContext>(CurDecl)) { R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl); if (CurDecl->getDeclContext()->isTranslationUnit()) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 2c7fc8d56dbdb..dc694b2cb7c97 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3965,6 +3965,11 @@ Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) { 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(), diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 4f6ee0772c3c7..ebb83f12b6566 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -12606,7 +12606,8 @@ TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) { // 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, diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index 53e4c889f5298..152037dfc9269 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -430,6 +430,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::Decomposition: case Decl::Binding: case Decl::Concept: + case Decl::ImplicitConceptSpecialization: case Decl::LifetimeExtendedTemporary: case Decl::RequiresExprBody: case Decl::UnresolvedUsingIfExists: diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 36629101b7de4..94a1d243918dd 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -384,6 +384,8 @@ namespace clang { 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 @@ void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) { 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<TemplateArgument, 4> 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 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { 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"); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 98b8a960aef7c..f6a2f85682b2a 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -794,17 +794,13 @@ readConstraintSatisfaction(ASTRecordReader &Record) { 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<ConceptDecl>(); E->FoundDecl = Record.readDeclAs<NamedDecl>(); + E->SpecDecl = Record.readDeclAs<ImplicitConceptSpecializationDecl>(); E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); - llvm::SmallVector<TemplateArgument, 4> 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 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; case EXPR_CONCEPT_SPECIALIZATION: { - unsigned numTemplateArgs = Record[ASTStmtReader::NumExprFields]; - S = ConceptSpecializationExpr::Create(Context, Empty, numTemplateArgs); + S = new (Context) ConceptSpecializationExpr(Empty); break; } diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index afe59ef98c8e2..93785eeb9e880 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -107,6 +107,8 @@ namespace clang { 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 @@ void ASTDeclWriter::VisitConceptDecl(ConceptDecl *D) { 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; } diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 65761566ab060..be28ad6b2a668 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -433,16 +433,13 @@ addSubstitutionDiagnostic( void ASTStmtWriter::VisitConceptSpecializationExpr( ConceptSpecializationExpr *E) { VisitExpr(E); - ArrayRef<TemplateArgument> 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()); diff --git a/clang/test/AST/ast-dump-concepts.cpp b/clang/test/AST/ast-dump-concepts.cpp index dff300a559517..06518a71987a2 100644 --- a/clang/test/AST/ast-dump-concepts.cpp +++ b/clang/test/AST/ast-dump-concepts.cpp @@ -19,6 +19,11 @@ template <typename T> struct Foo { // CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'binary_concept' // CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} <col:13, col:31> 'bool' Concept {{.*}} 'binary_concept' + // CHECK-NEXT: |-ImplicitConceptSpecializationDecl {{.*}} <line:13:9> 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 @@ struct Foo { // CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'unary_concept' // CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} <col:13> 'bool' + // CHECK-NEXT: |-ImplicitConceptSpecializationDecl {{.*}} <line:10:9> col:9 + // CHECK-NEXT: | `-TemplateArgument type 'type-parameter-1-0' + // CHECK-NEXT: | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent {{.*}}depth 1 index 0 template <unary_concept R> Foo(R); diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp b/clang/test/SemaTemplate/concepts-lambda.cpp index 13c402e3ca7a8..a4e8e0e50f026 100644 --- a/clang/test/SemaTemplate/concepts-lambda.cpp +++ b/clang/test/SemaTemplate/concepts-lambda.cpp @@ -55,3 +55,39 @@ namespace GH57971 { using function_ptr = void(*)(int); function_ptr ptr = f<void>; } + +// 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<size_t...Ts> +struct IdxSeq{}; + +template <class T, class... Ts> +concept NotLike = true; + +template <size_t, class... Ts> +struct AnyExcept { + template <NotLike<Ts...> T> operator T&() const; + template <NotLike<Ts...> T> operator T&&() const; +}; + +template <class T> + concept ConstructibleWithN = (requires { + []<size_t I, size_t... Idxs> + (IdxSeq<I, Idxs...>) + requires requires { T{AnyExcept<I, T>{}}; } + { } + (IdxSeq<1,2,3>{}); + }); + +struct Foo { + int i; + double j; + char k; +}; + +static_assert(ConstructibleWithN<Foo>); + +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 69d34646ca937..9cdbddd82f76c 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -6700,6 +6700,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::PragmaDetectMismatch: case Decl::UsingPack: case Decl::Concept: + case Decl::ImplicitConceptSpecialization: case Decl::LifetimeExtendedTemporary: case Decl::RequiresExprBody: case Decl::UnresolvedUsingIfExists: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits