From 308047d3a5dc226ab49758253e4a2e4a69c6e43d Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 9 Sep 2009 00:23:06 +0000 Subject: Initial stab at implement dependent member references to member templates, e.g., x.template get 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 --- clang/lib/Sema/SemaExpr.cpp | 36 ++++++---- clang/lib/Sema/SemaTemplate.cpp | 7 +- clang/lib/Sema/TreeTransform.h | 152 +++++++++++++++++++++++++++++----------- 3 files changed, 135 insertions(+), 60 deletions(-) (limited to 'clang/lib/Sema') diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 17708346ab8..2644c1d6f75 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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()) 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/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index bc2c304ecc0..dc455185fec 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/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 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 case. - assert(!ObjectType && - "Cannot handle dependent template names without a nested-name-specifier"); - NestedNameSpecifier *Qualifier = static_cast(SS.getScopeRep()); return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name)); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 02b402b77a2..d19653d157c 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/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::TransformDeclarationName(DeclarationName Name, template TemplateName -TreeTransform::TransformTemplateName(TemplateName Name) { +TreeTransform::TransformTemplateName(TemplateName Name, + QualType ObjectType) { if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(QTN->getQualifier(), @@ -1789,14 +1834,14 @@ TreeTransform::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::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( getDerived().TransformDecl(E->getFirstQualifierFoundInScope())); @@ -4214,21 +4262,60 @@ TreeTransform::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+ + TemplateName OrigTemplateName + = SemaRef.Context.getDependentTemplateName(0, Name.getAsIdentifierInfo()); + + TemplateName Template + = getDerived().TransformTemplateName(OrigTemplateName, + QualType::getFromOpaquePtr(ObjectType)); + if (Template.isNull()) + return SemaRef.ExprError(); + + llvm::SmallVector 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 @@ -4643,33 +4730,18 @@ TreeTransform::RebuildTemplateName(NestedNameSpecifier *Qualifier, template TemplateName TreeTransform::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(); + SS.setScopeRep(Qualifier); + return getSema().ActOnDependentTemplateName( + /*FIXME:*/getDerived().getBaseLocation(), + II, + /*FIXME:*/getDerived().getBaseLocation(), + SS, + ObjectType.getAsOpaquePtr()) + .template getAsVal(); } template -- cgit v1.2.3