Representation of and template instantiation for member

expressions. This change introduces another AST node,
CXXUnresolvedMemberExpr, that captures member references (x->m, x.m)
when the base of the expression (the "x") is type-dependent, and we
therefore cannot resolve the member reference yet.

Note that our parsing of member references for C++ is still quite
poor, e.g., we don't handle x->Base::m or x->operator int.

llvm-svn: 72281
This commit is contained in:
Douglas Gregor 2009-05-22 21:13:27 +00:00
parent c996521508
commit a8db954f24
7 changed files with 195 additions and 9 deletions

View File

@ -1088,6 +1088,76 @@ public:
virtual child_iterator child_end();
};
/// \brief
class CXXUnresolvedMemberExpr : public Expr {
/// \brief The expression for the base pointer or class reference,
/// e.g., the \c x in x.f.
Stmt *Base;
/// \brief Whether this member expression used the '->' operator or
/// the '.' operator.
bool IsArrow;
/// \brief The location of the '->' or '.' operator.
SourceLocation OperatorLoc;
/// \brief The member to which this member expression refers, which
/// can be name, overloaded operator, or destructor.
/// FIXME: could also be a template-id, and we might have a
/// nested-name-specifier as well.
DeclarationName Member;
/// \brief The location of the member name.
SourceLocation MemberLoc;
public:
CXXUnresolvedMemberExpr(ASTContext &C,
Expr *Base, bool IsArrow,
SourceLocation OperatorLoc,
DeclarationName Member,
SourceLocation MemberLoc)
: Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
Base(Base), IsArrow(IsArrow), OperatorLoc(OperatorLoc),
Member(Member), MemberLoc(MemberLoc) { }
/// \brief Retrieve the base object of this member expressions,
/// e.g., the \c x in \c x.m.
Expr *getBase() { return cast<Expr>(Base); }
void setBase(Expr *E) { Base = E; }
/// \brief Determine whether this member expression used the '->'
/// operator; otherwise, it used the '.' operator.
bool isArrow() const { return IsArrow; }
void setArrow(bool A) { IsArrow = A; }
/// \brief Retrieve the location of the '->' or '.' operator.
SourceLocation getOperatorLoc() const { return OperatorLoc; }
void setOperatorLoc(SourceLocation L) { OperatorLoc = L; }
/// \brief Retrieve the name of the member that this expression
/// refers to.
DeclarationName getMember() const { return Member; }
void setMember(DeclarationName N) { Member = N; }
// \brief Retrieve the location of the name of the member that this
// expression refers to.
SourceLocation getMemberLoc() const { return MemberLoc; }
void setMemberLoc(SourceLocation L) { MemberLoc = L; }
virtual SourceRange getSourceRange() const {
return SourceRange(Base->getSourceRange().getBegin(),
MemberLoc);
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXUnresolvedMemberExprClass;
}
static bool classof(const CXXUnresolvedMemberExpr *) { return true; }
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
};
} // end namespace clang
#endif

View File

@ -127,6 +127,7 @@ EXPR(CXXConstructExpr , Expr)
EXPR(CXXExprWithTemporaries , Expr)
EXPR(CXXTemporaryObjectExpr , CXXConstructExpr)
EXPR(CXXUnresolvedConstructExpr, Expr)
EXPR(CXXUnresolvedMemberExpr, Expr)
// Obj-C Expressions.
EXPR(ObjCStringLiteral , Expr)

View File

@ -354,6 +354,14 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() {
return child_iterator(reinterpret_cast<Stmt **>(this + 1) + NumArgs);
}
Stmt::child_iterator CXXUnresolvedMemberExpr::child_begin() {
return child_iterator(&Base);
}
Stmt::child_iterator CXXUnresolvedMemberExpr::child_end() {
return child_iterator(&Base + 1);
}
//===----------------------------------------------------------------------===//
// Cloners
//===----------------------------------------------------------------------===//

View File

@ -1125,6 +1125,12 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr(
OS << ")";
}
void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
OS << Node->getMember().getAsString();
}
static const char *getTypeTraitName(UnaryTypeTrait UTT) {
switch (UTT) {
default: assert(false && "Unknown type trait");

View File

@ -2031,10 +2031,11 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
// must have pointer type, and the accessed type is the pointee.
if (OpKind == tok::arrow) {
if (BaseType->isDependentType())
// FIXME: This should not return a MemberExpr AST node, but a more
// specialized one.
return Owned(new (Context) MemberExpr(BaseExpr, true, 0,
MemberLoc, Context.DependentTy));
return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
BaseExpr, true,
OpLoc,
DeclarationName(&Member),
MemberLoc));
else if (const PointerType *PT = BaseType->getAsPointerType())
BaseType = PT->getPointeeType();
else if (getLangOptions().CPlusPlus && BaseType->isRecordType())
@ -2058,10 +2059,11 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
if (!PT || (getLangOptions().ObjC1 &&
!PT->getPointeeType()->isRecordType()))
// FIXME: This should not return a MemberExpr AST node, but a more
// specialized one.
return Owned(new (Context) MemberExpr(BaseExpr, false, 0,
MemberLoc, Context.DependentTy));
return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
BaseExpr, false,
OpLoc,
DeclarationName(&Member),
MemberLoc));
}
}

