forked from OSchip/llvm-project
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:
parent
0a25d6857a
commit
a727cb98a4
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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> >());
|
||||
}
|
||||
|
Loading…
Reference in New Issue