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; 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. /// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F.
/// ///
class MemberExpr : public Expr { class MemberExpr : public Expr {
@ -1061,9 +1086,17 @@ class MemberExpr : public Expr {
bool IsArrow : 1; bool IsArrow : 1;
/// \brief True if this member expression used a nested-name-specifier to /// \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; 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. /// \brief Retrieve the qualifier that preceded the member name, if any.
NameQualifier *getMemberQualifier() { NameQualifier *getMemberQualifier() {
if (!HasQualifier) if (!HasQualifier)
@ -1074,15 +1107,33 @@ class MemberExpr : public Expr {
/// \brief Retrieve the qualifier that preceded the member name, if any. /// \brief Retrieve the qualifier that preceded the member name, if any.
const NameQualifier *getMemberQualifier() const { 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 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, MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l, SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l,
QualType ty); bool has_explicit, SourceLocation langle,
const TemplateArgument *targs, unsigned numtargs,
SourceLocation rangle, QualType ty);
public: public:
MemberExpr(Expr *base, bool isarrow, NamedDecl *memberdecl, SourceLocation l, MemberExpr(Expr *base, bool isarrow, NamedDecl *memberdecl, SourceLocation l,
@ -1090,7 +1141,7 @@ public:
: Expr(MemberExprClass, ty, : Expr(MemberExprClass, ty,
base->isTypeDependent(), base->isValueDependent()), base->isTypeDependent(), base->isValueDependent()),
Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow), Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
HasQualifier(false) {} HasQualifier(false), HasExplicitTemplateArgumentList(false) {}
/// \brief Build an empty member reference expression. /// \brief Build an empty member reference expression.
explicit MemberExpr(EmptyShell Empty) : Expr(MemberExprClass, Empty) { } explicit MemberExpr(EmptyShell Empty) : Expr(MemberExprClass, Empty) { }
@ -1098,7 +1149,13 @@ public:
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow, static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifier *qual, SourceRange qualrange, NestedNameSpecifier *qual, SourceRange qualrange,
NamedDecl *memberdecl, 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; } void setBase(Expr *E) { Base = E; }
Expr *getBase() const { return cast<Expr>(Base); } Expr *getBase() const { return cast<Expr>(Base); }
@ -1110,7 +1167,7 @@ public:
NamedDecl *getMemberDecl() const { return MemberDecl; } NamedDecl *getMemberDecl() const { return MemberDecl; }
void setMemberDecl(NamedDecl *D) { MemberDecl = D; } 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., /// a C++ nested-name-specifier prior to the name of the member, e.g.,
/// x->Base::foo. /// x->Base::foo.
bool hasQualifier() const { return HasQualifier; } bool hasQualifier() const { return HasQualifier; }
@ -1135,6 +1192,48 @@ public:
return getMemberQualifier()->NNS; 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; } bool isArrow() const { return IsArrow; }
void setArrow(bool A) { IsArrow = A; } void setArrow(bool A) { IsArrow = A; }
@ -1146,10 +1245,14 @@ public:
virtual SourceRange getSourceRange() const { virtual SourceRange getSourceRange() const {
// If we have an implicit base (like a C++ implicit this), // If we have an implicit base (like a C++ implicit this),
// make sure not to return its location // make sure not to return its location
SourceLocation EndLoc = MemberLoc;
if (HasExplicitTemplateArgumentList)
EndLoc = getRAngleLoc();
SourceLocation BaseLoc = getBase()->getLocStart(); SourceLocation BaseLoc = getBase()->getLocStart();
if (BaseLoc.isInvalid()) if (BaseLoc.isInvalid())
return SourceRange(MemberLoc, MemberLoc); return SourceRange(MemberLoc, EndLoc);
return SourceRange(BaseLoc, MemberLoc); return SourceRange(BaseLoc, EndLoc);
} }
virtual SourceLocation getExprLoc() const { return MemberLoc; } virtual SourceLocation getExprLoc() const { return MemberLoc; }

View File

@ -264,31 +264,58 @@ QualType CallExpr::getCallReturnType() const {
MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
SourceRange qualrange, NamedDecl *memberdecl, 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, : Expr(MemberExprClass, ty,
base->isTypeDependent() || (qual && qual->isDependent()), base->isTypeDependent() || (qual && qual->isDependent()),
base->isValueDependent() || (qual && qual->isDependent())), base->isValueDependent() || (qual && qual->isDependent())),
Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow), Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
HasQualifier(qual != 0) { HasQualifier(qual != 0), HasExplicitTemplateArgumentList(has_explicit) {
// Initialize the qualifier, if any. // Initialize the qualifier, if any.
if (HasQualifier) { if (HasQualifier) {
NameQualifier *NQ = getMemberQualifier(); NameQualifier *NQ = getMemberQualifier();
NQ->NNS = qual; NQ->NNS = qual;
NQ->Range = qualrange; 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, MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifier *qual, NestedNameSpecifier *qual,
SourceRange qualrange, SourceRange qualrange,
NamedDecl *memberdecl, 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); std::size_t Size = sizeof(MemberExpr);
if (qual != 0) if (qual != 0)
Size += sizeof(NameQualifier); Size += sizeof(NameQualifier);
if (has_explicit)
Size += sizeof(ExplicitTemplateArgumentList) +
sizeof(TemplateArgument) * numtargs;
void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>()); 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); ty);
} }

View File

@ -743,6 +743,12 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
Qualifier->print(OS, Policy); Qualifier->print(OS, Policy);
OS << Node->getMemberDecl()->getNameAsString(); OS << Node->getMemberDecl()->getNameAsString();
if (Node->hasExplicitTemplateArgumentList())
OS << TemplateSpecializationType::PrintTemplateArgumentList(
Node->getTemplateArgs(),
Node->getNumTemplateArgs(),
Policy);
} }
void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) { void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) {
PrintExpr(Node->getBase()); PrintExpr(Node->getBase());

View File

@ -416,6 +416,7 @@ void PCHStmtWriter::VisitMemberExpr(MemberExpr *E) {
Writer.AddSourceLocation(E->getMemberLoc(), Record); Writer.AddSourceLocation(E->getMemberLoc(), Record);
Record.push_back(E->isArrow()); Record.push_back(E->isArrow());
// FIXME: C++ nested-name-specifier // FIXME: C++ nested-name-specifier
// FIXME: C++ template argument list
Code = pch::EXPR_MEMBER; Code = pch::EXPR_MEMBER;
} }

