aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-05-22 21:13:27 +0000
committerDouglas Gregor <dgregor@apple.com>2009-05-22 21:13:27 +0000
commit1c0ca59416999129d0439c2661d137ef38e86209 (patch)
tree4acb129e8ae4af4969342d5ae3ea8224c8522c3b
parent55d1b6a7f7b1bece532c57cc05eb8b44812ce842 (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72281 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ExprCXX.h70
-rw-r--r--include/clang/AST/StmtNodes.def1
-rw-r--r--lib/AST/ExprCXX.cpp8
-rw-r--r--lib/AST/StmtPrinter.cpp6
-rw-r--r--lib/Sema/SemaExpr.cpp18
-rw-r--r--lib/Sema/SemaTemplateInstantiateExpr.cpp41
-rw-r--r--test/SemaTemplate/instantiate-expr-4.cpp60
7 files changed, 195 insertions, 9 deletions
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index d02c6042f2..b7fb7d8029 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -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
diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def
index 98e65d5cf9..060a586ee9 100644
--- a/include/clang/AST/StmtNodes.def
+++ b/include/clang/AST/StmtNodes.def
@@ -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)
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index cca391e193..c3195b17c7 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -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
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 30de402edd..80aa2d1d8f 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -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");
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 0d2a2b8a0a..c9acb48e85 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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));
}
}
diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp
index fd88b934fb..6ef748cff2 100644
--- a/lib/Sema/SemaTemplateInstantiateExpr.cpp
+++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp
@@ -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);
@@ -289,6 +290,26 @@ Sema::OwningExprResult TemplateExprInstantiator::VisitCallExpr(CallExpr *E) {
}
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
= SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
@@ -1159,6 +1180,24 @@ TemplateExprInstantiator::VisitCXXUnresolvedConstructExpr(
}
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)
return Owned((Expr *)0);
diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp
index 09d574176a..0f2bb93f41 100644
--- a/test/SemaTemplate/instantiate-expr-4.cpp
+++ b/test/SemaTemplate/instantiate-expr-4.cpp
@@ -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>;