Preliminary parsing and ASTs for template-ids that refer to function

templates, such as make<int&>. These template-ids are only barely
functional for function calls; much more to come.

llvm-svn: 74563
This commit is contained in:
Douglas Gregor 2009-06-30 22:34:41 +00:00
parent 0a25d6857a
commit a727cb98a4
12 changed files with 316 additions and 17 deletions

View File

@ -1017,6 +1017,100 @@ public:
virtual StmtIterator child_end();
};
/// \brief An expression that refers to a C++ template-id, such as
/// @c isa<FunctionDecl>.
class TemplateIdRefExpr : public Expr {
/// \brief If this template-id was qualified-id, e.g., @c std::sort<int>,
/// this nested name specifier contains the @c std::.
NestedNameSpecifier *Qualifier;
/// \brief If this template-id was a qualified-id, e.g., @c std::sort<int>,
/// 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<int>, 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<int>;
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<int>.
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<const TemplateArgument *>(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;

View File

@ -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)

View File

@ -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

View File

@ -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<TemplateArgument *> (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");

View File

@ -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());

View File

@ -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));

View File

@ -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<TemplateIdAnnotation *>(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.");

View File

@ -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,

View File

@ -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<UnaryOperator>(FnExpr)->getOpcode()
== UnaryOperator::AddrOf) {
FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
} else if ((DRExpr = dyn_cast<DeclRefExpr>(FnExpr))) {
} else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) {
// Qualified names disable ADL (C++0x [basic.lookup.argdep]p1).
ADL &= !isa<QualifiedDeclRefExpr>(DRExpr);
NDecl = dyn_cast<NamedDecl>(DRExpr->getDecl());
break;
} else if (UnresolvedFunctionNameExpr *DepName
= dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) {
UnqualifiedName = DepName->getName();
break;
} else if (TemplateIdRefExpr *TemplateIdRef
= dyn_cast<TemplateIdRefExpr>(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<FunctionDecl>(DRExpr->getDecl());
if ((FunctionTemplate = dyn_cast<FunctionTemplateDecl>(DRExpr->getDecl())))
if (NDecl) {
FDecl = dyn_cast<FunctionDecl>(NDecl);
if ((FunctionTemplate = dyn_cast<FunctionTemplateDecl>(NDecl)))
FDecl = FunctionTemplate->getTemplatedDecl();
else
FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
Ovl = dyn_cast<OverloadedFunctionDecl>(DRExpr->getDecl());
NDecl = dyn_cast<NamedDecl>(DRExpr->getDecl());
FDecl = dyn_cast<FunctionDecl>(NDecl);
Ovl = dyn_cast<OverloadedFunctionDecl>(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<QualifiedDeclRefExpr>(DRExpr))
= dyn_cast<QualifiedDeclRefExpr>(FnExpr))
NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(),
QDRExpr->getLocation(),
false, false,

View File

@ -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<TemplateName>();
// Translate the parser's template argument list in our AST format.
llvm::SmallVector<TemplateArgument, 16> 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

View File

@ -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<TemplateArgument, 4> 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();

View File

@ -0,0 +1,11 @@
// RUN: clang-cc -fsyntax-only %s
template<typename T> struct A { };
template<typename T> T make(A<T>);
void test_make() {
int& ir0 = make<int&>(A<int&>());
A<int> a0 = make< A<int> >(A<A<int> >());
}