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:
parent
c996521508
commit
a8db954f24
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>;
|
||||
|
|
Loading…
Reference in New Issue