View File

@ -48,7 +48,7 @@ namespace {
OwningExprResult VisitUnaryOperator(UnaryOperator *E);
OwningExprResult VisitArraySubscriptExpr(ArraySubscriptExpr *E);
OwningExprResult VisitCallExpr(CallExpr *E);
// FIXME: VisitMemberExpr
OwningExprResult VisitMemberExpr(MemberExpr *E);
OwningExprResult VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
OwningExprResult VisitBinaryOperator(BinaryOperator *E);
OwningExprResult VisitCompoundAssignOperator(CompoundAssignOperator *E);
@ -96,6 +96,7 @@ namespace {
OwningExprResult VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E);
OwningExprResult VisitCXXUnresolvedConstructExpr(
CXXUnresolvedConstructExpr *E);
OwningExprResult VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *E);
OwningExprResult VisitGNUNullExpr(GNUNullExpr *E);
OwningExprResult VisitUnresolvedFunctionNameExpr(
UnresolvedFunctionNameExpr *E);
@ -288,6 +289,26 @@ Sema::OwningExprResult TemplateExprInstantiator::VisitCallExpr(CallExpr *E) {
E->getRParenLoc());
}
Sema::OwningExprResult
TemplateExprInstantiator::VisitMemberExpr(MemberExpr *E) {
// Instantiate the base of the expression.
OwningExprResult Base = Visit(E->getBase());
if (Base.isInvalid())
return SemaRef.ExprError();
// FIXME: Handle declaration names here
SourceLocation FakeOperatorLoc =
SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd());
return SemaRef.ActOnMemberReferenceExpr(/*Scope=*/0,
move(Base),
/*FIXME*/FakeOperatorLoc,
E->isArrow()? tok::arrow
: tok::period,
E->getMemberLoc(),
/*FIXME:*/*E->getMemberDecl()->getIdentifier(),
/*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
}
Sema::OwningExprResult
TemplateExprInstantiator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
SourceLocation FakeTypeLoc
@ -1158,6 +1179,24 @@ TemplateExprInstantiator::VisitCXXUnresolvedConstructExpr(
E->getRParenLoc());
}
Sema::OwningExprResult
TemplateExprInstantiator::VisitCXXUnresolvedMemberExpr(
CXXUnresolvedMemberExpr *E) {
// Instantiate the base of the expression.
OwningExprResult Base = Visit(E->getBase());
if (Base.isInvalid())
return SemaRef.ExprError();
// FIXME: Instantiate the declaration name.
return SemaRef.ActOnMemberReferenceExpr(/*Scope=*/0,
move(Base), E->getOperatorLoc(),
E->isArrow()? tok::arrow
: tok::period,
E->getMemberLoc(),
/*FIXME:*/*E->getMember().getAsIdentifierInfo(),
/*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
}
Sema::OwningExprResult
Sema::InstantiateExpr(Expr *E, const TemplateArgumentList &TemplateArgs) {
if (!E)

View File

@ -178,3 +178,63 @@ struct InitList2 {
template struct InitList2<APair, int*, float*>;
template struct InitList2<APair, int*, double*>; // expected-note{{instantiation}}
// ---------------------------------------------------------------------
// member references
// ---------------------------------------------------------------------
template<typename T, typename Result>
struct DotMemRef0 {
void f(T t) {
Result result = t.m; // expected-error{{cannot be initialized}}
}
};
struct MemInt {
int m;
};
struct InheritsMemInt : MemInt { };
struct MemIntFunc {
static int m(int);
};
template struct DotMemRef0<MemInt, int&>;
template struct DotMemRef0<InheritsMemInt, int&>;
template struct DotMemRef0<MemIntFunc, int (*)(int)>;
template struct DotMemRef0<MemInt, float&>; // expected-note{{instantiation}}
template<typename T, typename Result>
struct ArrowMemRef0 {
void f(T t) {
Result result = t->m; // expected-error 2{{cannot be initialized}}
}
};
template<typename T>
struct ArrowWrapper {
T operator->();
};
template struct ArrowMemRef0<MemInt*, int&>;
template struct ArrowMemRef0<InheritsMemInt*, int&>;
template struct ArrowMemRef0<MemIntFunc*, int (*)(int)>;
template struct ArrowMemRef0<MemInt*, float&>; // expected-note{{instantiation}}
template struct ArrowMemRef0<ArrowWrapper<MemInt*>, int&>;
template struct ArrowMemRef0<ArrowWrapper<InheritsMemInt*>, int&>;
template struct ArrowMemRef0<ArrowWrapper<MemIntFunc*>, int (*)(int)>;
template struct ArrowMemRef0<ArrowWrapper<MemInt*>, float&>; // expected-note{{instantiation}}
template struct ArrowMemRef0<ArrowWrapper<ArrowWrapper<MemInt*> >, int&>;
// FIXME: we should be able to return a MemInt without the reference!
MemInt &createMemInt(int);
template<int N>
struct NonDepMemberExpr0 {
void f() {
createMemInt(N).m = N;
}
};
template struct NonDepMemberExpr0<0>;