From: Douglas Gregor Date: Tue, 30 Jun 2009 22:34:41 +0000 (+0000) Subject: Preliminary parsing and ASTs for template-ids that refer to function X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=edce4dd44732dfad69f28822dddcf2b8e92b4483;p=clang Preliminary parsing and ASTs for template-ids that refer to function templates, such as make. These template-ids are only barely functional for function calls; much more to come. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74563 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index f9f5da1291..7d76a49d12 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1017,6 +1017,100 @@ public: virtual StmtIterator child_end(); }; +/// \brief An expression that refers to a C++ template-id, such as +/// @c isa. +class TemplateIdRefExpr : public Expr { + /// \brief If this template-id was qualified-id, e.g., @c std::sort, + /// this nested name specifier contains the @c std::. + NestedNameSpecifier *Qualifier; + + /// \brief If this template-id was a qualified-id, e.g., @c std::sort, + /// this covers the source code range of the @c std::. + SourceRange QualifierRange; + + /// \brief The actual template to which this template-id refers. + TemplateName Template; + + /// \brief The source location of the template name. + SourceLocation TemplateNameLoc; + + /// \brief The source location of the left angle bracket ('<'); + SourceLocation LAngleLoc; + + /// \brief The source location of the right angle bracket ('>'); + SourceLocation RAngleLoc; + + /// \brief The number of template arguments in TemplateArgs. + unsigned NumTemplateArgs; + + TemplateIdRefExpr(QualType T, + NestedNameSpecifier *Qualifier, SourceRange QualifierRange, + TemplateName Template, SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc); + +public: + static TemplateIdRefExpr * + Create(ASTContext &Context, QualType T, + NestedNameSpecifier *Qualifier, SourceRange QualifierRange, + TemplateName Template, SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, SourceLocation RAngleLoc); + + void Destroy(ASTContext &Context); + + /// \brief Retrieve the nested name specifier used to qualify the name of + /// this template-id, e.g., the "std::sort" in @c std::sort, or NULL + /// if this template-id was an unqualified-id. + NestedNameSpecifier *getQualifier() const { return Qualifier; } + + /// \brief Retrieve the source range describing the nested name specifier + /// used to qualified the name of this template-id, if the name was qualified. + SourceRange getQualifierRange() const { return QualifierRange; } + + /// \brief Retrieve the name of the template referenced, e.g., "sort" in + /// @c std::sort; + TemplateName getTemplateName() const { return Template; } + + /// \brief Retrieve the location of the name of the template referenced, e.g., + /// the location of "sort" in @c std::sort. + SourceLocation getTemplateNameLoc() const { return TemplateNameLoc; } + + /// \brief Retrieve the location of the left angle bracket following the + /// template name ('<'). + SourceLocation getLAngleLoc() const { return LAngleLoc; } + + /// \brief Retrieve the template arguments provided as part of this + /// template-id. + const TemplateArgument *getTemplateArgs() const { + return reinterpret_cast(this + 1); + } + + /// \brief Retrieve the number of template arguments provided as part of this + /// template-id. + unsigned getNumTemplateArgs() const { return NumTemplateArgs; } + + /// \brief Retrieve the location of the right angle bracket following the + /// template arguments ('>'). + SourceLocation getRAngleLoc() const { return RAngleLoc; } + + virtual SourceRange getSourceRange() const { + return SourceRange(Qualifier? QualifierRange.getBegin() : TemplateNameLoc, + RAngleLoc); + } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == TemplateIdRefExprClass; + } + static bool classof(const TemplateIdRefExpr *) { return true; } +}; + class CXXExprWithTemporaries : public Expr { Stmt *SubExpr; diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index ab6524663d..a95a627311 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -9,7 +9,7 @@ // // This file defines the AST Node info database. // -//===----------------------------------------------------------------------===// +//===---------------------------------------------------------------------===// #ifndef FIRST_STMT #define FIRST_STMT(CLASS) @@ -123,6 +123,7 @@ EXPR(UnresolvedFunctionNameExpr , Expr) EXPR(UnaryTypeTraitExpr , Expr) EXPR(QualifiedDeclRefExpr , DeclRefExpr) EXPR(UnresolvedDeclRefExpr , Expr) +EXPR(TemplateIdRefExpr , Expr) EXPR(CXXConstructExpr , Expr) EXPR(CXXBindTemporaryExpr , Expr) EXPR(CXXExprWithTemporaries , Expr) diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index bfb74748c5..04acbc4be9 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -1379,6 +1379,24 @@ public: return TypeResult(); }; + /// \brief Form a reference to a template-id (that will refer to a function) + /// from a template and a list of template arguments. + /// + /// This action forms an expression that references the given template-id, + /// possibly checking well-formedness of the template arguments. It does not + /// imply the declaration of any entity. + /// + /// \param Template A template whose specialization results in a + /// function or a dependent template. + virtual OwningExprResult ActOnTemplateIdExpr(TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc) { + return ExprError(); + } + /// \brief Form a dependent template name. /// /// This action forms a dependent template name given the template diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 18c0f77ab2..399c30255a 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" using namespace clang; @@ -153,6 +154,65 @@ StmtIterator UnresolvedDeclRefExpr::child_end() { return child_iterator(); } +TemplateIdRefExpr::TemplateIdRefExpr(QualType T, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + TemplateName Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc) + : Expr(TemplateIdRefExprClass, T, + (Template.isDependent() || + TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs, NumTemplateArgs)), + (Template.isDependent() || + TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs, NumTemplateArgs))), + Qualifier(Qualifier), QualifierRange(QualifierRange), Template(Template), + TemplateNameLoc(TemplateNameLoc), LAngleLoc(LAngleLoc), + RAngleLoc(RAngleLoc), NumTemplateArgs(NumTemplateArgs) + +{ + TemplateArgument *StoredTemplateArgs + = reinterpret_cast (this+1); + for (unsigned I = 0; I != NumTemplateArgs; ++I) + new (StoredTemplateArgs + I) TemplateArgument(TemplateArgs[I]); +} + +TemplateIdRefExpr * +TemplateIdRefExpr::Create(ASTContext &Context, QualType T, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + TemplateName Template, SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, SourceLocation RAngleLoc) { + void *Mem = Context.Allocate(sizeof(TemplateIdRefExpr) + + sizeof(TemplateArgument) * NumTemplateArgs); + return new (Mem) TemplateIdRefExpr(T, Qualifier, QualifierRange, Template, + TemplateNameLoc, LAngleLoc, TemplateArgs, + NumTemplateArgs, RAngleLoc); +} + +void TemplateIdRefExpr::Destroy(ASTContext &Context) { + const TemplateArgument *TemplateArgs = getTemplateArgs(); + for (unsigned I = 0; I != NumTemplateArgs; ++I) + if (Expr *E = TemplateArgs[I].getAsExpr()) + E->Destroy(Context); +} + +Stmt::child_iterator TemplateIdRefExpr::child_begin() { + // FIXME: Walk the expressions in the template arguments (?) + return Stmt::child_iterator(); +} + +Stmt::child_iterator TemplateIdRefExpr::child_end() { + // FIXME: Walk the expressions in the template arguments (?) + return Stmt::child_iterator(); +} + bool UnaryTypeTraitExpr::EvaluateTrait() const { switch(UTT) { default: assert(false && "Unknown type trait or not implemented"); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 825a873d06..fec17fb223 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -490,6 +490,18 @@ void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) { OS << Node->getDeclName().getAsString(); } +void StmtPrinter::VisitTemplateIdRefExpr(TemplateIdRefExpr *Node) { + if (Node->getQualifier()) + Node->getQualifier()->print(OS, Policy); + Node->getTemplateName().print(OS, Policy, true); + OS << '<'; + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); + OS << '>'; +} + void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { if (Node->getBase()) { PrintExpr(Node->getBase()); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index ee2f209fff..cd7618f665 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -777,7 +777,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::annot_cxxscope: // [C++] id-expression: qualified-id case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id - // template-id + case tok::annot_template_id: // [C++] template-id Res = ParseCXXIdExpression(isAddressOfOperand); return ParsePostfixExpressionSuffix(move(Res)); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index d89f1e172f..1220b2d27b 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -207,13 +207,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { /// operator-function-id /// conversion-function-id [TODO] /// '~' class-name [TODO] -/// template-id [TODO] +/// template-id /// /// qualified-id: /// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id /// '::' identifier /// '::' operator-function-id -/// '::' template-id [TODO] +/// '::' template-id /// /// nested-name-specifier: /// type-name '::' @@ -264,7 +264,7 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // operator-function-id // conversion-function-id // '~' class-name [TODO] - // template-id [TODO] + // template-id // switch (Tok.getKind()) { default: @@ -294,6 +294,29 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { return ExprError(); } + case tok::annot_template_id: { + TemplateIdAnnotation *TemplateId + = static_cast(Tok.getAnnotationValue()); + assert((TemplateId->Kind == TNK_Function_template || + TemplateId->Kind == TNK_Dependent_template_name) && + "A template type name is not an ID expression"); + + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->getTemplateArgIsType(), + TemplateId->NumArgs); + + OwningExprResult Result + = Actions.ActOnTemplateIdExpr(TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->getTemplateArgLocations(), + TemplateId->RAngleLoc); + ConsumeToken(); // Consume the template-id token + return move(Result); + } + } // switch. assert(0 && "The switch was supposed to take care everything."); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 308a78c80c..65b5f25029 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2075,6 +2075,20 @@ public: SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc); + OwningExprResult BuildTemplateIdExpr(TemplateName Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc); + + virtual OwningExprResult ActOnTemplateIdExpr(TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc); + virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index d66b002578..2ee3c992b6 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2635,7 +2635,6 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, } // If we're directly calling a function, get the appropriate declaration. - DeclRefExpr *DRExpr = NULL; Expr *FnExpr = Fn; bool ADL = true; while (true) { @@ -2650,14 +2649,19 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, cast(FnExpr)->getOpcode() == UnaryOperator::AddrOf) { FnExpr = cast(FnExpr)->getSubExpr(); - } else if ((DRExpr = dyn_cast(FnExpr))) { + } else if (DeclRefExpr *DRExpr = dyn_cast(FnExpr)) { // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1). ADL &= !isa(DRExpr); + NDecl = dyn_cast(DRExpr->getDecl()); break; } else if (UnresolvedFunctionNameExpr *DepName = dyn_cast(FnExpr)) { UnqualifiedName = DepName->getName(); break; + } else if (TemplateIdRefExpr *TemplateIdRef + = dyn_cast(FnExpr)) { + NDecl = TemplateIdRef->getTemplateName().getAsTemplateDecl(); + break; } else { // Any kind of name that does not refer to a declaration (or // set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3). @@ -2668,14 +2672,13 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, OverloadedFunctionDecl *Ovl = 0; FunctionTemplateDecl *FunctionTemplate = 0; - if (DRExpr) { - FDecl = dyn_cast(DRExpr->getDecl()); - if ((FunctionTemplate = dyn_cast(DRExpr->getDecl()))) + if (NDecl) { + FDecl = dyn_cast(NDecl); + if ((FunctionTemplate = dyn_cast(NDecl))) FDecl = FunctionTemplate->getTemplatedDecl(); else - FDecl = dyn_cast(DRExpr->getDecl()); - Ovl = dyn_cast(DRExpr->getDecl()); - NDecl = dyn_cast(DRExpr->getDecl()); + FDecl = dyn_cast(NDecl); + Ovl = dyn_cast(NDecl); } if (Ovl || FunctionTemplate || @@ -2689,16 +2692,15 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, ADL = false; if (Ovl || FunctionTemplate || ADL) { - FDecl = ResolveOverloadedCallFn(Fn, DRExpr? DRExpr->getDecl() : 0, - UnqualifiedName, LParenLoc, Args, - NumArgs, CommaLocs, RParenLoc, ADL); + FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName, LParenLoc, + Args, NumArgs, CommaLocs, RParenLoc, ADL); if (!FDecl) return ExprError(); // Update Fn to refer to the actual function selected. Expr *NewFn = 0; if (QualifiedDeclRefExpr *QDRExpr - = dyn_cast_or_null(DRExpr)) + = dyn_cast(FnExpr)) NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(), QDRExpr->getLocation(), false, false, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index e2f6d33827..d72fcf8adc 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -933,6 +933,42 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, return Result.getAsOpaquePtr(); } +Sema::OwningExprResult Sema::BuildTemplateIdExpr(TemplateName Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc) { + // FIXME: Can we do any checking at this point? I guess we could check the + // template arguments that we have against the template name, if the template + // name refers to a single template. That's not a terribly common case, + // though. + return Owned(TemplateIdRefExpr::Create(Context, + /*FIXME: New type?*/Context.OverloadTy, + /*FIXME: Necessary?*/0, + /*FIXME: Necessary?*/SourceRange(), + Template, TemplateNameLoc, LAngleLoc, + TemplateArgs, + NumTemplateArgs, RAngleLoc)); +} + +Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc) { + TemplateName Template = TemplateD.getAsVal(); + + // Translate the parser's template argument list in our AST format. + llvm::SmallVector TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + + return BuildTemplateIdExpr(Template, TemplateNameLoc, LAngleLoc, + TemplateArgs.data(), TemplateArgs.size(), + RAngleLoc); +} + /// \brief Form a dependent template name. /// /// This action forms a dependent template name given the template diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp index 719a9eda47..58896d48fa 100644 --- a/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -106,6 +106,34 @@ TemplateExprInstantiator::VisitUnresolvedFunctionNameExpr( return SemaRef.Clone(E); } +Sema::OwningExprResult +TemplateExprInstantiator::VisitTemplateIdRefExpr(TemplateIdRefExpr *E) { + TemplateName Template + = SemaRef.InstantiateTemplateName(E->getTemplateName(), E->getTemplateNameLoc(), + TemplateArgs); + // FIXME: Can InstantiateTemplateName report an error? + + llvm::SmallVector InstantiatedArgs; + for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { + TemplateArgument InstArg = SemaRef.Instantiate(E->getTemplateArgs()[I], + TemplateArgs); + if (InstArg.isNull()) + return SemaRef.ExprError(); + + InstantiatedArgs.push_back(InstArg); + } + + // FIXME: It's possible that we'll find out now that the template name + // actually refers to a type, in which case this is a functional cast. + // Implement this! + + return SemaRef.BuildTemplateIdExpr(Template, E->getTemplateNameLoc(), + E->getLAngleLoc(), + InstantiatedArgs.data(), + InstantiatedArgs.size(), + E->getRAngleLoc()); +} + Sema::OwningExprResult TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) { NamedDecl *D = E->getDecl(); diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p1.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p1.cpp new file mode 100644 index 0000000000..97c5ce96f6 --- /dev/null +++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p1.cpp @@ -0,0 +1,11 @@ +// RUN: clang-cc -fsyntax-only %s + +template struct A { }; + +template T make(A); + +void test_make() { + int& ir0 = make(A()); + A a0 = make< A >(A >()); +} +