/// \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;
/// \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,
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); }
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;
}
/// 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.
/// 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);
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);
}
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);
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) {
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) {
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?
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.
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.
//
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();
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));
}
}
}
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;
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));
/// 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.
///
/// 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.
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.
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(),
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()) {
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()));
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>
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>
--- /dev/null
+// 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);
+}
+