summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-09-09 00:23:06 +0000
committerDouglas Gregor <dgregor@apple.com>2009-09-09 00:23:06 +0000
commit3b6afbb99a1c44b4076f8e15fb7311405941b306 (patch)
treec1cd15e2e3745e95de9bb6714d84ef1f4000e39d /lib
parent7f4f86a2167abc116275e49c81350fc3225485e5 (diff)
downloadclang-3b6afbb99a1c44b4076f8e15fb7311405941b306.tar.gz
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81300 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp3
-rw-r--r--lib/AST/ExprCXX.cpp71
-rw-r--r--lib/AST/NestedNameSpecifier.cpp2
-rw-r--r--lib/AST/StmtPrinter.cpp13
-rw-r--r--lib/AST/TemplateName.cpp2
-rw-r--r--lib/Parse/ParseExpr.cpp6
-rw-r--r--lib/Parse/ParseExprCXX.cpp2
-rw-r--r--lib/Sema/SemaExpr.cpp36
-rw-r--r--lib/Sema/SemaTemplate.cpp7
-rw-r--r--lib/Sema/TreeTransform.h152
10 files changed, 227 insertions, 67 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 780b1fdc42..30e4234956 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -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);
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 86c522795e..7c36caad58 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -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);
}
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 24fb752420..2ed8eb0099 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -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);
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 317486cd71..7a0d6d6349 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -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) {
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index 3913121b09..92c741b35d 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -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?
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index da923c489d..39496626fe 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -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.
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 4cd952e393..a248a5dbee 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -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.
//
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 17708346ab..2644c1d6f7 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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));
}
}
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index bc2c304ecc..dc455185fe 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -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));
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 02b402b77a..d19653d157 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -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>