This patch includes a conceptually simple, but very intrusive/pervasive change.
The idea is to segregate Objective-C "object" pointers from general C pointers (utilizing the recently added ObjCObjectPointerType). The fun starts in Sema::GetTypeForDeclarator(), where "SomeInterface *" is now represented by a single AST node (rather than a PointerType whose Pointee is an ObjCInterfaceType). Since a significant amount of code assumed ObjC object pointers where based on C pointers/structs, this patch is very tedious. It should also explain why it is hard to accomplish this in smaller, self-contained patches.
This patch does most of the "heavy lifting" related to moving from PointerType->ObjCObjectPointerType. It doesn't include all potential "cleanups". The good news is additional cleanups can be done later (some are noted in the code). This patch is so large that I didn't want to include any changes that are purely aesthetic.
By making the ObjC types truly built-in, they are much easier to work with (and require fewer "hacks"). For example, there is no need for ASTContext::isObjCIdStructType() or ASTContext::isObjCClassStructType()! We believe this change (and the follow-up cleanups) will pay dividends over time.
Given the amount of code change, I do expect some fallout from this change (though it does pass all of the clang tests). If you notice any problems, please let us know asap! Thanks.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@75314 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 2bd1482..dbac120 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -42,8 +42,8 @@
Idents(idents), Selectors(sels),
BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
if (size_reserve > 0) Types.reserve(size_reserve);
- InitBuiltinTypes();
TUDecl = TranslationUnitDecl::Create(*this);
+ InitBuiltinTypes();
}
ASTContext::~ASTContext() {
@@ -190,11 +190,10 @@
LongDoubleComplexTy = getComplexType(LongDoubleTy);
BuiltinVaListType = QualType();
- ObjCIdType = QualType();
- IdStructType = 0;
- ObjCClassType = QualType();
- ClassStructType = 0;
+ ObjCIdType = QualType();
+ ObjCClassType = QualType();
+
ObjCConstantStringType = QualType();
// void * type
@@ -1071,7 +1070,7 @@
if (T->isPointerType()) {
QualType Pointee = T->getAsPointerType()->getPointeeType();
- if (Pointee->isPointerType()) {
+ if (Pointee->isPointerType() || Pointee->isObjCObjectPointerType()) {
QualType ResultType = getObjCGCQualType(Pointee, GCAttr);
return getPointerType(ResultType);
}
@@ -1847,15 +1846,18 @@
/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for
/// the given interface decl and the conforming protocol list.
-QualType ASTContext::getObjCObjectPointerType(ObjCInterfaceDecl *Decl,
+QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT,
ObjCProtocolDecl **Protocols,
unsigned NumProtocols) {
+ if (InterfaceT.isNull())
+ InterfaceT = QualType(ObjCObjectPointerType::getIdInterface(), 0);
+
// Sort the protocol list alphabetically to canonicalize it.
if (NumProtocols)
SortAndUniqueProtocols(Protocols, NumProtocols);
llvm::FoldingSetNodeID ID;
- ObjCObjectPointerType::Profile(ID, Decl, Protocols, NumProtocols);
+ ObjCObjectPointerType::Profile(ID, InterfaceT, Protocols, NumProtocols);
void *InsertPos = 0;
if (ObjCObjectPointerType *QT =
@@ -1864,7 +1866,7 @@
// No Match;
ObjCObjectPointerType *QType =
- new (*this,8) ObjCObjectPointerType(Decl, Protocols, NumProtocols);
+ new (*this,8) ObjCObjectPointerType(InterfaceT, Protocols, NumProtocols);
Types.push_back(QType);
ObjCObjectPointerTypes.InsertNode(QType, InsertPos);
@@ -2745,25 +2747,7 @@
S += 'j';
getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false,
false);
- } else if (T->isObjCQualifiedIdType()) {
- getObjCEncodingForTypeImpl(getObjCIdType(), S,
- ExpandPointedToStructures,
- ExpandStructures, FD);
- if (FD || EncodingProperty) {
- // Note that we do extended encoding of protocol qualifer list
- // Only when doing ivar or property encoding.
- const ObjCObjectPointerType *QIDT = T->getAsObjCQualifiedIdType();
- S += '"';
- for (ObjCObjectPointerType::qual_iterator I = QIDT->qual_begin(),
- E = QIDT->qual_end(); I != E; ++I) {
- S += '<';
- S += (*I)->getNameAsString();
- S += '>';
- }
- S += '"';
- }
- return;
- }
+ }
else if (const PointerType *PT = T->getAsPointerType()) {
QualType PointeeTy = PT->getPointeeType();
bool isReadOnly = false;
@@ -2797,42 +2781,7 @@
S.replace(S.end()-2, S.end(), replace);
}
}
- if (isObjCIdStructType(PointeeTy)) {
- S += '@';
- return;
- }
- else if (PointeeTy->isObjCInterfaceType()) {
- if (!EncodingProperty &&
- isa<TypedefType>(PointeeTy.getTypePtr())) {
- // Another historical/compatibility reason.
- // We encode the underlying type which comes out as
- // {...};
- S += '^';
- getObjCEncodingForTypeImpl(PointeeTy, S,
- false, ExpandPointedToStructures,
- NULL);
- return;
- }
- S += '@';
- if (FD || EncodingProperty) {
- const ObjCInterfaceType *OIT =
- PointeeTy.getUnqualifiedType()->getAsObjCInterfaceType();
- ObjCInterfaceDecl *OI = OIT->getDecl();
- S += '"';
- S += OI->getNameAsCString();
- for (ObjCInterfaceType::qual_iterator I = OIT->qual_begin(),
- E = OIT->qual_end(); I != E; ++I) {
- S += '<';
- S += (*I)->getNameAsString();
- S += '>';
- }
- S += '"';
- }
- return;
- } else if (isObjCClassStructType(PointeeTy)) {
- S += '#';
- return;
- } else if (isObjCSelType(PointeeTy)) {
+ if (isObjCSelType(PointeeTy)) {
S += ':';
return;
}
@@ -2937,7 +2886,61 @@
}
S += '}';
}
- else
+ else if (const ObjCObjectPointerType *OPT = T->getAsObjCObjectPointerType()) {
+ if (OPT->isObjCIdType()) {
+ S += '@';
+ return;
+ } else if (OPT->isObjCClassType()) {
+ S += '#';
+ return;
+ } else if (OPT->isObjCQualifiedIdType()) {
+ getObjCEncodingForTypeImpl(getObjCIdType(), S,
+ ExpandPointedToStructures,
+ ExpandStructures, FD);
+ if (FD || EncodingProperty) {
+ // Note that we do extended encoding of protocol qualifer list
+ // Only when doing ivar or property encoding.
+ const ObjCObjectPointerType *QIDT = T->getAsObjCQualifiedIdType();
+ S += '"';
+ for (ObjCObjectPointerType::qual_iterator I = QIDT->qual_begin(),
+ E = QIDT->qual_end(); I != E; ++I) {
+ S += '<';
+ S += (*I)->getNameAsString();
+ S += '>';
+ }
+ S += '"';
+ }
+ return;
+ } else {
+ QualType PointeeTy = OPT->getPointeeType();
+ if (!EncodingProperty &&
+ isa<TypedefType>(PointeeTy.getTypePtr())) {
+ // Another historical/compatibility reason.
+ // We encode the underlying type which comes out as
+ // {...};
+ S += '^';
+ getObjCEncodingForTypeImpl(PointeeTy, S,
+ false, ExpandPointedToStructures,
+ NULL);
+ return;
+ }
+ S += '@';
+ if (FD || EncodingProperty) {
+ const ObjCInterfaceType *OIT = OPT->getInterfaceType();
+ ObjCInterfaceDecl *OI = OIT->getDecl();
+ S += '"';
+ S += OI->getNameAsCString();
+ for (ObjCInterfaceType::qual_iterator I = OIT->qual_begin(),
+ E = OIT->qual_end(); I != E; ++I) {
+ S += '<';
+ S += (*I)->getNameAsString();
+ S += '>';
+ }
+ S += '"';
+ }
+ return;
+ }
+ } else
assert(0 && "@encode for type not implemented!");
}
@@ -2967,23 +2970,12 @@
void ASTContext::setObjCIdType(QualType T)
{
ObjCIdType = T;
-
const TypedefType *TT = T->getAsTypedefType();
- if (!TT)
- return;
-
- TypedefDecl *TD = TT->getDecl();
-
- // typedef struct objc_object *id;
- const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
- // User error - caller will issue diagnostics.
- if (!ptr)
- return;
- const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
- // User error - caller will issue diagnostics.
- if (!rec)
- return;
- IdStructType = rec;
+ assert(TT && "missing 'id' typedef");
+ const ObjCObjectPointerType *OPT =
+ TT->getDecl()->getUnderlyingType()->getAsObjCObjectPointerType();
+ assert(OPT && "missing 'id' type");
+ ObjCObjectPointerType::setIdInterface(OPT->getPointeeType());
}
void ASTContext::setObjCSelType(QualType T)
@@ -3013,18 +3005,12 @@
void ASTContext::setObjCClassType(QualType T)
{
ObjCClassType = T;
-
const TypedefType *TT = T->getAsTypedefType();
- if (!TT)
- return;
- TypedefDecl *TD = TT->getDecl();
-
- // typedef struct objc_class *Class;
- const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
- assert(ptr && "'Class' incorrectly typed");
- const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
- assert(rec && "'Class' incorrectly typed");
- ClassStructType = rec;
+ assert(TT && "missing 'Class' typedef");
+ const ObjCObjectPointerType *OPT =
+ TT->getDecl()->getUnderlyingType()->getAsObjCObjectPointerType();
+ assert(OPT && "missing 'Class' type");
+ ObjCObjectPointerType::setClassInterface(OPT->getPointeeType());
}
void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
@@ -3123,6 +3109,8 @@
/// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified
/// ID type).
bool ASTContext::isObjCObjectPointerType(QualType Ty) const {
+ if (Ty->isObjCObjectPointerType())
+ return true;
if (Ty->isObjCQualifiedIdType())
return true;
@@ -3198,8 +3186,30 @@
/// compatible for assignment from RHS to LHS. This handles validation of any
/// protocol qualifiers on the LHS or RHS.
///
+/// FIXME: Move the following to ObjCObjectPointerType/ObjCInterfaceType.
+bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
+ const ObjCObjectPointerType *RHSOPT) {
+ // If either interface represents the built-in 'id' or 'Class' types,
+ // then return true (no need to call canAssignObjCInterfaces()).
+ if (LHSOPT->isObjCIdType() || RHSOPT->isObjCIdType() ||
+ LHSOPT->isObjCClassType() || RHSOPT->isObjCClassType())
+ return true;
+
+ const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
+ const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
+ if (!LHS || !RHS)
+ return false;
+ return canAssignObjCInterfaces(LHS, RHS);
+}
+
bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
const ObjCInterfaceType *RHS) {
+ // If either interface represents the built-in 'id' or 'Class' types,
+ // then return true.
+ if (LHS->isObjCIdInterface() || RHS->isObjCIdInterface() ||
+ LHS->isObjCClassInterface() || RHS->isObjCClassInterface())
+ return true;
+
// Verify that the base decls are compatible: the RHS must be a subclass of
// the LHS.
if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
@@ -3245,25 +3255,14 @@
bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {
// get the "pointed to" types
- const PointerType *LHSPT = LHS->getAsPointerType();
- const PointerType *RHSPT = RHS->getAsPointerType();
+ const ObjCObjectPointerType *LHSOPT = LHS->getAsObjCObjectPointerType();
+ const ObjCObjectPointerType *RHSOPT = RHS->getAsObjCObjectPointerType();
- if (!LHSPT || !RHSPT)
+ if (!LHSOPT || !RHSOPT)
return false;
-
- QualType lhptee = LHSPT->getPointeeType();
- QualType rhptee = RHSPT->getPointeeType();
- const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType();
- const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType();
- // ID acts sort of like void* for ObjC interfaces
- if (LHSIface && isObjCIdStructType(rhptee))
- return true;
- if (RHSIface && isObjCIdStructType(lhptee))
- return true;
- if (!LHSIface || !RHSIface)
- return false;
- return canAssignObjCInterfaces(LHSIface, RHSIface) ||
- canAssignObjCInterfaces(RHSIface, LHSIface);
+
+ return canAssignObjCInterfaces(LHSOPT, RHSOPT) ||
+ canAssignObjCInterfaces(RHSOPT, LHSOPT);
}
/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible,
@@ -3406,8 +3405,7 @@
// issue error.
if ((GCAttr == QualType::Weak && GCLHSAttr != GCAttr) ||
(GCAttr == QualType::Strong && GCLHSAttr != GCAttr &&
- LHSCan->isPointerType() && !isObjCObjectPointerType(LHSCan) &&
- !isObjCIdStructType(LHSCan->getAsPointerType()->getPointeeType())))
+ !LHSCan->isObjCObjectPointerType()))
return QualType();
RHS = QualType(cast<ExtQualType>(RHS.getDesugaredType())->getBaseType(),
@@ -3432,8 +3430,7 @@
// issue error.
if ((GCAttr == QualType::Weak && GCRHSAttr != GCAttr) ||
(GCAttr == QualType::Strong && GCRHSAttr != GCAttr &&
- RHSCan->isPointerType() && !isObjCObjectPointerType(RHSCan) &&
- !isObjCIdStructType(RHSCan->getAsPointerType()->getPointeeType())))
+ !RHSCan->isObjCObjectPointerType()))
return QualType();
LHS = QualType(cast<ExtQualType>(LHS.getDesugaredType())->getBaseType(),
@@ -3460,47 +3457,12 @@
if (RHSClass == Type::ExtVector) RHSClass = Type::Vector;
// Consider qualified interfaces and interfaces the same.
+ // FIXME: Remove (ObjCObjectPointerType should obsolete this funny business).
if (LHSClass == Type::ObjCQualifiedInterface) LHSClass = Type::ObjCInterface;
if (RHSClass == Type::ObjCQualifiedInterface) RHSClass = Type::ObjCInterface;
// If the canonical type classes don't match.
if (LHSClass != RHSClass) {
- const ObjCInterfaceType* LHSIface = LHS->getAsObjCInterfaceType();
- const ObjCInterfaceType* RHSIface = RHS->getAsObjCInterfaceType();
-
- // 'id' and 'Class' act sort of like void* for ObjC interfaces
- if (LHSIface && (isObjCIdStructType(RHS) || isObjCClassStructType(RHS)))
- return LHS;
- if (RHSIface && (isObjCIdStructType(LHS) || isObjCClassStructType(LHS)))
- return RHS;
-
- // ID is compatible with all qualified id types.
- if (LHS->isObjCQualifiedIdType()) {
- if (const PointerType *PT = RHS->getAsPointerType()) {
- QualType pType = PT->getPointeeType();
- if (isObjCIdStructType(pType) || isObjCClassStructType(pType))
- return LHS;
- // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true).
- // Unfortunately, this API is part of Sema (which we don't have access
- // to. Need to refactor. The following check is insufficient, since we
- // need to make sure the class implements the protocol.
- if (pType->isObjCInterfaceType())
- return LHS;
- }
- }
- if (RHS->isObjCQualifiedIdType()) {
- if (const PointerType *PT = LHS->getAsPointerType()) {
- QualType pType = PT->getPointeeType();
- if (isObjCIdStructType(pType) || isObjCClassStructType(pType))
- return RHS;
- // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true).
- // Unfortunately, this API is part of Sema (which we don't have access
- // to. Need to refactor. The following check is insufficient, since we
- // need to make sure the class implements the protocol.
- if (pType->isObjCInterfaceType())
- return RHS;
- }
- }
// C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
// a signed integer type, or an unsigned integer type.
if (const EnumType* ETy = LHS->getAsEnumType()) {
@@ -3611,9 +3573,6 @@
return mergeFunctionTypes(LHS, RHS);
case Type::Record:
case Type::Enum:
- // FIXME: Why are these compatible?
- if (isObjCIdStructType(LHS) && isObjCClassStructType(RHS)) return LHS;
- if (isObjCClassStructType(LHS) && isObjCIdStructType(RHS)) return LHS;
return QualType();
case Type::Builtin:
// Only exactly equal builtin types are compatible, which is tested above.
@@ -3638,10 +3597,17 @@
return QualType();
}
- case Type::ObjCObjectPointer:
- // FIXME: finish
- // Distinct qualified id's are not compatible.
+ case Type::ObjCObjectPointer: {
+ // FIXME: Incorporate tests from Sema::ObjCQualifiedIdTypesAreCompatible().
+ if (LHS->isObjCQualifiedIdType() && RHS->isObjCQualifiedIdType())
+ return QualType();
+
+ if (canAssignObjCInterfaces(LHS->getAsObjCObjectPointerType(),
+ RHS->getAsObjCObjectPointerType()))
+ return LHS;
+
return QualType();
+ }
case Type::FixedWidthInt:
// Distinct fixed-width integers are not compatible.
return QualType();