Author: Corentin Jabot Date: 2026-08-19T10:18:50+02:00 New Revision: 40fe85daa063f8201174f9a5a777d9db13f77f91
URL: https://github.com/llvm/llvm-project/commit/40fe85daa063f8201174f9a5a777d9db13f77f91 DIFF: https://github.com/llvm/llvm-project/commit/40fe85daa063f8201174f9a5a777d9db13f77f91.diff LOG: [Clang][NFC] Introduce a node to model concept and variable template template parameters (#216729) The initial implementation of concept template parameter piggy-backed on UnresolvedLookupExpr, because it did _mostly_ what we wanted and I was lazy (it led to some akwardness in a few places) However, to implement template pack indexing we need to store a TemplateName rather than a template decl. So this PR adds this new node, as preparatory work for P3670. --- Opus 5 was used to make the initial version of this PR, with quite a bit of cleaning after. Added: Modified: clang/include/clang/AST/ComputeDependence.h clang/include/clang/AST/ExprCXX.h clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/AST/TemplateBase.h clang/include/clang/AST/TextNodeDumper.h clang/include/clang/Basic/StmtNodes.td clang/include/clang/Sema/Sema.h clang/include/clang/Serialization/ASTBitCodes.h clang/lib/AST/ASTImporter.cpp clang/lib/AST/ComputeDependence.cpp clang/lib/AST/Expr.cpp clang/lib/AST/ExprCXX.cpp clang/lib/AST/ExprClassification.cpp clang/lib/AST/ExprConstant.cpp clang/lib/AST/ItaniumMangle.cpp clang/lib/AST/StmtPrinter.cpp clang/lib/AST/StmtProfile.cpp clang/lib/AST/TextNodeDumper.cpp clang/lib/Sema/SemaExceptionSpec.cpp clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaTemplateDeduction.cpp clang/lib/Sema/SemaTemplateInstantiate.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTWriter.cpp clang/lib/Serialization/ASTWriterStmt.cpp clang/lib/StaticAnalyzer/Core/ExprEngine.cpp clang/tools/libclang/CXCursor.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h index 3a3c86842501a..6430081a40350 100644 --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -80,6 +80,7 @@ class CXXDefaultArgExpr; class LambdaExpr; class CXXUnresolvedConstructExpr; class CXXDependentScopeMemberExpr; +class DependentTemplateIdExpr; class MaterializeTemporaryExpr; class CXXFoldExpr; class CXXParenListInitExpr; @@ -175,6 +176,7 @@ ExprDependence computeDependence(LambdaExpr *E, bool ContainsUnexpandedParameterPack); ExprDependence computeDependence(CXXUnresolvedConstructExpr *E); ExprDependence computeDependence(CXXDependentScopeMemberExpr *E); +ExprDependence computeDependence(DependentTemplateIdExpr *E); ExprDependence computeDependence(MaterializeTemporaryExpr *E); ExprDependence computeDependence(CXXFoldExpr *E); ExprDependence computeDependence(CXXParenListInitExpr *E); diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index d3d3b9c6d6326..59a70942af4e1 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -3287,39 +3287,11 @@ class OverloadExpr : public Expr { getTrailingASTTemplateKWAndArgsInfo()->NumTemplateArgs; } - bool isConceptReference() const { - return getNumDecls() == 1 && [&]() { - if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>( - getTrailingResults()->getDecl())) - return TTP->templateParameterKind() == TNK_Concept_template; - if (isa<ConceptDecl>(getTrailingResults()->getDecl())) - return true; - return false; - }(); - } - - bool isVarDeclReference() const { - return getNumDecls() == 1 && [&]() { - if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>( - getTrailingResults()->getDecl())) - return TTP->templateParameterKind() == TNK_Var_template; - if (isa<VarTemplateDecl>(getTrailingResults()->getDecl())) - return true; - return false; - }(); - } - TemplateDecl *getTemplateDecl() const { assert(getNumDecls() == 1); return dyn_cast_or_null<TemplateDecl>(getTrailingResults()->getDecl()); } - TemplateTemplateParmDecl *getTemplateTemplateDecl() const { - assert(getNumDecls() == 1); - return dyn_cast_or_null<TemplateTemplateParmDecl>( - getTrailingResults()->getDecl()); - } - TemplateArgumentLoc const *getTemplateArgs() const { if (!hasExplicitTemplateArgs()) return nullptr; @@ -3488,6 +3460,75 @@ class UnresolvedLookupExpr final } }; +/// A template-id naming a variable template or a concept through a template +/// template parameter. +class DependentTemplateIdExpr final + : public Expr, + private llvm::TrailingObjects<DependentTemplateIdExpr, + TemplateArgumentLoc> { + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend TrailingObjects; + + DeclarationNameInfo NameInfo; + TemplateName Name; + ASTTemplateKWAndArgsInfo KWAndArgs; + + DependentTemplateIdExpr(const ASTContext &Context, + const DeclarationNameInfo &NameInfo, + TemplateName Name, + const TemplateArgumentListInfo &TemplateArgs); + + DependentTemplateIdExpr(EmptyShell Empty, unsigned NumTemplateArgs); + +public: + static DependentTemplateIdExpr * + Create(const ASTContext &Context, const DeclarationNameInfo &NameInfo, + TemplateName Name, const TemplateArgumentListInfo &TemplateArgs); + + static DependentTemplateIdExpr *CreateEmpty(const ASTContext &Context, + unsigned NumTemplateArgs); + + const DeclarationNameInfo &getNameInfo() const { return NameInfo; } + DeclarationName getName() const { return NameInfo.getName(); } + SourceLocation getNameLoc() const { return NameInfo.getLoc(); } + + TemplateName getTemplateName() const { return Name; } + + TemplateTemplateParmDecl *getParameter() const { + return cast<TemplateTemplateParmDecl>(Name.getAsTemplateDecl()); + } + + bool isConceptReference() const { + return getParameter()->templateParameterKind() == TNK_Concept_template; + } + + SourceLocation getLAngleLoc() const { return KWAndArgs.LAngleLoc; } + SourceLocation getRAngleLoc() const { return KWAndArgs.RAngleLoc; } + + unsigned getNumTemplateArgs() const { return KWAndArgs.NumTemplateArgs; } + + ArrayRef<TemplateArgumentLoc> template_arguments() const { + return getTrailingObjects(getNumTemplateArgs()); + } + + SourceLocation getBeginLoc() const { return getNameLoc(); } + + SourceLocation getEndLoc() const { return getRAngleLoc(); } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DependentTemplateIdExprClass; + } +}; + /// A qualified reference to a name whose declaration cannot /// yet be resolved. /// diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index d435cda19fa49..1f7c8d762e1b5 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2646,6 +2646,12 @@ DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, { } }) +DEF_TRAVERSE_STMT(DependentTemplateIdExpr, { + TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo())); + TRY_TO(TraverseTemplateArgumentLocsHelper(S->template_arguments().data(), + S->getNumTemplateArgs())); +}) + DEF_TRAVERSE_STMT(DeclRefExpr, { TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo())); diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index f7d754ea6082b..b9a787ed1b626 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -775,7 +775,7 @@ struct ASTTemplateArgumentListInfo final /// Represents an explicit template argument list in C++, e.g., /// the "<int>" in "sort<int>". /// -/// It is intended to be used as a trailing object on AST nodes, and +/// It is designed to be usable as a trailing object on AST nodes, and /// as such, doesn't contain the array of TemplateArgumentLoc itself, /// but expects the containing object to also provide storage for /// that. diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 1eaafd49c2f06..5d4a4456b40a1 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -277,6 +277,7 @@ class TextNodeDumper void VisitImplicitCastExpr(const ImplicitCastExpr *Node); void VisitDeclRefExpr(const DeclRefExpr *Node); void VisitDependentScopeDeclRefExpr(const DependentScopeDeclRefExpr *Node); + void VisitDependentTemplateIdExpr(const DependentTemplateIdExpr *Node); void VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *Node); void VisitPredefinedExpr(const PredefinedExpr *Node); void VisitCharacterLiteral(const CharacterLiteral *Node); diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 6df244d7a8c90..84804d6705d2b 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -161,6 +161,7 @@ def ExprWithCleanups : StmtNode<FullExpr>; def CXXTemporaryObjectExpr : StmtNode<CXXConstructExpr>; def CXXUnresolvedConstructExpr : StmtNode<Expr>; def CXXDependentScopeMemberExpr : StmtNode<Expr>; +def DependentTemplateIdExpr : StmtNode<Expr>; def OverloadExpr : StmtNode<Expr, 1>; def UnresolvedLookupExpr : StmtNode<OverloadExpr>; def UnresolvedMemberExpr : StmtNode<OverloadExpr>; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 3cb0dcbbba83a..a0f94df1407b2 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11819,8 +11819,7 @@ class Sema final : public SemaBase { const TemplateArgumentListInfo *TemplateArgs); ExprResult CheckVarOrConceptTemplateTemplateId( - const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, - TemplateTemplateParmDecl *Template, SourceLocation TemplateLoc, + const DeclarationNameInfo &NameInfo, TemplateTemplateParmDecl *Template, const TemplateArgumentListInfo *TemplateArgs); ExprResult diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 974761b236411..6a52a9e4fa780 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1929,6 +1929,7 @@ enum StmtCode { EXPR_CXX_DEPENDENT_SCOPE_MEMBER, // CXXDependentScopeMemberExpr EXPR_CXX_DEPENDENT_SCOPE_DECL_REF, // DependentScopeDeclRefExpr + EXPR_DEPENDENT_TEMPLATE_ID, // DependentTemplateIdExpr EXPR_CXX_UNRESOLVED_CONSTRUCT, // CXXUnresolvedConstructExpr EXPR_CXX_UNRESOLVED_MEMBER, // UnresolvedMemberExpr EXPR_CXX_UNRESOLVED_LOOKUP, // UnresolvedLookupExpr diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 725ebbd6ec987..c2164352126ef 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -682,6 +682,7 @@ namespace clang { ExpectedStmt VisitCXXMemberCallExpr(CXXMemberCallExpr *E); ExpectedStmt VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E); ExpectedStmt VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E); + ExpectedStmt VisitDependentTemplateIdExpr(DependentTemplateIdExpr *E); ExpectedStmt VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E); ExpectedStmt VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E); ExpectedStmt VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E); @@ -8825,6 +8826,29 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr( ToMemberNameInfo, ResInfo); } +ExpectedStmt +ASTNodeImporter::VisitDependentTemplateIdExpr(DependentTemplateIdExpr *E) { + Error Err = Error::success(); + auto ToName = importChecked(Err, E->getTemplateName()); + auto ToDeclName = importChecked(Err, E->getName()); + auto ToNameLoc = importChecked(Err, E->getNameLoc()); + if (Err) + return std::move(Err); + + DeclarationNameInfo ToNameInfo(ToDeclName, ToNameLoc); + if (Error Err = ImportDeclarationNameLoc(E->getNameInfo(), ToNameInfo)) + return std::move(Err); + + TemplateArgumentListInfo ToTAInfo; + if (Error Err = + ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(), + E->template_arguments(), ToTAInfo)) + return std::move(Err); + + return DependentTemplateIdExpr::Create(Importer.getToContext(), ToNameInfo, + ToName, ToTAInfo); +} + ExpectedStmt ASTNodeImporter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { Error Err = Error::success(); diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 7e6bd69711c5b..0fc9da18b9394 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -831,7 +831,7 @@ clang::computeDependence(OverloadExpr *E, bool KnownDependent, ~NestedNameSpecifierDependence::Dependent); for (auto *D : E->decls()) { if (D->getDeclContext()->isDependentContext() || - isa<UnresolvedUsingValueDecl>(D) || isa<TemplateTemplateParmDecl>(D)) + isa<UnresolvedUsingValueDecl>(D)) Deps |= ExprDependence::TypeValueInstantiation; } // If we have explicit template arguments, check for dependent @@ -903,6 +903,17 @@ ExprDependence clang::computeDependence(CXXDependentScopeMemberExpr *E) { return D; } +ExprDependence clang::computeDependence(DependentTemplateIdExpr *E) { + auto D = ExprDependence::TypeValueInstantiation; + if (E->getTemplateName().getDependence() & + TemplateNameDependence::UnexpandedPack) + D |= ExprDependence::UnexpandedPack; + D |= getDependenceInExpr(E->getNameInfo()); + for (const auto &A : E->template_arguments()) + D |= toExprDependence(A.getArgument().getDependence()); + return D; +} + ExprDependence clang::computeDependence(MaterializeTemporaryExpr *E) { return E->getSubExpr()->getDependence(); } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 5d7ee4710481c..e501527ed9b04 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3714,6 +3714,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, llvm_unreachable("unexpected Expr kind"); case DependentScopeDeclRefExprClass: + case DependentTemplateIdExprClass: case CXXUnresolvedConstructExprClass: case CXXDependentScopeMemberExprClass: case UnresolvedLookupExprClass: diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 6c1cde6540d85..08c931d863044 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -401,14 +401,40 @@ SourceLocation CXXPseudoDestructorExpr::getEndLoc() const { return End; } -static bool UnresolvedLookupExprIsVariableOrConceptParameterPack( - UnresolvedSetIterator Begin, UnresolvedSetIterator End) { - if (std::distance(Begin, End) != 1) - return false; - NamedDecl *ND = *Begin; - if (const auto *TTP = llvm::dyn_cast<TemplateTemplateParmDecl>(ND)) - return TTP->isParameterPack(); - return false; +DependentTemplateIdExpr::DependentTemplateIdExpr( + const ASTContext &Context, const DeclarationNameInfo &NameInfo, + TemplateName Name, const TemplateArgumentListInfo &TemplateArgs) + : Expr(DependentTemplateIdExprClass, Context.DependentTy, VK_LValue, + OK_Ordinary), + NameInfo(NameInfo), Name(Name) { + KWAndArgs.initializeFrom(/*TemplateKWLoc=*/{}, TemplateArgs, + getTrailingObjects()); + setDependence(computeDependence(this)); +} + +DependentTemplateIdExpr::DependentTemplateIdExpr(EmptyShell Empty, + unsigned NumTemplateArgs) + : Expr(DependentTemplateIdExprClass, Empty) { + KWAndArgs.NumTemplateArgs = NumTemplateArgs; +} + +DependentTemplateIdExpr *DependentTemplateIdExpr::Create( + const ASTContext &Context, const DeclarationNameInfo &NameInfo, + TemplateName Name, const TemplateArgumentListInfo &TemplateArgs) { + void *Mem = Context.Allocate( + totalSizeToAlloc<TemplateArgumentLoc>(TemplateArgs.size()), + alignof(DependentTemplateIdExpr)); + return new (Mem) + DependentTemplateIdExpr(Context, NameInfo, Name, TemplateArgs); +} + +DependentTemplateIdExpr * +DependentTemplateIdExpr::CreateEmpty(const ASTContext &Context, + unsigned NumTemplateArgs) { + void *Mem = + Context.Allocate(totalSizeToAlloc<TemplateArgumentLoc>(NumTemplateArgs), + alignof(DependentTemplateIdExpr)); + return new (Mem) DependentTemplateIdExpr(EmptyShell(), NumTemplateArgs); } // UnresolvedLookupExpr @@ -419,11 +445,10 @@ UnresolvedLookupExpr::UnresolvedLookupExpr( const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End, bool KnownDependent, bool KnownInstantiationDependent) - : OverloadExpr( - UnresolvedLookupExprClass, Context, QualifierLoc, TemplateKWLoc, - NameInfo, TemplateArgs, Begin, End, KnownDependent, - KnownInstantiationDependent, - UnresolvedLookupExprIsVariableOrConceptParameterPack(Begin, End)), + : OverloadExpr(UnresolvedLookupExprClass, Context, QualifierLoc, + TemplateKWLoc, NameInfo, TemplateArgs, Begin, End, + KnownDependent, KnownInstantiationDependent, + /*KnownContainsUnexpandedParameterPack=*/false), NamingClass(NamingClass) { UnresolvedLookupExprBits.RequiresADL = RequiresADL; } diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index ef071cdef66b6..eebae17d7b948 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -130,6 +130,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // FIXME: Is this wise? Should they get their own kind? case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: + case Expr::DependentTemplateIdExprClass: case Expr::DependentCoawaitExprClass: case Expr::CXXDependentScopeMemberExprClass: case Expr::DependentScopeDeclRefExprClass: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 05f981f671e62..ddcef9e7bfc6f 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -22340,6 +22340,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::UnresolvedLookupExprClass: case Expr::RecoveryExprClass: case Expr::DependentScopeDeclRefExprClass: + case Expr::DependentTemplateIdExprClass: case Expr::CXXConstructExprClass: case Expr::CXXInheritedCtorInitExprClass: case Expr::CXXStdInitializerListExprClass: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index da8339e4a45ee..c77d9d979e932 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -5317,6 +5317,15 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, break; } + case Expr::DependentTemplateIdExprClass: { + NotPrimaryExpr(); + const auto *DTI = cast<DependentTemplateIdExpr>(E); + mangleUnresolvedName(NestedNameSpecifier(), DTI->getName(), + DTI->template_arguments().data(), + DTI->getNumTemplateArgs(), Arity); + break; + } + case Expr::CXXUnresolvedConstructExprClass: { NotPrimaryExpr(); const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E); diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index eeb377c794e05..e08566e5ae011 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -2671,6 +2671,12 @@ void StmtPrinter::VisitCXXReflectExpr(CXXReflectExpr *S) { assert(false && "not implemented yet"); } +void StmtPrinter::VisitDependentTemplateIdExpr(DependentTemplateIdExpr *Node) { + OS << Node->getNameInfo(); + printTemplateArgumentList(OS, Node->template_arguments(), Policy, + Node->getParameter()->getTemplateParameters()); +} + void StmtPrinter::VisitCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *Node) { if (!Node->isImplicitAccess()) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 45c962aa27553..dca2c49ac45d5 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2353,6 +2353,14 @@ void StmtProfiler::VisitCXXUnresolvedConstructExpr( ID.AddInteger(S->isListInitialization()); } +void StmtProfiler::VisitDependentTemplateIdExpr( + const DependentTemplateIdExpr *S) { + VisitExpr(S); + VisitTemplateName(S->getTemplateName()); + VisitTemplateArguments(S->template_arguments().data(), + S->getNumTemplateArgs()); +} + void StmtProfiler::VisitCXXDependentScopeMemberExpr( const CXXDependentScopeMemberExpr *S) { ID.AddBoolean(S->isImplicitAccess()); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index d07767aab2068..55e71cf58f248 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1642,6 +1642,13 @@ void clang::TextNodeDumper::VisitDependentScopeDeclRefExpr( dumpNestedNameSpecifier(Node->getQualifier()); } +void clang::TextNodeDumper::VisitDependentTemplateIdExpr( + const DependentTemplateIdExpr *Node) { + OS << (Node->isConceptReference() ? " concept" : " variable template"); + OS << ' '; + dumpBareTemplateName(Node->getTemplateName()); +} + void TextNodeDumper::VisitUnresolvedLookupExpr( const UnresolvedLookupExpr *Node) { OS << " ("; diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index daa4bb5234b7b..8f08e17276ef3 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1385,6 +1385,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::UnaryExprOrTypeTraitExprClass: case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: + case Expr::DependentTemplateIdExprClass: // FIXME: Many of the above can throw. return CT_Cannot; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index c1d8c3500a9a9..1fde412749cc9 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1238,9 +1238,10 @@ static ExprResult formImmediatelyDeclaredConstraint( } // We have a template template parameter else { + assert(SS.isEmpty() && "template parameter with a scope specifier?"); auto *CDT = dyn_cast<TemplateTemplateParmDecl>(NamedConcept); - ImmediatelyDeclaredConstraint = S.CheckVarOrConceptTemplateTemplateId( - SS, NameInfo, CDT, SourceLocation(), &ConstraintArgs); + ImmediatelyDeclaredConstraint = + S.CheckVarOrConceptTemplateTemplateId(NameInfo, CDT, &ConstraintArgs); } if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid()) return ImmediatelyDeclaredConstraint; @@ -2789,16 +2790,10 @@ struct DependencyChecker : DynamicRecursiveASTVisitor { return DynamicRecursiveASTVisitor::VisitDeclRefExpr(E); } - bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *ULE) override { - if (ULE->isConceptReference() || ULE->isVarDeclReference()) { - if (auto *TTP = ULE->getTemplateTemplateDecl()) { - if (Matches(TTP->getDepth(), ULE->getExprLoc())) - return false; - } - for (auto &TLoc : ULE->template_arguments()) - DynamicRecursiveASTVisitor::TraverseTemplateArgumentLoc(TLoc); - } - return DynamicRecursiveASTVisitor::VisitUnresolvedLookupExpr(ULE); + bool VisitDependentTemplateIdExpr(DependentTemplateIdExpr *E) override { + if (Matches(E->getParameter()->getDepth(), E->getExprLoc())) + return false; + return DynamicRecursiveASTVisitor::VisitDependentTemplateIdExpr(E); } bool VisitSubstTemplateTypeParmType(SubstTemplateTypeParmType *T) override { @@ -4836,8 +4831,7 @@ ExprResult Sema::CheckVarTemplateId( } ExprResult Sema::CheckVarOrConceptTemplateTemplateId( - const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, - TemplateTemplateParmDecl *Template, SourceLocation TemplateLoc, + const DeclarationNameInfo &NameInfo, TemplateTemplateParmDecl *Template, const TemplateArgumentListInfo *TemplateArgs) { assert(Template && "A variable template id without template?"); @@ -4849,7 +4843,7 @@ ExprResult Sema::CheckVarOrConceptTemplateTemplateId( // Check that the template argument list is well-formed for this template. CheckTemplateArgumentInfo CTAI; if (CheckTemplateArgumentList( - Template, TemplateLoc, + Template, /*Template kw loc=*/{}, // FIXME: TemplateArgs will not be modified because // UpdateArgsWithConversions is false, however, we should // CheckTemplateArgumentList to be const-correct. @@ -4858,18 +4852,8 @@ ExprResult Sema::CheckVarOrConceptTemplateTemplateId( /*UpdateArgsWithConversions=*/false)) return true; - UnresolvedSet<1> R; - R.addDecl(Template); - - // FIXME: We model references to variable template and concept parameters - // as an UnresolvedLookupExpr. This is because they encapsulate the same - // data, can generally be used in the same places and work the same way. - // However, it might be cleaner to use a dedicated AST node in the long run. - return UnresolvedLookupExpr::Create( - getASTContext(), nullptr, SS.getWithLocInContext(getASTContext()), - SourceLocation(), NameInfo, false, TemplateArgs, R.begin(), R.end(), - /*KnownDependent=*/false, - /*KnownInstantiationDependent=*/false); + return DependentTemplateIdExpr::Create(getASTContext(), NameInfo, + TemplateName(Template), *TemplateArgs); } void Sema::diagnoseMissingTemplateArguments(TemplateName Name, @@ -4999,6 +4983,8 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, R.suppressDiagnostics(); if (R.getAsSingle<ConceptDecl>()) { + assert(TemplateKWLoc.isInvalid() && + "template keyword in front of a concept id?"); return CheckConceptTemplateId(SS, TemplateKWLoc, R.getLookupNameInfo(), R.getRepresentativeDecl(), R.getAsSingle<ConceptDecl>(), TemplateArgs); @@ -5007,10 +4993,14 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, // Check variable template ids (C++17) and concept template parameters // (C++26). UnresolvedLookupExpr *ULE; - if (R.getAsSingle<TemplateTemplateParmDecl>()) + if (R.getAsSingle<TemplateTemplateParmDecl>()) { + assert(SS.isEmpty() && "template parameter with a scope specifier?"); + assert(TemplateKWLoc.isInvalid() && + "template keyword in front of a template parameter?"); return CheckVarOrConceptTemplateTemplateId( - SS, R.getLookupNameInfo(), R.getAsSingle<TemplateTemplateParmDecl>(), - TemplateKWLoc, TemplateArgs); + R.getLookupNameInfo(), R.getAsSingle<TemplateTemplateParmDecl>(), + TemplateArgs); + } // Function templates ULE = UnresolvedLookupExpr::Create( @@ -8704,10 +8694,8 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs( if (isa<NonTypeTemplateParmDecl>(DRE->getDecl())) continue; - if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(ArgExpr); - ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) { + if (isa<DependentTemplateIdExpr>(ArgExpr)) continue; - } // C++ [temp.class.spec]p9: // Within the argument list of a class template partial diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index c57a090a8553e..21190031b95ea 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -247,14 +247,10 @@ getDeducedNTTParameterFromExpr(const Expr *E, unsigned Depth) { if (NTTP->getDepth() == Depth) return NTTP; - if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E); - ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) { - if (auto *TTP = ULE->getTemplateTemplateDecl()) { + if (const auto *DTI = dyn_cast<DependentTemplateIdExpr>(E)) + if (DTI->getParameter()->getDepth() == Depth) + return DTI->getParameter(); - if (TTP->getDepth() == Depth) - return TTP; - } - } return nullptr; } @@ -6872,15 +6868,10 @@ struct MarkUsedTemplateParameterVisitor : DynamicRecursiveASTVisitor { return true; } - bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *ULE) override { - if (ULE->isConceptReference() || ULE->isVarDeclReference()) { - if (auto *TTP = ULE->getTemplateTemplateDecl()) { - if (TTP->getDepth() == Depth) - Used[TTP->getIndex()] = true; - } - for (auto &TLoc : ULE->template_arguments()) - DynamicRecursiveASTVisitor::TraverseTemplateArgumentLoc(TLoc); - } + bool VisitDependentTemplateIdExpr(DependentTemplateIdExpr *E) override { + TemplateTemplateParmDecl *TTP = E->getParameter(); + if (TTP->getDepth() == Depth) + Used[TTP->getIndex()] = true; return true; } @@ -6909,11 +6900,10 @@ MarkUsedTemplateParameters(ASTContext &Ctx, E = Expansion->getPattern(); E = unwrapExpressionForDeduction(E); - if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E); - ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) { - if (const auto *TTP = ULE->getTemplateTemplateDecl()) - Used[TTP->getIndex()] = true; - for (auto &TLoc : ULE->template_arguments()) + + if (const auto *DTI = dyn_cast<DependentTemplateIdExpr>(E)) { + Used[DTI->getParameter()->getIndex()] = true; + for (const auto &TLoc : DTI->template_arguments()) MarkUsedTemplateParameters(Ctx, TLoc.getArgument(), OnlyDeduced, Depth, Used); return; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index d2c72753aee79..f107811be868f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -4588,6 +4588,7 @@ ExprResult Sema::SubstConceptTemplateArguments( case Stmt::ConceptSpecializationExprClass: case Stmt::ParenExprClass: case Stmt::UnresolvedLookupExprClass: + case Stmt::DependentTemplateIdExprClass: return Base::TransformExpr(E); default: break; @@ -4625,43 +4626,46 @@ ExprResult Sema::SubstConceptTemplateArguments( return false; } - ExprResult TransformUnresolvedLookupExpr(UnresolvedLookupExpr *E, - bool IsAddressOfOperand = false) { - if (!E->isConceptReference()) - return E; - - assert(E->getNumDecls() == 1 && - "ConceptReference must have single declaration"); - NamedDecl *D = *E->decls_begin(); - ConceptDecl *ResolvedConcept = nullptr; - - if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { - unsigned Depth = TTP->getDepth(); - unsigned Pos = TTP->getPosition(); - if (Depth < MLTAL.getNumLevels() && - MLTAL.hasTemplateArgument(Depth, Pos)) { - TemplateArgument Arg = MLTAL(Depth, Pos); - assert(Arg.getKind() == TemplateArgument::Template); - ResolvedConcept = - dyn_cast<ConceptDecl>(Arg.getAsTemplate().getAsTemplateDecl()); - } - if (ResolvedConcept == nullptr) - return E; - } else - ResolvedConcept = cast<ConceptDecl>(D); - - TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc()); - if (TransformTemplateArguments(E->getTemplateArgs(), - E->getNumTemplateArgs(), TransArgs)) + ExprResult RebuildConceptSpecialization(ConceptDecl *ResolvedConcept, + SourceLocation NameLoc, + SourceLocation LAngleLoc, + SourceLocation RAngleLoc, + const TemplateArgumentLoc *Args, + unsigned NumArgs) { + TemplateArgumentListInfo TransArgs(LAngleLoc, RAngleLoc); + if (TransformTemplateArguments(Args, NumArgs, TransArgs)) return ExprError(); CXXScopeSpec SS; - DeclarationNameInfo NameInfo(ResolvedConcept->getDeclName(), - E->getNameLoc()); + DeclarationNameInfo NameInfo(ResolvedConcept->getDeclName(), NameLoc); return SemaRef.CheckConceptTemplateId(SS, SourceLocation(), NameInfo, ResolvedConcept, ResolvedConcept, &TransArgs, false); } + + ExprResult TransformDependentTemplateIdExpr(DependentTemplateIdExpr *E) { + if (!E->isConceptReference()) + return E; + + TemplateTemplateParmDecl *TTP = E->getParameter(); + unsigned Depth = TTP->getDepth(); + unsigned Pos = TTP->getPosition(); + ConceptDecl *ResolvedConcept = nullptr; + + if (MLTAL.hasTemplateArgument(Depth, Pos)) { + TemplateArgument Arg = MLTAL(Depth, Pos); + assert(Arg.getKind() == TemplateArgument::Template); + ResolvedConcept = + dyn_cast<ConceptDecl>(Arg.getAsTemplate().getAsTemplateDecl()); + } + if (!ResolvedConcept) + return E; + + return RebuildConceptSpecialization(ResolvedConcept, E->getNameLoc(), + E->getLAngleLoc(), E->getRAngleLoc(), + E->template_arguments().data(), + E->getNumTemplateArgs()); + } }; ConstraintExprTransformer Transformer(*this, MLTALForConstraint); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index e6abb3ad577c6..b397447ee0e52 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -16532,6 +16532,36 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr( T, E->getLParenLoc(), Args, E->getRParenLoc(), E->isListInitialization()); } +template <typename Derived> +ExprResult TreeTransform<Derived>::TransformDependentTemplateIdExpr( + DependentTemplateIdExpr *E) { + + NestedNameSpecifierLoc Loc; + TemplateName Name = getDerived().TransformTemplateName( + Loc, /*Template Keyword=*/SourceLocation(), E->getTemplateName(), + E->getNameLoc()); + if (Name.isNull()) + return ExprError(); + + TemplateDecl *TD = Name.getAsTemplateDecl(); + + assert(TD && "A dependent template id always refers to a template decl"); + + TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc()); + if (getDerived().TransformTemplateArguments( + E->template_arguments().data(), E->getNumTemplateArgs(), TransArgs)) + return ExprError(); + + CXXScopeSpec SS; + + LookupResult R(SemaRef, E->getNameInfo(), Sema::LookupOrdinaryName); + R.addDecl(TD); + R.resolveKind(); + return getDerived().RebuildTemplateIdExpr( + SS, /*Template Keyword=*/SourceLocation(), R, + /*RequiresADL=*/false, &TransArgs); +} + template<typename Derived> ExprResult TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 1afde95b05290..c2d8267b6fcea 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2095,6 +2095,17 @@ void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) { E->SubExpr = Record.readSubExpr(); } +void ASTStmtReader::VisitDependentTemplateIdExpr(DependentTemplateIdExpr *E) { + VisitExpr(E); + unsigned NumTemplateArgs = Record.readInt(); + assert(NumTemplateArgs == E->getNumTemplateArgs() && + "Wrong NumTemplateArgs!"); + ReadTemplateKWAndArgsInfo(E->KWAndArgs, E->getTrailingObjects(), + NumTemplateArgs); + E->NameInfo = Record.readDeclarationNameInfo(); + E->Name = Record.readTemplateName(); +} + void ASTStmtReader::VisitCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *E) { VisitExpr(E); @@ -4409,6 +4420,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; } + case EXPR_DEPENDENT_TEMPLATE_ID: + S = DependentTemplateIdExpr::CreateEmpty( + Context, /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]); + break; + case EXPR_CXX_DEPENDENT_SCOPE_DECL_REF: { BitsUnpacker DependentScopeDeclRefBits( Record[ASTStmtReader::NumStmtFields]); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index f34b2ff182bc8..4e9af7c721d2f 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -858,6 +858,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream, RECORD(EXPR_CXX_PSEUDO_DESTRUCTOR); RECORD(EXPR_EXPR_WITH_CLEANUPS); RECORD(EXPR_CXX_DEPENDENT_SCOPE_MEMBER); + RECORD(EXPR_DEPENDENT_TEMPLATE_ID); RECORD(EXPR_CXX_DEPENDENT_SCOPE_DECL_REF); RECORD(EXPR_CXX_UNRESOLVED_CONSTRUCT); RECORD(EXPR_CXX_UNRESOLVED_MEMBER); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 3854eabd62a46..bf90b247fd6ab 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2110,6 +2110,15 @@ void ASTStmtWriter::VisitExprWithCleanups(ExprWithCleanups *E) { Code = serialization::EXPR_EXPR_WITH_CLEANUPS; } +void ASTStmtWriter::VisitDependentTemplateIdExpr(DependentTemplateIdExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumTemplateArgs()); + AddTemplateKWAndArgsInfo(E->KWAndArgs, E->getTrailingObjects()); + Record.AddDeclarationNameInfo(E->getNameInfo()); + Record.AddTemplateName(E->getTemplateName()); + Code = serialization::EXPR_DEPENDENT_TEMPLATE_ID; +} + void ASTStmtWriter::VisitCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *E) { VisitExpr(E); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 41cc820fd547b..e6349eb4eba2a 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1701,6 +1701,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::ExpressionTraitExprClass: case Stmt::UnresolvedLookupExprClass: case Stmt::UnresolvedMemberExprClass: + case Stmt::DependentTemplateIdExprClass: case Stmt::RecoveryExprClass: case Stmt::CXXNoexceptExprClass: case Stmt::PackExpansionExprClass: diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index e27964d0ad6e1..768f5465a166a 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -614,6 +614,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::SubstNonTypeTemplateParmPackExprClass: case Stmt::FunctionParmPackExprClass: case Stmt::UnresolvedLookupExprClass: + case Stmt::DependentTemplateIdExprClass: K = CXCursor_DeclRefExpr; break; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
