Preliminary AST representation and semantic analysis for

explicitly-specified template argument lists in member reference
expressions, e.g.,

  x->f<int>()

llvm-svn: 80646
This commit is contained in:
Douglas Gregor 2009-09-01 00:37:14 +00:00
parent b1b2016b83
commit 84f14dd674
11 changed files with 242 additions and 35 deletions

View File

@ -1043,6 +1043,31 @@ struct NameQualifier {
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.
///
class MemberExpr : public Expr {
@ -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; }
@ -1135,6 +1192,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; }

View File

@ -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,
has_explicit, langle, targs, numtargs, rangle,
ty);
}

View File

@ -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());

View File

@ -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;
}

View File

@ -1609,6 +1609,26 @@ public:
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);
virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,

View File

@ -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,

View File

@ -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)

View File

@ -4564,8 +4564,10 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
/*SuppressUserConversions=*/false);
else
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func),
/*FIXME:*/false, /*FIXME:*/0,
/*FIXME:*/0, ObjectArg, Args, NumArgs,
MemExpr->hasExplicitTemplateArgumentList(),
MemExpr->getTemplateArgs(),
MemExpr->getNumTemplateArgs(),
ObjectArg, Args, NumArgs,
CandidateSet,
/*SuppressUsedConversions=*/false);
}

View File

@ -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

View File

@ -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();
}

View File

@ -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