From 975740bf8db92e054b95a7cedd646d7bc3f74fed Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Mon, 24 Oct 2022 12:20:36 -0700 Subject: [PATCH] "Reapply "GH58368: Correct concept checking in a lambda defined in concept"" This reverts commit cecc9a92cfca71c1b6c2a35c5e302ab649496d11. The problem ended up being how we were handling the lambda-context in code generation: we were assuming any decl context here would be a named-decl, but that isn't the case. Instead, we just replace it with the concept's owning context. Differential Revision: https://reviews.llvm.org/D136451 --- clang/include/clang/AST/ASTNodeTraverser.h | 7 +++ clang/include/clang/AST/DeclTemplate.h | 36 +++++++++++- clang/include/clang/AST/ExprConcepts.h | 48 +++++++-------- clang/include/clang/AST/RecursiveASTVisitor.h | 5 ++ clang/include/clang/Basic/DeclNodes.td | 1 + clang/include/clang/Serialization/ASTBitCodes.h | 7 ++- clang/lib/AST/ASTContext.cpp | 8 ++- clang/lib/AST/Decl.cpp | 7 ++- clang/lib/AST/DeclBase.cpp | 1 + clang/lib/AST/DeclTemplate.cpp | 38 ++++++++++++ clang/lib/AST/ExprConcepts.cpp | 77 ++++++++----------------- clang/lib/CodeGen/CGDecl.cpp | 1 + clang/lib/Sema/SemaConcept.cpp | 3 +- clang/lib/Sema/SemaLambda.cpp | 10 +++- clang/lib/Sema/SemaTemplate.cpp | 12 +++- clang/lib/Sema/SemaTemplateInstantiate.cpp | 12 ++++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 ++ clang/lib/Sema/TreeTransform.h | 3 +- clang/lib/Serialization/ASTCommon.cpp | 1 + clang/lib/Serialization/ASTReaderDecl.cpp | 17 ++++++ clang/lib/Serialization/ASTReaderStmt.cpp | 9 +-- clang/lib/Serialization/ASTWriterDecl.cpp | 11 ++++ clang/lib/Serialization/ASTWriterStmt.cpp | 5 +- clang/test/AST/ast-dump-concepts.cpp | 8 +++ clang/test/SemaTemplate/concepts-lambda.cpp | 37 ++++++++++++ clang/tools/libclang/CIndex.cpp | 1 + 26 files changed, 268 insertions(+), 102 deletions(-) diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 44dc52b..6df3a83 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -623,7 +623,14 @@ public: 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 ae10744..d1dfe73 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -3259,7 +3259,7 @@ public: 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 @@ public: 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 diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h index fd9cd31..6dedeb5 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 { +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,51 +59,46 @@ protected: 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. /// 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 @@ public: /// 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 b5c24e1..8c54126 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 386c0a1..c94c84b 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -90,6 +90,7 @@ def Named : DeclNode; def ObjCImplementation : DeclNode; def ObjCProperty : DeclNode; def ObjCCompatibleAlias : DeclNode; +def ImplicitConceptSpecialization : DeclNode; def LinkageSpec : DeclNode, DeclContext; def Export : DeclNode, DeclContext; def ObjCPropertyImpl : DeclNode; diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 3bbd272..77d4a8a 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -41,7 +41,7 @@ namespace serialization { /// Version 4 of AST files also requires that the version control branch and /// revision match exactly, since there is no backward compatibility of /// AST files at this time. -const unsigned VERSION_MAJOR = 22; +const unsigned VERSION_MAJOR = 23; /// AST file minor version number supported by this version of /// Clang. @@ -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 1685214..08cbe2a 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(IDC)) NewIDC = new (C) CXXFoldExpr( diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 510910b..0480864 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1262,8 +1262,13 @@ LinkageInfo LinkageComputer::getLVForClosure(const DeclContext *DC, else if (isa(ContextDecl)) Owner = dyn_cast(ContextDecl->getDeclContext()->getRedeclContext()); - else + else if (isa(ContextDecl)) { + // Replace with the concept's owning decl, which is either a namespace or a + // TU, so this needs a dyn_cast. + Owner = dyn_cast(ContextDecl->getDeclContext()); + } else { Owner = cast(ContextDecl); + } if (!Owner) return LinkageInfo::none(); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 72922ef..5cb5523 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 9a2932c..deed47e 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -1053,6 +1053,44 @@ ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C, } //===----------------------------------------------------------------------===// +// 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 //===----------------------------------------------------------------------===// void ClassTemplatePartialSpecializationDecl::anchor() {} diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp index c17453f..fc8f1eb 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 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 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 @@ ConceptSpecializationExpr::ConceptSpecializationExpr( 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 * diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 8f28f96..2bf104b 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 484c024..e5ee950 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 2143b81..a22708d 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(ManglingContextDecl)) { Kind = DataMember; + } else if (isa(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 f6627c9..d81ed15 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 1400693..7475289 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(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(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()) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 2c7fc8d..dc694b2 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 4f6ee07..ebb83f1 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -12606,7 +12606,8 @@ TreeTransform::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 53e4c88..152037d 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 3662910..94a1d24 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 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 98b8a96..f6a2f85 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(); 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 @@ 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 afe59ef..93785ee 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 6576156..be28ad6 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 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 dff300a..06518a7 100644 --- a/clang/test/AST/ast-dump-concepts.cpp +++ b/clang/test/AST/ast-dump-concepts.cpp @@ -19,6 +19,11 @@ template struct Foo { // CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'binary_concept' // CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} 'bool' Concept {{.*}} 'binary_concept' + // CHECK-NEXT: |-ImplicitConceptSpecializationDecl {{.*}} 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 {{.*}} 'bool' + // CHECK-NEXT: |-ImplicitConceptSpecializationDecl {{.*}} 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); diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp b/clang/test/SemaTemplate/concepts-lambda.cpp index 13c402e..eace722 100644 --- a/clang/test/SemaTemplate/concepts-lambda.cpp +++ b/clang/test/SemaTemplate/concepts-lambda.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -std=c++20 -verify %s +// RUN: %clang_cc1 -std=c++20 -verify %s -triple powerpc64-ibm-aix // expected-no-diagnostics namespace GH57945 { @@ -55,3 +56,39 @@ namespace GH57971 { 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); + +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 69d3464..9cdbddd 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: -- 2.7.4