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
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 51e4e05..7fafb14 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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);
- }
+ 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);
+ }
- // 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);
+ 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);
- return new MemberExpr(BaseExpr, OpKind == tok::arrow, MemberDecl,
- MemberLoc, MemberType);
+ // 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) &&
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index c719f56..fe4b763 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -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;
+ 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;
}
-
- // 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;
}
}