]> granicus.if.org Git - clang/commitdiff
Representation of and template instantiation for member
authorDouglas Gregor <dgregor@apple.com>
Fri, 22 May 2009 21:13:27 +0000 (21:13 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 22 May 2009 21:13:27 +0000 (21:13 +0000)
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

include/clang/AST/ExprCXX.h
include/clang/AST/StmtNodes.def
lib/AST/ExprCXX.cpp
lib/AST/StmtPrinter.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaTemplateInstantiateExpr.cpp
test/SemaTemplate/instantiate-expr-4.cpp

index d02c6042f2f68c4182dcc990278cba8d5944d6a1..b7fb7d8029ebf3548917d32ffc3f0d5eb1d49806 100644 (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
index 98e65d5cf9e178ee24be87896f4d4425f194e1ec..060a586ee994d43b3696fbdd0255cff981db1988 100644 (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)
index cca391e1939178b4a8106a074ca2068265a467a9..c3195b17c7fcb03fc3e1baf109c03f0e29851c8b 100644 (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
 //===----------------------------------------------------------------------===//
index 30de402edd6519e7a17299be01e1b1741fcce147..80aa2d1d8fe3b578725408d667306c3597180c1a 100644 (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");
index 0d2a2b8a0a1123f787cefd1fae8bdc16d9f68ddb..c9acb48e859d1642675cf520a39212058cef92f3 100644 (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));
     }
   }
 
index fd88b934fbf30ddc4a877b0d57e6b78a42fe38c7..6ef748cff29ff93f035d0e1a6d7ec1f44cdaf88b 100644 (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)
index 09d574176ac1801bfb6bb6519bcfcaf4fa13a6d0..0f2bb93f413200675a62b0f85dd3661832a654ed 100644 (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>;