forked from OSchip/llvm-project
Initial stab at implement dependent member references to member
templates, e.g., x.template get<T> We can now parse these, represent them within an UnresolvedMemberExpr expression, then instantiate that expression node in simple cases. This allows us to stumble through parsing LLVM's Casting.h. llvm-svn: 81300
This commit is contained in:
parent
c466e31309
commit
308047d3a5
clang
|
@ -1407,8 +1407,12 @@ class CXXUnresolvedMemberExpr : public Expr {
|
|||
|
||||
/// \brief Whether this member expression used the '->' operator or
|
||||
/// the '.' operator.
|
||||
bool IsArrow;
|
||||
bool IsArrow : 1;
|
||||
|
||||
/// \brief Whether this member expression has explicitly-specified template
|
||||
/// arguments.
|
||||
bool HasExplicitTemplateArgumentList : 1;
|
||||
|
||||
/// \brief The location of the '->' or '.' operator.
|
||||
SourceLocation OperatorLoc;
|
||||
|
||||
|
@ -1435,6 +1439,36 @@ class CXXUnresolvedMemberExpr : public Expr {
|
|||
/// \brief The location of the member name.
|
||||
SourceLocation MemberLoc;
|
||||
|
||||
/// \brief Retrieve the explicit template argument list that followed the
|
||||
/// member template name, if any.
|
||||
ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() {
|
||||
if (!HasExplicitTemplateArgumentList)
|
||||
return 0;
|
||||
|
||||
return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the explicit template argument list that followed the
|
||||
/// member template name, if any.
|
||||
const ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() const {
|
||||
return const_cast<CXXUnresolvedMemberExpr *>(this)
|
||||
->getExplicitTemplateArgumentList();
|
||||
}
|
||||
|
||||
CXXUnresolvedMemberExpr(ASTContext &C,
|
||||
Expr *Base, bool IsArrow,
|
||||
SourceLocation OperatorLoc,
|
||||
NestedNameSpecifier *Qualifier,
|
||||
SourceRange QualifierRange,
|
||||
NamedDecl *FirstQualifierFoundInScope,
|
||||
DeclarationName Member,
|
||||
SourceLocation MemberLoc,
|
||||
bool HasExplicitTemplateArgs,
|
||||
SourceLocation LAngleLoc,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs,
|
||||
SourceLocation RAngleLoc);
|
||||
|
||||
public:
|
||||
CXXUnresolvedMemberExpr(ASTContext &C,
|
||||
Expr *Base, bool IsArrow,
|
||||
|
@ -1444,12 +1478,28 @@ public:
|
|||
NamedDecl *FirstQualifierFoundInScope,
|
||||
DeclarationName Member,
|
||||
SourceLocation MemberLoc)
|
||||
: Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
|
||||
Base(Base), IsArrow(IsArrow), OperatorLoc(OperatorLoc),
|
||||
Qualifier(Qualifier), QualifierRange(QualifierRange),
|
||||
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
|
||||
Member(Member), MemberLoc(MemberLoc) { }
|
||||
|
||||
: Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
|
||||
Base(Base), IsArrow(IsArrow), HasExplicitTemplateArgumentList(false),
|
||||
OperatorLoc(OperatorLoc),
|
||||
Qualifier(Qualifier), QualifierRange(QualifierRange),
|
||||
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
|
||||
Member(Member), MemberLoc(MemberLoc) { }
|
||||
|
||||
static CXXUnresolvedMemberExpr *
|
||||
Create(ASTContext &C,
|
||||
Expr *Base, bool IsArrow,
|
||||
SourceLocation OperatorLoc,
|
||||
NestedNameSpecifier *Qualifier,
|
||||
SourceRange QualifierRange,
|
||||
NamedDecl *FirstQualifierFoundInScope,
|
||||
DeclarationName Member,
|
||||
SourceLocation MemberLoc,
|
||||
bool HasExplicitTemplateArgs,
|
||||
SourceLocation LAngleLoc,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs,
|
||||
SourceLocation RAngleLoc);
|
||||
|
||||
/// \brief Retrieve the base object of this member expressions,
|
||||
/// e.g., the \c x in \c x.m.
|
||||
Expr *getBase() { return cast<Expr>(Base); }
|
||||
|
@ -1497,10 +1547,57 @@ public:
|
|||
SourceLocation getMemberLoc() const { return MemberLoc; }
|
||||
void setMemberLoc(SourceLocation L) { MemberLoc = L; }
|
||||
|
||||
/// \brief Determines whether this member expression actually had a C++
|
||||
/// template argument list explicitly specified, e.g., x.f<int>.
|
||||
bool hasExplicitTemplateArgumentList() {
|
||||
return HasExplicitTemplateArgumentList;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the location of the left angle bracket following the
|
||||
/// member name ('<'), if any.
|
||||
SourceLocation getLAngleLoc() const {
|
||||
if (!HasExplicitTemplateArgumentList)
|
||||
return SourceLocation();
|
||||
|
||||
return getExplicitTemplateArgumentList()->LAngleLoc;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template arguments provided as part of this
|
||||
/// template-id.
|
||||
const TemplateArgument *getTemplateArgs() const {
|
||||
if (!HasExplicitTemplateArgumentList)
|
||||
return 0;
|
||||
|
||||
return getExplicitTemplateArgumentList()->getTemplateArgs();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the number of template arguments provided as part of this
|
||||
/// template-id.
|
||||
unsigned getNumTemplateArgs() const {
|
||||
if (!HasExplicitTemplateArgumentList)
|
||||
return 0;
|
||||
|
||||
return getExplicitTemplateArgumentList()->NumTemplateArgs;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the location of the right angle bracket following the
|
||||
/// template arguments ('>').
|
||||
SourceLocation getRAngleLoc() const {
|
||||
if (!HasExplicitTemplateArgumentList)
|
||||
return SourceLocation();
|
||||
|
||||
return getExplicitTemplateArgumentList()->RAngleLoc;
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
if (HasExplicitTemplateArgumentList)
|
||||
return SourceRange(Base->getSourceRange().getBegin(),
|
||||
getRAngleLoc());
|
||||
|
||||
return SourceRange(Base->getSourceRange().getBegin(),
|
||||
MemberLoc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXUnresolvedMemberExprClass;
|
||||
}
|
||||
|
|
|
@ -217,7 +217,7 @@ public:
|
|||
/// resolved prior to template instantiation.
|
||||
///
|
||||
/// This kind of template name refers to a dependent template name,
|
||||
/// including its nested name specifier. For example,
|
||||
/// including its nested name specifier (if any). For example,
|
||||
/// DependentTemplateName can refer to "MetaFun::template apply",
|
||||
/// where "MetaFun::" is the nested name specifier and "apply" is the
|
||||
/// template name referenced. The "template" keyword is implied.
|
||||
|
|
|
@ -3319,7 +3319,8 @@ TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
|
|||
/// template name such as \c MetaFun::template apply.
|
||||
TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
|
||||
const IdentifierInfo *Name) {
|
||||
assert(NNS->isDependent() && "Nested name specifier must be dependent");
|
||||
assert((!NNS || NNS->isDependent()) &&
|
||||
"Nested name specifier must be dependent");
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
DependentTemplateName::Profile(ID, NNS, Name);
|
||||
|
|
|
@ -523,6 +523,77 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() {
|
|||
return child_iterator(reinterpret_cast<Stmt **>(this + 1) + NumArgs);
|
||||
}
|
||||
|
||||
CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C,
|
||||
Expr *Base, bool IsArrow,
|
||||
SourceLocation OperatorLoc,
|
||||
NestedNameSpecifier *Qualifier,
|
||||
SourceRange QualifierRange,
|
||||
NamedDecl *FirstQualifierFoundInScope,
|
||||
DeclarationName Member,
|
||||
SourceLocation MemberLoc,
|
||||
bool HasExplicitTemplateArgs,
|
||||
SourceLocation LAngleLoc,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs,
|
||||
SourceLocation RAngleLoc)
|
||||
: Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
|
||||
Base(Base), IsArrow(IsArrow),
|
||||
HasExplicitTemplateArgumentList(HasExplicitTemplateArgs),
|
||||
OperatorLoc(OperatorLoc),
|
||||
Qualifier(Qualifier), QualifierRange(QualifierRange),
|
||||
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
|
||||
Member(Member), MemberLoc(MemberLoc)
|
||||
{
|
||||
if (HasExplicitTemplateArgumentList) {
|
||||
ExplicitTemplateArgumentList *ETemplateArgs
|
||||
= getExplicitTemplateArgumentList();
|
||||
ETemplateArgs->LAngleLoc = LAngleLoc;
|
||||
ETemplateArgs->RAngleLoc = RAngleLoc;
|
||||
ETemplateArgs->NumTemplateArgs = NumTemplateArgs;
|
||||
|
||||
TemplateArgument *SavedTemplateArgs = ETemplateArgs->getTemplateArgs();
|
||||
for (unsigned I = 0; I < NumTemplateArgs; ++I)
|
||||
new (SavedTemplateArgs + I) TemplateArgument(TemplateArgs[I]);
|
||||
}
|
||||
}
|
||||
|
||||
CXXUnresolvedMemberExpr *
|
||||
CXXUnresolvedMemberExpr::Create(ASTContext &C,
|
||||
Expr *Base, bool IsArrow,
|
||||
SourceLocation OperatorLoc,
|
||||
NestedNameSpecifier *Qualifier,
|
||||
SourceRange QualifierRange,
|
||||
NamedDecl *FirstQualifierFoundInScope,
|
||||
DeclarationName Member,
|
||||
SourceLocation MemberLoc,
|
||||
bool HasExplicitTemplateArgs,
|
||||
SourceLocation LAngleLoc,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs,
|
||||
SourceLocation RAngleLoc)
|
||||
{
|
||||
if (!HasExplicitTemplateArgs)
|
||||
return new (C) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc,
|
||||
Qualifier, QualifierRange,
|
||||
FirstQualifierFoundInScope,
|
||||
Member, MemberLoc);
|
||||
|
||||
void *Mem = C.Allocate(sizeof(CXXUnresolvedMemberExpr) +
|
||||
sizeof(ExplicitTemplateArgumentList) +
|
||||
sizeof(TemplateArgument) * NumTemplateArgs,
|
||||
llvm::alignof<CXXUnresolvedMemberExpr>());
|
||||
return new (Mem) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc,
|
||||
Qualifier, QualifierRange,
|
||||
FirstQualifierFoundInScope,
|
||||
Member,
|
||||
MemberLoc,
|
||||
HasExplicitTemplateArgs,
|
||||
LAngleLoc,
|
||||
TemplateArgs,
|
||||
NumTemplateArgs,
|
||||
RAngleLoc);
|
||||
}
|
||||
|
||||
Stmt::child_iterator CXXUnresolvedMemberExpr::child_begin() {
|
||||
return child_iterator(&Base);
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ NestedNameSpecifier *
|
|||
NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
|
||||
IdentifierInfo *II) {
|
||||
assert(II && "Identifier cannot be NULL");
|
||||
assert(Prefix && Prefix->isDependent() && "Prefix must be dependent");
|
||||
assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent");
|
||||
|
||||
NestedNameSpecifier Mockup;
|
||||
Mockup.Prefix.setPointer(Prefix);
|
||||
|
|
|
@ -493,12 +493,10 @@ 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) {
|
||||
|
@ -1154,7 +1152,18 @@ void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) {
|
|||
OS << (Node->isArrow() ? "->" : ".");
|
||||
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
|
||||
Qualifier->print(OS, Policy);
|
||||
else if (Node->hasExplicitTemplateArgumentList())
|
||||
// FIXME: Track use of "template" keyword explicitly?
|
||||
OS << "template ";
|
||||
|
||||
OS << Node->getMember().getAsString();
|
||||
|
||||
if (Node->hasExplicitTemplateArgumentList()) {
|
||||
OS << TemplateSpecializationType::PrintTemplateArgumentList(
|
||||
Node->getTemplateArgs(),
|
||||
Node->getNumTemplateArgs(),
|
||||
Policy);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *getTypeTraitName(UnaryTypeTrait UTT) {
|
||||
|
|
|
@ -67,7 +67,7 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
|
|||
OS << "template ";
|
||||
OS << QTN->getDecl()->getNameAsString();
|
||||
} else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
|
||||
if (!SuppressNNS)
|
||||
if (!SuppressNNS && DTN->getQualifier())
|
||||
DTN->getQualifier()->print(OS, Policy);
|
||||
OS << "template ";
|
||||
// FIXME: Shouldn't we have a more general kind of name?
|
||||
|
|
|
@ -918,8 +918,10 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
|
|||
ConsumeParen();
|
||||
break;
|
||||
}
|
||||
case tok::arrow: // postfix-expression: p-e '->' identifier
|
||||
case tok::period: { // postfix-expression: p-e '.' identifier
|
||||
case tok::arrow:
|
||||
case tok::period: {
|
||||
// postfix-expression: p-e '->' template[opt] id-expression
|
||||
// postfix-expression: p-e '.' template[opt] id-expression
|
||||
tok::TokenKind OpKind = Tok.getKind();
|
||||
SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token.
|
||||
|
||||
|
|
|
@ -76,7 +76,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
if (HasScopeSpecifier) {
|
||||
// C++ [basic.lookup.classref]p5:
|
||||
// If the qualified-id has the form
|
||||
//
|
||||
// ::class-name-or-namespace-name::...
|
||||
//
|
||||
// the class-name-or-namespace-name is looked up in global scope as a
|
||||
// class-name or namespace-name.
|
||||
//
|
||||
|
|
|
@ -2029,14 +2029,17 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
|
||||
}
|
||||
|
||||
return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
|
||||
BaseExpr, true,
|
||||
OpLoc,
|
||||
Qualifier,
|
||||
return Owned(CXXUnresolvedMemberExpr::Create(Context, BaseExpr, true,
|
||||
OpLoc, Qualifier,
|
||||
SS? SS->getRange() : SourceRange(),
|
||||
FirstQualifierInScope,
|
||||
MemberName,
|
||||
MemberLoc));
|
||||
FirstQualifierInScope,
|
||||
MemberName,
|
||||
MemberLoc,
|
||||
HasExplicitTemplateArgs,
|
||||
LAngleLoc,
|
||||
ExplicitTemplateArgs,
|
||||
NumExplicitTemplateArgs,
|
||||
RAngleLoc));
|
||||
}
|
||||
else if (const PointerType *PT = BaseType->getAs<PointerType>())
|
||||
BaseType = PT->getPointeeType();
|
||||
|
@ -2067,14 +2070,19 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
|
||||
}
|
||||
|
||||
return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
|
||||
BaseExpr, false,
|
||||
OpLoc,
|
||||
Qualifier,
|
||||
return Owned(CXXUnresolvedMemberExpr::Create(Context,
|
||||
BaseExpr, false,
|
||||
OpLoc,
|
||||
Qualifier,
|
||||
SS? SS->getRange() : SourceRange(),
|
||||
FirstQualifierInScope,
|
||||
MemberName,
|
||||
MemberLoc));
|
||||
FirstQualifierInScope,
|
||||
MemberName,
|
||||
MemberLoc,
|
||||
HasExplicitTemplateArgs,
|
||||
LAngleLoc,
|
||||
ExplicitTemplateArgs,
|
||||
NumExplicitTemplateArgs,
|
||||
RAngleLoc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1229,7 +1229,7 @@ Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base,
|
|||
else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl())
|
||||
Name = Ovl->getDeclName();
|
||||
else
|
||||
assert(false && "Cannot support dependent template names yet");
|
||||
Name = Template.getAsDependentTemplateName()->getName();
|
||||
|
||||
// Translate the parser's template argument list in our AST format.
|
||||
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
|
||||
|
@ -1287,11 +1287,6 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
|
|||
return Template;
|
||||
}
|
||||
|
||||
// FIXME: We need to be able to create a dependent template name with just
|
||||
// an identifier, to handle the x->template f<T> case.
|
||||
assert(!ObjectType &&
|
||||
"Cannot handle dependent template names without a nested-name-specifier");
|
||||
|
||||
NestedNameSpecifier *Qualifier
|
||||
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
|
||||
return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name));
|
||||
|
|
|
@ -261,7 +261,8 @@ public:
|
|||
/// By default, transforms the template name by transforming the declarations
|
||||
/// and nested-name-specifiers that occur within the template name.
|
||||
/// Subclasses may override this function to provide alternate behavior.
|
||||
TemplateName TransformTemplateName(TemplateName Name);
|
||||
TemplateName TransformTemplateName(TemplateName Name,
|
||||
QualType ObjectType = QualType());
|
||||
|
||||
/// \brief Transform the given template argument.
|
||||
///
|
||||
|
@ -567,7 +568,8 @@ public:
|
|||
/// template name. Subclasses may override this routine to provide different
|
||||
/// behavior.
|
||||
TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
|
||||
const IdentifierInfo &II);
|
||||
const IdentifierInfo &II,
|
||||
QualType ObjectType);
|
||||
|
||||
|
||||
/// \brief Build a new compound statement.
|
||||
|
@ -1510,16 +1512,58 @@ public:
|
|||
SS.setRange(QualifierRange);
|
||||
SS.setScopeRep(Qualifier);
|
||||
|
||||
Base = SemaRef.BuildMemberReferenceExpr(/*Scope=*/0,
|
||||
return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0,
|
||||
move(Base), OperatorLoc, OpKind,
|
||||
MemberLoc,
|
||||
Name,
|
||||
/*FIXME?*/Sema::DeclPtrTy::make((Decl*)0),
|
||||
&SS,
|
||||
FirstQualifierInScope);
|
||||
return move(Base);
|
||||
}
|
||||
|
||||
/// \brief Build a new member reference expression with explicit template
|
||||
/// arguments.
|
||||
///
|
||||
/// By default, performs semantic analysis to build the new expression.
|
||||
/// Subclasses may override this routine to provide different behavior.
|
||||
OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE,
|
||||
bool IsArrow,
|
||||
SourceLocation OperatorLoc,
|
||||
NestedNameSpecifier *Qualifier,
|
||||
SourceRange QualifierRange,
|
||||
TemplateName Template,
|
||||
SourceLocation TemplateNameLoc,
|
||||
NamedDecl *FirstQualifierInScope,
|
||||
SourceLocation LAngleLoc,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs,
|
||||
SourceLocation RAngleLoc) {
|
||||
OwningExprResult Base = move(BaseE);
|
||||
tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
|
||||
|
||||
CXXScopeSpec SS;
|
||||
SS.setRange(QualifierRange);
|
||||
SS.setScopeRep(Qualifier);
|
||||
|
||||
// FIXME: We're going to end up looking up the template based on its name,
|
||||
// twice! Also, duplicates part of Sema::ActOnMemberTemplateIdReferenceExpr.
|
||||
DeclarationName Name;
|
||||
if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl())
|
||||
Name = ActualTemplate->getDeclName();
|
||||
else if (OverloadedFunctionDecl *Ovl
|
||||
= Template.getAsOverloadedFunctionDecl())
|
||||
Name = Ovl->getDeclName();
|
||||
else
|
||||
Name = Template.getAsDependentTemplateName()->getName();
|
||||
|
||||
return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, move(Base),
|
||||
OperatorLoc, OpKind,
|
||||
TemplateNameLoc, Name, true,
|
||||
LAngleLoc, TemplateArgs,
|
||||
NumTemplateArgs, RAngleLoc,
|
||||
Sema::DeclPtrTy(), &SS);
|
||||
}
|
||||
|
||||
/// \brief Build a new Objective-C @encode expression.
|
||||
///
|
||||
/// By default, performs semantic analysis to build the new expression.
|
||||
|
@ -1746,7 +1790,8 @@ TreeTransform<Derived>::TransformDeclarationName(DeclarationName Name,
|
|||
|
||||
template<typename Derived>
|
||||
TemplateName
|
||||
TreeTransform<Derived>::TransformTemplateName(TemplateName Name) {
|
||||
TreeTransform<Derived>::TransformTemplateName(TemplateName Name,
|
||||
QualType ObjectType) {
|
||||
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
|
||||
NestedNameSpecifier *NNS
|
||||
= getDerived().TransformNestedNameSpecifier(QTN->getQualifier(),
|
||||
|
@ -1789,14 +1834,14 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name) {
|
|||
NestedNameSpecifier *NNS
|
||||
= getDerived().TransformNestedNameSpecifier(DTN->getQualifier(),
|
||||
/*FIXME:*/SourceRange(getDerived().getBaseLocation()));
|
||||
if (!NNS)
|
||||
if (!NNS && DTN->getQualifier())
|
||||
return TemplateName();
|
||||
|
||||
if (!getDerived().AlwaysRebuild() &&
|
||||
NNS == DTN->getQualifier())
|
||||
return Name;
|
||||
|
||||
return getDerived().RebuildTemplateName(NNS, *DTN->getName());
|
||||
return getDerived().RebuildTemplateName(NNS, *DTN->getName(), ObjectType);
|
||||
}
|
||||
|
||||
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
|
||||
|
@ -4195,6 +4240,9 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
|
|||
if (Base.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
|
||||
// FIXME: The first qualifier found might be a template type parameter,
|
||||
// in which case there is no transformed declaration to refer to (it might
|
||||
// refer to a built-in type!).
|
||||
NamedDecl *FirstQualifierInScope
|
||||
= cast_or_null<NamedDecl>(
|
||||
getDerived().TransformDecl(E->getFirstQualifierFoundInScope()));
|
||||
|
@ -4214,21 +4262,60 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
|
|||
if (!Name)
|
||||
return SemaRef.ExprError();
|
||||
|
||||
if (!getDerived().AlwaysRebuild() &&
|
||||
Base.get() == E->getBase() &&
|
||||
Qualifier == E->getQualifier() &&
|
||||
Name == E->getMember() &&
|
||||
FirstQualifierInScope == E->getFirstQualifierFoundInScope())
|
||||
return SemaRef.Owned(E->Retain());
|
||||
if (!E->hasExplicitTemplateArgumentList()) {
|
||||
// This is a reference to a member without an explicitly-specified
|
||||
// template argument list. Optimize for this common case.
|
||||
if (!getDerived().AlwaysRebuild() &&
|
||||
Base.get() == E->getBase() &&
|
||||
Qualifier == E->getQualifier() &&
|
||||
Name == E->getMember() &&
|
||||
FirstQualifierInScope == E->getFirstQualifierFoundInScope())
|
||||
return SemaRef.Owned(E->Retain());
|
||||
|
||||
return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base),
|
||||
E->isArrow(),
|
||||
E->getOperatorLoc(),
|
||||
Qualifier,
|
||||
E->getQualifierRange(),
|
||||
Name,
|
||||
E->getMemberLoc(),
|
||||
FirstQualifierInScope);
|
||||
}
|
||||
|
||||
// FIXME: This is an ugly hack, which forces the same template name to
|
||||
// be looked up multiple times. Yuck!
|
||||
// FIXME: This also won't work for, e.g., x->template operator+<int>
|
||||
TemplateName OrigTemplateName
|
||||
= SemaRef.Context.getDependentTemplateName(0, Name.getAsIdentifierInfo());
|
||||
|
||||
TemplateName Template
|
||||
= getDerived().TransformTemplateName(OrigTemplateName,
|
||||
QualType::getFromOpaquePtr(ObjectType));
|
||||
if (Template.isNull())
|
||||
return SemaRef.ExprError();
|
||||
|
||||
llvm::SmallVector<TemplateArgument, 4> TransArgs;
|
||||
for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) {
|
||||
TemplateArgument TransArg
|
||||
= getDerived().TransformTemplateArgument(E->getTemplateArgs()[I]);
|
||||
if (TransArg.isNull())
|
||||
return SemaRef.ExprError();
|
||||
|
||||
TransArgs.push_back(TransArg);
|
||||
}
|
||||
|
||||
return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base),
|
||||
E->isArrow(),
|
||||
E->getOperatorLoc(),
|
||||
Qualifier,
|
||||
E->getQualifierRange(),
|
||||
Name,
|
||||
Template,
|
||||
E->getMemberLoc(),
|
||||
FirstQualifierInScope);
|
||||
FirstQualifierInScope,
|
||||
E->getLAngleLoc(),
|
||||
TransArgs.data(),
|
||||
TransArgs.size(),
|
||||
E->getRAngleLoc());
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
|
@ -4643,33 +4730,18 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
|
|||
template<typename Derived>
|
||||
TemplateName
|
||||
TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
|
||||
const IdentifierInfo &II) {
|
||||
if (Qualifier->isDependent())
|
||||
return SemaRef.Context.getDependentTemplateName(Qualifier, &II);
|
||||
|
||||
// Somewhat redundant with ActOnDependentTemplateName.
|
||||
const IdentifierInfo &II,
|
||||
QualType ObjectType) {
|
||||
CXXScopeSpec SS;
|
||||
SS.setRange(SourceRange(getDerived().getBaseLocation()));
|
||||
SS.setScopeRep(Qualifier);
|
||||
Sema::TemplateTy Template;
|
||||
TemplateNameKind TNK = SemaRef.isTemplateName(0, II,
|
||||
/*FIXME:*/getDerived().getBaseLocation(),
|
||||
&SS,
|
||||
/*FIXME:ObjectType=*/0, false,
|
||||
Template);
|
||||
if (TNK == TNK_Non_template) {
|
||||
SemaRef.Diag(getDerived().getBaseLocation(),
|
||||
diag::err_template_kw_refers_to_non_template)
|
||||
<< &II;
|
||||
return TemplateName();
|
||||
} else if (TNK == TNK_Function_template) {
|
||||
SemaRef.Diag(getDerived().getBaseLocation(),
|
||||
diag::err_template_kw_refers_to_non_template)
|
||||
<< &II;
|
||||
return TemplateName();
|
||||
}
|
||||
|
||||
return Template.getAsVal<TemplateName>();
|
||||
SS.setScopeRep(Qualifier);
|
||||
return getSema().ActOnDependentTemplateName(
|
||||
/*FIXME:*/getDerived().getBaseLocation(),
|
||||
II,
|
||||
/*FIXME:*/getDerived().getBaseLocation(),
|
||||
SS,
|
||||
ObjectType.getAsOpaquePtr())
|
||||
.template getAsVal<TemplateName>();
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
template<typename U, typename T>
|
||||
U f0(T t) {
|
||||
return t.template get<U>();
|
||||
}
|
||||
|
||||
template<typename U, typename T>
|
||||
int &f1(T t) {
|
||||
// FIXME: When we pretty-print this, we lose the "template" keyword.
|
||||
return t.U::template get<int&>();
|
||||
}
|
||||
|
||||
struct X {
|
||||
template<typename T> T get();
|
||||
};
|
||||
|
||||
void test_f0(X x) {
|
||||
int i = f0<int>(x);
|
||||
int &ir = f0<int&>(x);
|
||||
}
|
||||
|
||||
struct XDerived : public X {
|
||||
};
|
||||
|
||||
void test_f1(XDerived xd) {
|
||||
// FIXME: Not quite functional yet.
|
||||
// int &ir = f1<X>(xd);
|
||||
}
|
||||
|
Loading…
Reference in New Issue