View File

@ -1609,6 +1609,26 @@ public:
SourceLocation MemberLoc, SourceLocation MemberLoc,
DeclarationName MemberName, DeclarationName MemberName,
DeclPtrTy ImplDecl, 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); const CXXScopeSpec *SS = 0);
virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base, 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()) if (SS && SS->isSet())
return MemberExpr::Create(C, Base, isArrow, return MemberExpr::Create(C, Base, isArrow,
(NestedNameSpecifier *)SS->getScopeRep(), (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); return new (C) MemberExpr(Base, isArrow, Member, Loc, Ty);
} }
@ -1980,6 +1983,11 @@ Action::OwningExprResult
Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
tok::TokenKind OpKind, SourceLocation MemberLoc, tok::TokenKind OpKind, SourceLocation MemberLoc,
DeclarationName MemberName, DeclarationName MemberName,
bool HasExplicitTemplateArgs,
SourceLocation LAngleLoc,
const TemplateArgument *ExplicitTemplateArgs,
unsigned NumExplicitTemplateArgs,
SourceLocation RAngleLoc,
DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) { DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) {
if (SS && SS->isInvalid()) if (SS && SS->isInvalid())
return ExprError(); return ExprError();
@ -2153,14 +2161,34 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
if (FunctionTemplateDecl *FunTmpl if (FunctionTemplateDecl *FunTmpl
= dyn_cast<FunctionTemplateDecl>(MemberDecl)) { = dyn_cast<FunctionTemplateDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, 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, return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
FunTmpl, MemberLoc, FunTmpl, MemberLoc,
Context.OverloadTy)); Context.OverloadTy));
} }
if (OverloadedFunctionDecl *Ovl 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, return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
Ovl, MemberLoc, Context.OverloadTy)); Ovl, MemberLoc, Context.OverloadTy));
}
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) { if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl); MarkDeclarationReferenced(MemberLoc, MemberDecl);
return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,

View File

@ -1831,21 +1831,6 @@ Sema::ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
ConvName, DeclPtrTy(), SS); 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) { Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
Expr *FullExpr = Arg.takeAs<Expr>(); Expr *FullExpr = Arg.takeAs<Expr>();
if (FullExpr) if (FullExpr)

View File

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

View File

@ -1084,6 +1084,41 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD,
RAngleLoc); 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. /// \brief Form a dependent template name.
/// ///
/// This action forms a dependent template name given the template /// This action forms a dependent template name given the template

View File

@ -2964,7 +2964,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
Qualifier Qualifier
= getDerived().TransformNestedNameSpecifier(E->getQualifier(), = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
E->getQualifierRange()); E->getQualifierRange());
if (Qualifier == 0); if (Qualifier == 0)
return SemaRef.ExprError(); 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) { void test_X_f0_explicit(X x, int i, long l) {
int &ir1 = x.f0<int>(i); int &ir1 = x.f0<int>(i);
int &ir2 = x.f0<>(i); int &ir2 = x.f0<>(i);
int &ir3 = x.f0<long>(i); long &il1 = x.f0<long>(i);
} }
// PR4608 // PR4608