[cfe-commits] r61294 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/Basic/DiagnosticKinds.def lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/AST/StmtPrinter.cpp lib/AST/StmtSerialization.cpp lib/Analysis/GRExprEngine.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprConstant.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/member-expr.cpp
Douglas Gregor
dgregor at apple.com
Sat Dec 20 15:49:59 PST 2008
Author: dgregor
Date: Sat Dec 20 17:49:58 2008
New Revision: 61294
URL: http://llvm.org/viewvc/llvm-project?rev=61294&view=rev
Log:
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.
Added:
cfe/trunk/test/SemaCXX/member-expr.cpp
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/lib/AST/StmtPrinter.cpp
cfe/trunk/lib/AST/StmtSerialization.cpp
cfe/trunk/lib/Analysis/GRExprEngine.cpp
cfe/trunk/lib/CodeGen/CGExpr.cpp
cfe/trunk/lib/CodeGen/CGExprConstant.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=61294&r1=61293&r2=61294&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Sat Dec 20 17:49:58 2008
@@ -126,7 +126,8 @@
LV_NotObjectType,
LV_IncompleteVoidType,
LV_DuplicateVectorComponents,
- LV_InvalidExpression
+ LV_InvalidExpression,
+ LV_MemberFunction
};
isLvalueResult isLvalue(ASTContext &Ctx) const;
@@ -147,7 +148,8 @@
MLV_ArrayType,
MLV_NotBlockQualified,
MLV_ReadonlyProperty,
- MLV_NoSetterProperty
+ MLV_NoSetterProperty,
+ MLV_MemberFunction
};
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx) const;
@@ -830,17 +832,17 @@
///
class MemberExpr : public Expr {
Stmt *Base;
- FieldDecl *MemberDecl;
+ NamedDecl *MemberDecl;
SourceLocation MemberLoc;
bool IsArrow; // True if this is "X->F", false if this is "X.F".
public:
- MemberExpr(Expr *base, bool isarrow, FieldDecl *memberdecl, SourceLocation l,
+ MemberExpr(Expr *base, bool isarrow, NamedDecl *memberdecl, SourceLocation l,
QualType ty)
: Expr(MemberExprClass, ty),
Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow) {}
Expr *getBase() const { return cast<Expr>(Base); }
- FieldDecl *getMemberDecl() const { return MemberDecl; }
+ NamedDecl *getMemberDecl() const { return MemberDecl; }
bool isArrow() const { return IsArrow; }
virtual SourceRange getSourceRange() const {
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=61294&r1=61293&r2=61294&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Sat Dec 20 17:49:58 2008
@@ -1171,6 +1171,10 @@
"%0 does not have a member named %1")
DIAG(err_typecheck_member_reference_arrow, ERROR,
"member reference type %0 is not a pointer")
+DIAG(err_typecheck_member_reference_type, ERROR,
+ "cannot refer to type member %0 with '%select{.|->}1'")
+DIAG(err_typecheck_member_reference_unknown, ERROR,
+ "cannot refer to member %0 with '%select{.|->}1'")
DIAG(err_typecheck_incomplete_tag, ERROR,
"incomplete definition of type %0")
DIAG(err_typecheck_no_member, ERROR,
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=61294&r1=61293&r2=61294&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Sat Dec 20 17:49:58 2008
@@ -407,8 +407,43 @@
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 @@
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::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 @@
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();
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=61294&r1=61293&r2=61294&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sat Dec 20 17:49:58 2008
@@ -153,7 +153,10 @@
RecordDecl *RD = Ty->getAsRecordType()->getDecl();
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
- FieldDecl *FD = E->getMemberDecl();
+
+ FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+ if (!FD) // FIXME: deal with other kinds of member expressions
+ return APValue();
// FIXME: This is linear time.
unsigned i = 0;
Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=61294&r1=61293&r2=61294&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Sat Dec 20 17:49:58 2008
@@ -702,10 +702,7 @@
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
-
- FieldDecl *Field = Node->getMemberDecl();
- assert(Field && "MemberExpr should alway reference a field!");
- OS << Field->getNameAsString();
+ OS << Node->getMemberDecl()->getNameAsString();
}
void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
PrintExpr(Node->getBase());
Modified: cfe/trunk/lib/AST/StmtSerialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtSerialization.cpp?rev=61294&r1=61293&r2=61294&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtSerialization.cpp (original)
+++ cfe/trunk/lib/AST/StmtSerialization.cpp Sat Dec 20 17:49:58 2008
@@ -761,7 +761,7 @@
MemberExpr* MemberExpr::CreateImpl(Deserializer& D, ASTContext& C) {
SourceLocation L = SourceLocation::ReadVal(D);
- FieldDecl* MemberDecl = cast<FieldDecl>(D.ReadPtr<Decl>());
+ NamedDecl* MemberDecl = cast<NamedDecl>(D.ReadPtr<Decl>());
bool IsArrow = D.ReadBool();
QualType T = QualType::ReadVal(D);
Expr* base = D.ReadOwnedPtr<Expr>(C);
Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=61294&r1=61293&r2=61294&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Sat Dec 20 17:49:58 2008
@@ -930,12 +930,16 @@
else
VisitLValue(Base, Pred, Tmp); // x.f = ... or ... = x.f
+ FieldDecl *Field = dyn_cast<FieldDecl>(M->getMemberDecl());
+ if (!Field) // FIXME: skipping member expressions for non-fields
+ return;
+
for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
const GRState* St = GetState(*I);
// FIXME: Should we insert some assumption logic in here to determine
// if "Base" is a valid piece of memory? Before we put this assumption
- // later when using FieldOffset lvals (which we no longer have).
- SVal L = StateMgr.GetLValue(St, GetSVal(St, Base), M->getMemberDecl());
+ // later when using FieldOffset lvals (which we no longer have).
+ SVal L = StateMgr.GetLValue(St, GetSVal(St, Base), Field);
if (asLValue)
MakeNode(Dst, M, *I, BindExpr(St, M, L));
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=61294&r1=61293&r2=61294&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Sat Dec 20 17:49:58 2008
@@ -782,7 +782,9 @@
CVRQualifiers = BaseExpr->getType().getCVRQualifiers();
}
- FieldDecl *Field = E->getMemberDecl();
+ FieldDecl *Field = dyn_cast<FieldDecl>(E->getMemberDecl());
+ // FIXME: Handle non-field member expressions
+ assert(Field && "No code generation for non-field member references");
LValue MemExpLV = EmitLValueForField(BaseValue, Field, isUnion, CVRQualifiers);
LValue::SetObjCIvar(MemExpLV, isIvar);
return MemExpLV;
Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=61294&r1=61293&r2=61294&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Sat Dec 20 17:49:58 2008
@@ -564,7 +564,10 @@
else
Base = EmitLValue(ME->getBase());
- unsigned FieldNumber = CGM.getTypes().getLLVMFieldNo(ME->getMemberDecl());
+ FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ // FIXME: Handle other kinds of member expressions.
+ assert(Field && "No code generation for non-field member expressions");
+ unsigned FieldNumber = CGM.getTypes().getLLVMFieldNo(Field);
llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
llvm::Constant *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty,
FieldNumber);
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=61294&r1=61293&r2=61294&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sat Dec 20 17:49:58 2008
@@ -1244,24 +1244,44 @@
<< &Member << BaseExpr->getSourceRange();
}
- FieldDecl *MemberDecl = dyn_cast<FieldDecl>(*Lookup.first);
- if (!MemberDecl) {
- unsigned DiagID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error,
- "Clang only supports references to members");
- return Diag(MemberLoc, DiagID);
- }
-
- // Figure out the type of the member; see C99 6.5.2.3p3
- // FIXME: Handle address space modifiers
- QualType MemberType = MemberDecl->getType();
- unsigned combinedQualifiers =
- MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers();
- if (MemberDecl->isMutable())
- combinedQualifiers &= ~QualType::Const;
- MemberType = MemberType.getQualifiedType(combinedQualifiers);
+ if (FieldDecl *MemberDecl = dyn_cast<FieldDecl>(*Lookup.first)) {
+ // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
+ // FIXME: Handle address space modifiers
+ QualType MemberType = MemberDecl->getType();
+ if (const ReferenceType *Ref = MemberType->getAsReferenceType())
+ MemberType = Ref->getPointeeType();
+ else {
+ unsigned combinedQualifiers =
+ MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers();
+ if (MemberDecl->isMutable())
+ combinedQualifiers &= ~QualType::Const;
+ MemberType = MemberType.getQualifiedType(combinedQualifiers);
+ }
- return new MemberExpr(BaseExpr, OpKind == tok::arrow, MemberDecl,
- MemberLoc, MemberType);
+ return new MemberExpr(BaseExpr, OpKind == tok::arrow, MemberDecl,
+ MemberLoc, MemberType);
+ } else if (CXXClassVarDecl *Var = dyn_cast<CXXClassVarDecl>(*Lookup.first))
+ return new MemberExpr(BaseExpr, OpKind == tok::arrow, Var, MemberLoc,
+ Var->getType().getNonReferenceType());
+ else if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(*Lookup.first))
+ return new MemberExpr(BaseExpr, OpKind == tok::arrow, MemberFn, MemberLoc,
+ MemberFn->getType());
+ else if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(*Lookup.first))
+ return new MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl, MemberLoc,
+ Context.OverloadTy);
+ else if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(*Lookup.first))
+ return new MemberExpr(BaseExpr, OpKind == tok::arrow, Enum, MemberLoc,
+ Enum->getType());
+ else if (isa<TypeDecl>(*Lookup.first))
+ return Diag(MemberLoc, diag::err_typecheck_member_reference_type)
+ << DeclarationName(&Member) << int(OpKind == tok::arrow);
+
+ // We found a declaration kind that we didn't expect. This is a
+ // generic error message that tells the user that she can't refer
+ // to this member with '.' or '->'.
+ return Diag(MemberLoc, diag::err_typecheck_member_reference_unknown)
+ << DeclarationName(&Member) << int(OpKind == tok::arrow);
}
// Handle access to Objective-C instance variables, such as "Obj->ivar" and
@@ -2920,10 +2940,12 @@
return QualType();
}
} else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(op)) { // C99 6.5.3.2p1
- if (MemExpr->getMemberDecl()->isBitField()) {
- Diag(OpLoc, diag::err_typecheck_address_of)
- << "bit-field" << op->getSourceRange();
- return QualType();
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(MemExpr->getMemberDecl())) {
+ if (Field->isBitField()) {
+ Diag(OpLoc, diag::err_typecheck_address_of)
+ << "bit-field" << op->getSourceRange();
+ return QualType();
+ }
}
// Check for Apple extension for accessing vector components.
} else if (isa<ArraySubscriptExpr>(op) &&
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=61294&r1=61293&r2=61294&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sat Dec 20 17:49:58 2008
@@ -666,26 +666,27 @@
// other value of that type for promotion purposes (C++ 4.5p3).
if (MemberExpr *MemRef = dyn_cast<MemberExpr>(From)) {
using llvm::APSInt;
- FieldDecl *MemberDecl = MemRef->getMemberDecl();
- APSInt BitWidth;
- if (MemberDecl->isBitField() &&
- FromType->isIntegralType() && !FromType->isEnumeralType() &&
- From->isIntegerConstantExpr(BitWidth, Context)) {
- APSInt ToSize(Context.getTypeSize(ToType));
-
- // Are we promoting to an int from a bitfield that fits in an int?
- if (BitWidth < ToSize ||
- (FromType->isSignedIntegerType() && BitWidth <= ToSize)) {
- return To->getKind() == BuiltinType::Int;
- }
-
- // Are we promoting to an unsigned int from an unsigned bitfield
- // that fits into an unsigned int?
- if (FromType->isUnsignedIntegerType() && BitWidth <= ToSize) {
- return To->getKind() == BuiltinType::UInt;
+ if (FieldDecl *MemberDecl = dyn_cast<FieldDecl>(MemRef->getMemberDecl())) {
+ APSInt BitWidth;
+ if (MemberDecl->isBitField() &&
+ FromType->isIntegralType() && !FromType->isEnumeralType() &&
+ From->isIntegerConstantExpr(BitWidth, Context)) {
+ APSInt ToSize(Context.getTypeSize(ToType));
+
+ // Are we promoting to an int from a bitfield that fits in an int?
+ if (BitWidth < ToSize ||
+ (FromType->isSignedIntegerType() && BitWidth <= ToSize)) {
+ return To->getKind() == BuiltinType::Int;
+ }
+
+ // Are we promoting to an unsigned int from an unsigned bitfield
+ // that fits into an unsigned int?
+ if (FromType->isUnsignedIntegerType() && BitWidth <= ToSize) {
+ return To->getKind() == BuiltinType::UInt;
+ }
+
+ return false;
}
-
- return false;
}
}
Added: cfe/trunk/test/SemaCXX/member-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-expr.cpp?rev=61294&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/member-expr.cpp (added)
+++ cfe/trunk/test/SemaCXX/member-expr.cpp Sat Dec 20 17:49:58 2008
@@ -0,0 +1,22 @@
+// RUN: clang -fsyntax-only -verify %s
+
+class X{
+public:
+ enum E {Enumerator};
+ int f();
+ static int mem;
+ static float g();
+};
+
+void test(X* xp, X x) {
+ int i1 = x.f();
+ int i2 = xp->f();
+ x.E; // expected-error{{cannot refer to type member 'E' with '.'}}
+ xp->E; // expected-error{{cannot refer to type member 'E' with '->'}}
+ // FIXME: lookup needs to find enumerators int i3 = x.Enumerator;
+ // FIXME: int i4 = xp->Enumerator;
+ x.mem = 1;
+ xp->mem = 2;
+ float f1 = x.g();
+ float f2 = xp->g();
+}
More information about the cfe-commits
mailing list