diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-12-20 23:49:58 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-12-20 23:49:58 +0000 |
commit | 86f194083504938df72135b5b66bf0c5cafd9498 (patch) | |
tree | 49bf351536460b89340a2e8b6251c3747a98d1de /lib/AST/Expr.cpp | |
parent | 4306d3cb9116605728252e2738df24b9f6ab53c3 (diff) |
Add support for member references (E1.E2, E1->E2) with C++ semantics,
which can refer to static data members, enumerators, and member
functions as well as to non-static data members.
Implement correct lvalue computation for member references in C++.
Compute the result type of non-static data members of reference type properly.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61294 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/Expr.cpp')
-rw-r--r-- | lib/AST/Expr.cpp | 69 |
1 files changed, 53 insertions, 16 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 8aaea7ac9f..adad2a472a 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -407,8 +407,43 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { return LV_Valid; break; } - case MemberExprClass: { // C99 6.5.2.3p4 + case MemberExprClass: { const MemberExpr *m = cast<MemberExpr>(this); + if (Ctx.getLangOptions().CPlusPlus) { // C++ [expr.ref]p4: + NamedDecl *Member = m->getMemberDecl(); + // C++ [expr.ref]p4: + // If E2 is declared to have type "reference to T", then E1.E2 + // is an lvalue. + if (ValueDecl *Value = dyn_cast<ValueDecl>(Member)) + if (Value->getType()->isReferenceType()) + return LV_Valid; + + // -- If E2 is a static data member [...] then E1.E2 is an lvalue. + if (isa<CXXClassVarDecl>(Member)) + return LV_Valid; + + // -- If E2 is a non-static data member [...]. If E1 is an + // lvalue, then E1.E2 is an lvalue. + if (isa<FieldDecl>(Member)) + return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx); + + // -- If it refers to a static member function [...], then + // E1.E2 is an lvalue. + // -- Otherwise, if E1.E2 refers to a non-static member + // function [...], then E1.E2 is not an lvalue. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) + return Method->isStatic()? LV_Valid : LV_MemberFunction; + + // -- If E2 is a member enumerator [...], the expression E1.E2 + // is not an lvalue. + if (isa<EnumConstantDecl>(Member)) + return LV_InvalidExpression; + + // Not an lvalue. + return LV_InvalidExpression; + } + + // C99 6.5.2.3p4 return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx); } case UnaryOperatorClass: @@ -542,6 +577,7 @@ Expr::isModifiableLvalueResult Expr::isModifiableLvalue(ASTContext &Ctx) const { if (CE->getSubExpr()->isLvalue(Ctx) == LV_Valid) return MLV_LValueCast; return MLV_InvalidExpression; + case LV_MemberFunction: return MLV_MemberFunction; } QualType CT = Ctx.getCanonicalType(getType()); @@ -1113,7 +1149,8 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx) const bool Expr::isBitField() { Expr *E = this->IgnoreParenCasts(); if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E)) - return MemRef->getMemberDecl()->isBitField(); + if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl())) + return Field->isBitField(); return false; } @@ -1245,21 +1282,21 @@ static int64_t evaluateOffsetOf(ASTContext& C, const Expr *E) { RecordDecl *RD = Ty->getAsRecordType()->getDecl(); const ASTRecordLayout &RL = C.getASTRecordLayout(RD); - FieldDecl *FD = ME->getMemberDecl(); - - // FIXME: This is linear time. And the fact that we're indexing - // into the layout by position in the record means that we're - // either stuck numbering the fields in the AST or we have to keep - // the linear search (yuck and yuck). - unsigned i = 0; - for (RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); - Field != FieldEnd; (void)++Field, ++i) { - if (*Field == FD) - break; + if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) { + // FIXME: This is linear time. And the fact that we're indexing + // into the layout by position in the record means that we're + // either stuck numbering the fields in the AST or we have to keep + // the linear search (yuck and yuck). + unsigned i = 0; + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; (void)++Field, ++i) { + if (*Field == FD) + break; + } + + return RL.getFieldOffset(i) + evaluateOffsetOf(C, ME->getBase()); } - - return RL.getFieldOffset(i) + evaluateOffsetOf(C, ME->getBase()); } else if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) { const Expr *Base = ASE->getBase(); |