Initial patch to support definitions of id and Class from headers in Objective-C code.
This currently breaks test/SemaObjC/id-isa-ref.m and issues some spurious warnings when you attempt to assign a struct objc_class* value to a Class variable. The test case probably should fail as it's written, because without the definition of Class the compiler should not assume struct objc_class* is a valid receiver type, but it's left broken because it would be nice if we could get that passing too for the special case of isa.
Approved by snaroff.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79248 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index ef172e5..6b597d1 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -26,6 +26,7 @@
#include "clang/Parse/Scope.h"
using namespace clang;
+
/// \brief Determine whether the use of this declaration is valid, and
/// emit any corresponding diagnostics.
///
@@ -2127,6 +2128,20 @@
DefaultFunctionArrayConversion(BaseExpr);
QualType BaseType = BaseExpr->getType();
+ // If this is an Objective-C pseudo-builtin and a definition is provided then
+ // use that.
+ if (BaseType->isObjCIdType()) {
+ // We have an 'id' type. Rather than fall through, we check if this
+ // is a reference to 'isa'.
+ if (BaseType != Context.ObjCIdRedefinitionType) {
+ BaseType = Context.ObjCIdRedefinitionType;
+ ImpCastExprToType(BaseExpr, BaseType);
+ }
+ } else if (BaseType->isObjCClassType() &&
+ BaseType != Context.ObjCClassRedefinitionType) {
+ BaseType = Context.ObjCClassRedefinitionType;
+ ImpCastExprToType(BaseExpr, BaseType);
+ }
assert(!BaseType.isNull() && "no type for member expression");
// Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
@@ -2402,11 +2417,6 @@
<< IDecl->getDeclName() << &Member
<< BaseExpr->getSourceRange());
}
- // We have an 'id' type. Rather than fall through, we check if this
- // is a reference to 'isa'.
- if (Member.isStr("isa"))
- return Owned(new (Context) ObjCIsaExpr(BaseExpr, true, MemberLoc,
- Context.getObjCIdType()));
}
// Handle properties on 'id' and qualified "id".
if (OpKind == tok::period && (BaseType->isObjCIdType() ||
@@ -3266,6 +3276,30 @@
ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer.
return RHSTy;
}
+ // Handle things like Class and struct objc_class*. Here we case the result
+ // to the pseudo-builtin, because that will be implicitly cast back to the
+ // redefinition type if an attempt is made to access its fields.
+ if (LHSTy->isObjCClassType() &&
+ (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
+ ImpCastExprToType(RHS, LHSTy);
+ return LHSTy;
+ }
+ if (RHSTy->isObjCClassType() &&
+ (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
+ ImpCastExprToType(LHS, RHSTy);
+ return RHSTy;
+ }
+ // And the same for struct objc_object* / id
+ if (LHSTy->isObjCIdType() &&
+ (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
+ ImpCastExprToType(RHS, LHSTy);
+ return LHSTy;
+ }
+ if (RHSTy->isObjCIdType() &&
+ (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
+ ImpCastExprToType(LHS, RHSTy);
+ return RHSTy;
+ }
// Handle block pointer types.
if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) {
if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
@@ -3484,6 +3518,13 @@
Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
QualType lhptee, rhptee;
+ if ((lhsType->isObjCClassType() &&
+ (rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) ||
+ (rhsType->isObjCClassType() &&
+ (lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) {
+ return Compatible;
+ }
+
// get the "pointed to" type (ignoring qualifiers at the top level)
lhptee = lhsType->getAs<PointerType>()->getPointeeType();
rhptee = rhsType->getAs<PointerType>()->getPointeeType();
@@ -3607,6 +3648,13 @@
if (lhsType == rhsType)
return Compatible; // Common case: fast path an exact match.
+ if ((lhsType->isObjCClassType() &&
+ (rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) ||
+ (rhsType->isObjCClassType() &&
+ (lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) {
+ return Compatible;
+ }
+
// If the left-hand side is a reference type, then we are in a
// (rare!) case where we've allowed the use of references in C,
// e.g., as a parameter type in a built-in function. In this case,