diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-09-01 00:37:14 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-09-01 00:37:14 +0000 |
commit | c4bf26fbdff42967d660f505a83f75a4df2cc752 (patch) | |
tree | d4d7ad9bdaef74905f2e3a439ea541c6ae92c9f9 | |
parent | fe9dcb345fa8347cea55142c0295b797fddeb30f (diff) |
Preliminary AST representation and semantic analysis for
explicitly-specified template argument lists in member reference
expressions, e.g.,
x->f<int>()
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80646 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Expr.h | 121 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 35 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 6 | ||||
-rw-r--r-- | lib/Frontend/PCHWriterStmt.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 20 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 32 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 35 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 2 | ||||
-rw-r--r-- | test/SemaTemplate/member-function-template.cpp | 2 |
11 files changed, 242 insertions, 35 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 1835edc1d0..793eb1edc6 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -1042,6 +1042,31 @@ struct NameQualifier { /// \brief The source range covered by the nested name specifier. SourceRange Range; }; + +/// \brief Represents an explicit template argument list in C++, e.g., +/// the "<int>" in "sort<int>". +struct ExplicitTemplateArgumentList { + /// \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. + /// The actual template arguments (if any) are stored after the + /// ExplicitTemplateArgumentList structure. + unsigned NumTemplateArgs; + + /// \brief Retrieve the template arguments + TemplateArgument *getTemplateArgs() { + return reinterpret_cast<TemplateArgument *> (this + 1); + } + + /// \brief Retrieve the template arguments + const TemplateArgument *getTemplateArgs() const { + return reinterpret_cast<const TemplateArgument *> (this + 1); + } +}; /// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. /// @@ -1061,9 +1086,17 @@ class MemberExpr : public Expr { bool IsArrow : 1; /// \brief True if this member expression used a nested-name-specifier to - /// refer to the member, e.g., "x->Base::f". + /// refer to the member, e.g., "x->Base::f". When true, a NameQualifier + /// structure is allocated immediately after the MemberExpr. bool HasQualifier : 1; + /// \brief True if this member expression specified a template argument list + /// explicitly, e.g., x->f<int>. When true, an ExplicitTemplateArgumentList + /// structure (and its TemplateArguments) are allocated immediately after + /// the MemberExpr or, if the member expression also has a qualifier, after + /// the NameQualifier structure. + bool HasExplicitTemplateArgumentList : 1; + /// \brief Retrieve the qualifier that preceded the member name, if any. NameQualifier *getMemberQualifier() { if (!HasQualifier) @@ -1074,15 +1107,33 @@ class MemberExpr : public Expr { /// \brief Retrieve the qualifier that preceded the member name, if any. const NameQualifier *getMemberQualifier() const { - if (!HasQualifier) + return const_cast<MemberExpr *>(this)->getMemberQualifier(); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() { + if (!HasExplicitTemplateArgumentList) return 0; - return reinterpret_cast<const NameQualifier *> (this + 1); + if (!HasQualifier) + return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1); + + return reinterpret_cast<ExplicitTemplateArgumentList *>( + getMemberQualifier() + 1); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + const ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() const { + return const_cast<MemberExpr *>(this)->getExplicitTemplateArgumentList(); } MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l, - QualType ty); + bool has_explicit, SourceLocation langle, + const TemplateArgument *targs, unsigned numtargs, + SourceLocation rangle, QualType ty); public: MemberExpr(Expr *base, bool isarrow, NamedDecl *memberdecl, SourceLocation l, @@ -1090,7 +1141,7 @@ public: : Expr(MemberExprClass, ty, base->isTypeDependent(), base->isValueDependent()), Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow), - HasQualifier(false) {} + HasQualifier(false), HasExplicitTemplateArgumentList(false) {} /// \brief Build an empty member reference expression. explicit MemberExpr(EmptyShell Empty) : Expr(MemberExprClass, Empty) { } @@ -1098,7 +1149,13 @@ public: static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, NamedDecl *memberdecl, - SourceLocation l, QualType ty); + SourceLocation l, + bool has_explicit, + SourceLocation langle, + const TemplateArgument *targs, + unsigned numtargs, + SourceLocation rangle, + QualType ty); void setBase(Expr *E) { Base = E; } Expr *getBase() const { return cast<Expr>(Base); } @@ -1110,7 +1167,7 @@ public: NamedDecl *getMemberDecl() const { return MemberDecl; } void setMemberDecl(NamedDecl *D) { MemberDecl = D; } - /// \brief Determines whether this adorned member expression actually had + /// \brief Determines whether this member expression actually had /// a C++ nested-name-specifier prior to the name of the member, e.g., /// x->Base::foo. bool hasQualifier() const { return HasQualifier; } @@ -1134,6 +1191,48 @@ public: return getMemberQualifier()->NNS; } + + /// \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; + } bool isArrow() const { return IsArrow; } void setArrow(bool A) { IsArrow = A; } @@ -1146,10 +1245,14 @@ public: virtual SourceRange getSourceRange() const { // If we have an implicit base (like a C++ implicit this), // make sure not to return its location + SourceLocation EndLoc = MemberLoc; + if (HasExplicitTemplateArgumentList) + EndLoc = getRAngleLoc(); + SourceLocation BaseLoc = getBase()->getLocStart(); if (BaseLoc.isInvalid()) - return SourceRange(MemberLoc, MemberLoc); - return SourceRange(BaseLoc, MemberLoc); + return SourceRange(MemberLoc, EndLoc); + return SourceRange(BaseLoc, EndLoc); } virtual SourceLocation getExprLoc() const { return MemberLoc; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 5b583a5200..a69448e7bc 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -264,31 +264,58 @@ QualType CallExpr::getCallReturnType() const { MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, NamedDecl *memberdecl, - SourceLocation l, QualType ty) + SourceLocation l, bool has_explicit, + SourceLocation langle, + const TemplateArgument *targs, unsigned numtargs, + SourceLocation rangle, QualType ty) : Expr(MemberExprClass, ty, base->isTypeDependent() || (qual && qual->isDependent()), base->isValueDependent() || (qual && qual->isDependent())), Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow), - HasQualifier(qual != 0) { + HasQualifier(qual != 0), HasExplicitTemplateArgumentList(has_explicit) { // Initialize the qualifier, if any. if (HasQualifier) { NameQualifier *NQ = getMemberQualifier(); NQ->NNS = qual; NQ->Range = qualrange; } + + // Initialize the explicit template argument list, if any. + if (HasExplicitTemplateArgumentList) { + ExplicitTemplateArgumentList *ETemplateArgs + = getExplicitTemplateArgumentList(); + ETemplateArgs->LAngleLoc = langle; + ETemplateArgs->RAngleLoc = rangle; + ETemplateArgs->NumTemplateArgs = numtargs; + + TemplateArgument *TemplateArgs = ETemplateArgs->getTemplateArgs(); + for (unsigned I = 0; I < numtargs; ++I) + new (TemplateArgs + I) TemplateArgument(targs[I]); + } } MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, NamedDecl *memberdecl, - SourceLocation l, QualType ty) { + SourceLocation l, + bool has_explicit, + SourceLocation langle, + const TemplateArgument *targs, + unsigned numtargs, + SourceLocation rangle, + QualType ty) { std::size_t Size = sizeof(MemberExpr); if (qual != 0) Size += sizeof(NameQualifier); + if (has_explicit) + Size += sizeof(ExplicitTemplateArgumentList) + + sizeof(TemplateArgument) * numtargs; + void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>()); - return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l, + return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l, + has_explicit, langle, targs, numtargs, rangle, ty); } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 4be4a8ac4f..f10a5e0473 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -743,6 +743,12 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { Qualifier->print(OS, Policy); OS << Node->getMemberDecl()->getNameAsString(); + + if (Node->hasExplicitTemplateArgumentList()) + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); } void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) { PrintExpr(Node->getBase()); diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index dfdecccb68..1f81529135 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -416,6 +416,7 @@ void PCHStmtWriter::VisitMemberExpr(MemberExpr *E) { Writer.AddSourceLocation(E->getMemberLoc(), Record); Record.push_back(E->isArrow()); // FIXME: C++ nested-name-specifier + // FIXME: C++ template argument list Code = pch::EXPR_MEMBER; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index a8cdb67bb3..63d2831fab 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1602,12 +1602,32 @@ public: SourceLocation LLoc, ExprArg Idx, SourceLocation RLoc); + + OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation MemberLoc, + DeclarationName MemberName, + DeclPtrTy ImplDecl, + const CXXScopeSpec *SS = 0) { + // FIXME: Temporary helper while we migrate existing calls to + // BuildMemberReferenceExpr to support explicitly-specified template + // arguments. + return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc, + MemberName, false, SourceLocation(), 0, 0, + SourceLocation(), ImplDecl, SS); + } OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, SourceLocation MemberLoc, DeclarationName MemberName, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + SourceLocation RAngleLoc, DeclPtrTy ImplDecl, const CXXScopeSpec *SS = 0); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index df94f20af7..d272be9765 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -885,7 +885,10 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, if (SS && SS->isSet()) return MemberExpr::Create(C, Base, isArrow, (NestedNameSpecifier *)SS->getScopeRep(), - SS->getRange(), Member, Loc, Ty); + SS->getRange(), Member, Loc, + // FIXME: Explicit template argument lists + false, SourceLocation(), 0, 0, SourceLocation(), + Ty); return new (C) MemberExpr(Base, isArrow, Member, Loc, Ty); } @@ -1980,6 +1983,11 @@ Action::OwningExprResult Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, SourceLocation MemberLoc, DeclarationName MemberName, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + SourceLocation RAngleLoc, DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) { if (SS && SS->isInvalid()) return ExprError(); @@ -2153,14 +2161,34 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); + + if (HasExplicitTemplateArgs) + return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow, + (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), + SS? SS->getRange() : SourceRange(), + FunTmpl, MemberLoc, true, + LAngleLoc, ExplicitTemplateArgs, + NumExplicitTemplateArgs, RAngleLoc, + Context.OverloadTy)); + return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, FunTmpl, MemberLoc, Context.OverloadTy)); } if (OverloadedFunctionDecl *Ovl - = dyn_cast<OverloadedFunctionDecl>(MemberDecl)) + = dyn_cast<OverloadedFunctionDecl>(MemberDecl)) { + if (HasExplicitTemplateArgs) + return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow, + (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), + SS? SS->getRange() : SourceRange(), + Ovl, MemberLoc, true, + LAngleLoc, ExplicitTemplateArgs, + NumExplicitTemplateArgs, RAngleLoc, + Context.OverloadTy)); + return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, Ovl, MemberLoc, Context.OverloadTy)); + } if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index dc58ecc16c..35938260c6 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1831,21 +1831,6 @@ Sema::ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base, ConvName, DeclPtrTy(), SS); } -Sema::OwningExprResult -Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - const CXXScopeSpec &SS, - TemplateTy Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, - SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc) { - // FIXME: Implement! - return ExprError(); -} - Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { Expr *FullExpr = Arg.takeAs<Expr>(); if (FullExpr) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index f22c1177e6..1427d48bc2 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4563,9 +4563,11 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); else - AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func), - /*FIXME:*/false, /*FIXME:*/0, - /*FIXME:*/0, ObjectArg, Args, NumArgs, + AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func), + MemExpr->hasExplicitTemplateArgumentList(), + MemExpr->getTemplateArgs(), + MemExpr->getNumTemplateArgs(), + ObjectArg, Args, NumArgs, CandidateSet, /*SuppressUsedConversions=*/false); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index fb25e99bc8..3985c1c0e0 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1084,6 +1084,41 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD, RAngleLoc); } +Sema::OwningExprResult +Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + TemplateTy TemplateD, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc) { + TemplateName Template = TemplateD.getAsVal<TemplateName>(); + + // FIXME: We're going to end up looking up the template based on its name, + // twice! + DeclarationName Name; + if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl()) + Name = ActualTemplate->getDeclName(); + else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl()) + Name = Ovl->getDeclName(); + else + assert(false && "Cannot support dependent template names yet"); + + // Translate the parser's template argument list in our AST format. + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + TemplateArgsIn.release(); + + // Do we have the save the actual template name? We might need it... + return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, TemplateNameLoc, + Name, true, LAngleLoc, + TemplateArgs.data(), TemplateArgs.size(), + RAngleLoc, DeclPtrTy(), &SS); +} + /// \brief Form a dependent template name. /// /// This action forms a dependent template name given the template diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 3879b39e6e..386a2c6d80 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -2964,7 +2964,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), E->getQualifierRange()); - if (Qualifier == 0); + if (Qualifier == 0) return SemaRef.ExprError(); } diff --git a/test/SemaTemplate/member-function-template.cpp b/test/SemaTemplate/member-function-template.cpp index 087f3952ab..8eb40c83c3 100644 --- a/test/SemaTemplate/member-function-template.cpp +++ b/test/SemaTemplate/member-function-template.cpp @@ -43,7 +43,7 @@ void test_X_f1_address() { void test_X_f0_explicit(X x, int i, long l) { int &ir1 = x.f0<int>(i); int &ir2 = x.f0<>(i); - int &ir3 = x.f0<long>(i); + long &il1 = x.f0<long>(i); } // PR4608 |