diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index d02c6042f2f6..b7fb7d8029eb 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/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(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/clang/include/clang/AST/StmtNodes.def b/clang/include/clang/AST/StmtNodes.def index 98e65d5cf9e1..060a586ee994 100644 --- a/clang/include/clang/AST/StmtNodes.def +++ b/clang/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/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index cca391e19391..c3195b17c7fc 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -354,6 +354,14 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() { return child_iterator(reinterpret_cast(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/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 30de402edd65..80aa2d1d8fe3 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 0d2a2b8a0a11..c9acb48e859d 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp b/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp index fd88b934fbf3..6ef748cff29f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/clang/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); @@ -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) diff --git a/clang/test/SemaTemplate/instantiate-expr-4.cpp b/clang/test/SemaTemplate/instantiate-expr-4.cpp index 09d574176ac1..0f2bb93f4132 100644 --- a/clang/test/SemaTemplate/instantiate-expr-4.cpp +++ b/clang/test/SemaTemplate/instantiate-expr-4.cpp @@ -178,3 +178,63 @@ struct InitList2 { template struct InitList2; template struct InitList2; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// member references +// --------------------------------------------------------------------- +template +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; +template struct DotMemRef0; +template struct DotMemRef0; +template struct DotMemRef0; // expected-note{{instantiation}} + +template +struct ArrowMemRef0 { + void f(T t) { + Result result = t->m; // expected-error 2{{cannot be initialized}} + } +}; + +template +struct ArrowWrapper { + T operator->(); +}; + +template struct ArrowMemRef0; +template struct ArrowMemRef0; +template struct ArrowMemRef0; +template struct ArrowMemRef0; // expected-note{{instantiation}} + +template struct ArrowMemRef0, int&>; +template struct ArrowMemRef0, int&>; +template struct ArrowMemRef0, int (*)(int)>; +template struct ArrowMemRef0, float&>; // expected-note{{instantiation}} +template struct ArrowMemRef0 >, int&>; + +// FIXME: we should be able to return a MemInt without the reference! +MemInt &createMemInt(int); + +template +struct NonDepMemberExpr0 { + void f() { + createMemInt(N).m = N; + } +}; + +template struct NonDepMemberExpr0<0>;