Newer
Older
// Sort protocols, keyed by name.
std::sort(Protocols, Protocols+NumProtocols, CmpProtocolNames);
// Remove duplicates.
ProtocolsEnd = std::unique(Protocols, ProtocolsEnd);
NumProtocols = ProtocolsEnd-Protocols;
}
/// getObjCQualifiedInterfaceType - Return a ObjCQualifiedInterfaceType type for
/// the given interface decl and the conforming protocol list.
QualType ASTContext::getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl,
ObjCProtocolDecl **Protocols, unsigned NumProtocols) {
// Sort the protocol list alphabetically to canonicalize it.
SortAndUniqueProtocols(Protocols, NumProtocols);
llvm::FoldingSetNodeID ID;
ObjCQualifiedInterfaceType::Profile(ID, Decl, Protocols, NumProtocols);
void *InsertPos = 0;
if (ObjCQualifiedInterfaceType *QT =
ObjCQualifiedInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(QT, 0);
// No Match;
ObjCQualifiedInterfaceType *QType =
new ObjCQualifiedInterfaceType(Decl, Protocols, NumProtocols);
Types.push_back(QType);
ObjCQualifiedInterfaceTypes.InsertNode(QType, InsertPos);
return QualType(QType, 0);
}
/// getObjCQualifiedIdType - Return an ObjCQualifiedIdType for the 'id' decl
/// and the conforming protocol list.
Chris Lattner
committed
QualType ASTContext::getObjCQualifiedIdType(ObjCProtocolDecl **Protocols,
Fariborz Jahanian
committed
unsigned NumProtocols) {
// Sort the protocol list alphabetically to canonicalize it.
SortAndUniqueProtocols(Protocols, NumProtocols);
Fariborz Jahanian
committed
llvm::FoldingSetNodeID ID;
ObjCQualifiedIdType::Profile(ID, Protocols, NumProtocols);
Fariborz Jahanian
committed
void *InsertPos = 0;
if (ObjCQualifiedIdType *QT =
Chris Lattner
committed
ObjCQualifiedIdTypes.FindNodeOrInsertPos(ID, InsertPos))
Fariborz Jahanian
committed
return QualType(QT, 0);
// No Match;
Chris Lattner
committed
ObjCQualifiedIdType *QType = new ObjCQualifiedIdType(Protocols, NumProtocols);
Fariborz Jahanian
committed
Types.push_back(QType);
ObjCQualifiedIdTypes.InsertNode(QType, InsertPos);
Fariborz Jahanian
committed
return QualType(QType, 0);
}
/// getTypeOfExpr - Unlike many "get<Type>" functions, we can't unique
/// TypeOfExpr AST's (since expression's are never shared). For example,
/// multiple declarations that refer to "typeof(x)" all contain different
/// DeclRefExpr's. This doesn't effect the type checker, since it operates
/// on canonical type's (which are always unique).
Chris Lattner
committed
QualType Canonical = getCanonicalType(tofExpr->getType());
TypeOfExpr *toe = new TypeOfExpr(tofExpr, Canonical);
Types.push_back(toe);
return QualType(toe, 0);
/// getTypeOfType - Unlike many "get<Type>" functions, we don't unique
/// TypeOfType AST's. The only motivation to unique these nodes would be
/// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be
/// an issue. This doesn't effect the type checker, since it operates
/// on canonical type's (which are always unique).
Chris Lattner
committed
QualType Canonical = getCanonicalType(tofType);
TypeOfType *tot = new TypeOfType(tofType, Canonical);
Types.push_back(tot);
return QualType(tot, 0);
/// getTagDeclType - Return the unique reference to the type for the
/// specified TagDecl (struct/union/class/enum) decl.
assert (Decl);
Douglas Gregor
committed
return getTypeDeclType(Decl);
}
/// getSizeType - Return the unique type for "size_t" (C99 7.17), the result
/// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and
// On Darwin, size_t is defined as a "long unsigned int".
// FIXME: should derive from "Target".
return UnsignedLongTy;
}
/// getWCharType - Return the unique type for "wchar_t" (C99 7.17), the
/// width of characters in wide strings, The value is target dependent and
/// needs to agree with the definition in <stddef.h>.
QualType ASTContext::getWCharType() const {
if (LangOpts.CPlusPlus)
return WCharTy;
// On Darwin, wchar_t is defined as a "int".
// FIXME: should derive from "Target".
return IntTy;
}
/// getSignedWCharType - Return the type of "signed wchar_t".
/// Used when in C++, as a GCC extension.
QualType ASTContext::getSignedWCharType() const {
// FIXME: derive from "Target" ?
return WCharTy;
}
/// getUnsignedWCharType - Return the type of "unsigned wchar_t".
/// Used when in C++, as a GCC extension.
QualType ASTContext::getUnsignedWCharType() const {
// FIXME: derive from "Target" ?
return UnsignedIntTy;
}
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?)
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType ASTContext::getPointerDiffType() const {
// On Darwin, ptrdiff_t is defined as a "int". This seems like a bug...
// FIXME: should derive from "Target".
return IntTy;
}
//===----------------------------------------------------------------------===//
// Type Operators
//===----------------------------------------------------------------------===//
/// getCanonicalType - Return the canonical (structural) type corresponding to
/// the specified potentially non-canonical type. The non-canonical version
/// of a type may have many "decorated" versions of types. Decorators can
/// include typedefs, 'typeof' operators, etc. The returned type is guaranteed
/// to be free of any of these, allowing two canonical types to be compared
/// for exact equality with a simple pointer comparison.
QualType ASTContext::getCanonicalType(QualType T) {
QualType CanType = T.getTypePtr()->getCanonicalTypeInternal();
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
// If the result has type qualifiers, make sure to canonicalize them as well.
unsigned TypeQuals = T.getCVRQualifiers() | CanType.getCVRQualifiers();
if (TypeQuals == 0) return CanType;
// If the type qualifiers are on an array type, get the canonical type of the
// array with the qualifiers applied to the element type.
ArrayType *AT = dyn_cast<ArrayType>(CanType);
if (!AT)
return CanType.getQualifiedType(TypeQuals);
// Get the canonical version of the element with the extra qualifiers on it.
// This can recursively sink qualifiers through multiple levels of arrays.
QualType NewEltTy=AT->getElementType().getWithAdditionalQualifiers(TypeQuals);
NewEltTy = getCanonicalType(NewEltTy);
if (ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
return getConstantArrayType(NewEltTy, CAT->getSize(),CAT->getSizeModifier(),
CAT->getIndexTypeQualifier());
if (IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT))
return getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(),
IAT->getIndexTypeQualifier());
// FIXME: What is the ownership of size expressions in VLAs?
VariableArrayType *VAT = cast<VariableArrayType>(AT);
return getVariableArrayType(NewEltTy, VAT->getSizeExpr(),
VAT->getSizeModifier(),
VAT->getIndexTypeQualifier());
}
const ArrayType *ASTContext::getAsArrayType(QualType T) {
// Handle the non-qualified case efficiently.
if (T.getCVRQualifiers() == 0) {
// Handle the common positive case fast.
if (const ArrayType *AT = dyn_cast<ArrayType>(T))
return AT;
}
// Handle the common negative case fast, ignoring CVR qualifiers.
QualType CType = T->getCanonicalTypeInternal();
// Make sure to look through type qualifiers (like ASQuals) for the negative
// test.
if (!isa<ArrayType>(CType) &&
!isa<ArrayType>(CType.getUnqualifiedType()))
return 0;
// Apply any CVR qualifiers from the array type to the element type. This
// implements C99 6.7.3p8: "If the specification of an array type includes
// any type qualifiers, the element type is so qualified, not the array type."
// If we get here, we either have type qualifiers on the type, or we have
// sugar such as a typedef in the way. If we have type qualifiers on the type
// we must propagate them down into the elemeng type.
unsigned CVRQuals = T.getCVRQualifiers();
unsigned AddrSpace = 0;
Type *Ty = T.getTypePtr();
// Rip through ASQualType's and typedefs to get to a concrete type.
while (1) {
if (const ASQualType *ASQT = dyn_cast<ASQualType>(Ty)) {
AddrSpace = ASQT->getAddressSpace();
Ty = ASQT->getBaseType();
} else {
T = Ty->getDesugaredType();
if (T.getTypePtr() == Ty && T.getCVRQualifiers() == 0)
break;
CVRQuals |= T.getCVRQualifiers();
Ty = T.getTypePtr();
}
}
// If we have a simple case, just return now.
const ArrayType *ATy = dyn_cast<ArrayType>(Ty);
if (ATy == 0 || (AddrSpace == 0 && CVRQuals == 0))
return ATy;
// Otherwise, we have an array and we have qualifiers on it. Push the
// qualifiers into the array element type and return a new array type.
// Get the canonical version of the element with the extra qualifiers on it.
// This can recursively sink qualifiers through multiple levels of arrays.
QualType NewEltTy = ATy->getElementType();
if (AddrSpace)
NewEltTy = getASQualType(NewEltTy, AddrSpace);
NewEltTy = NewEltTy.getWithAdditionalQualifiers(CVRQuals);
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy))
return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(),
CAT->getSizeModifier(),
CAT->getIndexTypeQualifier()));
if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(ATy))
return cast<ArrayType>(getIncompleteArrayType(NewEltTy,
IAT->getSizeModifier(),
IAT->getIndexTypeQualifier()));
// FIXME: What is the ownership of size expressions in VLAs?
const VariableArrayType *VAT = cast<VariableArrayType>(ATy);
return cast<ArrayType>(getVariableArrayType(NewEltTy, VAT->getSizeExpr(),
VAT->getSizeModifier(),
VAT->getIndexTypeQualifier()));
}
/// getArrayDecayedType - Return the properly qualified result of decaying the
/// specified array type to a pointer. This operation is non-trivial when
/// handling typedefs etc. The canonical type of "T" must be an array type,
/// this returns a pointer to a properly qualified element of the array.
///
/// See C99 6.7.5.3p7 and C99 6.3.2.1p3.
QualType ASTContext::getArrayDecayedType(QualType Ty) {
// Get the element type with 'getAsArrayType' so that we don't lose any
// typedefs in the element type of the array. This also handles propagation
// of type qualifiers from the array type into the element type if present
// (C99 6.7.3p8).
const ArrayType *PrettyArrayType = getAsArrayType(Ty);
assert(PrettyArrayType && "Not an array type!");
// int x[restrict 4] -> int *restrict
return PtrTy.getQualifiedType(PrettyArrayType->getIndexTypeQualifier());
/// getFloatingRank - Return a relative rank for floating point types.
/// This routine will assert if passed a built-in type that isn't a float.
static FloatingRank getFloatingRank(QualType T) {
Christopher Lamb
committed
if (const ComplexType *CT = T->getAsComplexType())
Chris Lattner
committed
return getFloatingRank(CT->getElementType());
Christopher Lamb
committed
switch (T->getAsBuiltinType()->getKind()) {
default: assert(0 && "getFloatingRank(): not a floating type");
Chris Lattner
committed
case BuiltinType::Float: return FloatRank;
case BuiltinType::Double: return DoubleRank;
case BuiltinType::LongDouble: return LongDoubleRank;
/// getFloatingTypeOfSizeWithinDomain - Returns a real floating
/// point or a complex type (based on typeDomain/typeSize).
/// 'typeDomain' is a real floating point or complex type.
/// 'typeSize' is a real floating point or complex type.
QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
QualType Domain) const {
FloatingRank EltRank = getFloatingRank(Size);
if (Domain->isComplexType()) {
switch (EltRank) {
case FloatRank: return FloatComplexTy;
case DoubleRank: return DoubleComplexTy;
case LongDoubleRank: return LongDoubleComplexTy;
}
}
assert(Domain->isRealFloatingType() && "Unknown domain!");
switch (EltRank) {
default: assert(0 && "getFloatingRank(): illegal value for rank");
case FloatRank: return FloatTy;
case DoubleRank: return DoubleTy;
case LongDoubleRank: return LongDoubleTy;
/// getFloatingTypeOrder - Compare the rank of the two specified floating
/// point types, ignoring the domain of the type (i.e. 'double' ==
/// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If
/// LHS < RHS, return -1.
int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) {
FloatingRank LHSR = getFloatingRank(LHS);
FloatingRank RHSR = getFloatingRank(RHS);
if (LHSR == RHSR)
Steve Naroff
committed
return 0;
Steve Naroff
committed
return 1;
return -1;
Chris Lattner
committed
/// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This
/// routine will assert if passed a built-in type that isn't an integer or enum,
/// or if it is not canonicalized.
static unsigned getIntegerRank(Type *T) {
assert(T->isCanonical() && "T should be canonicalized");
if (isa<EnumType>(T))
return 4;
switch (cast<BuiltinType>(T)->getKind()) {
default: assert(0 && "getIntegerRank(): not a built-in integer");
case BuiltinType::Bool:
return 1;
case BuiltinType::Char_S:
case BuiltinType::Char_U:
case BuiltinType::SChar:
case BuiltinType::UChar:
return 2;
case BuiltinType::Short:
case BuiltinType::UShort:
return 3;
case BuiltinType::Int:
case BuiltinType::UInt:
return 4;
case BuiltinType::Long:
case BuiltinType::ULong:
return 5;
case BuiltinType::LongLong:
case BuiltinType::ULongLong:
return 6;
Chris Lattner
committed
}
}
/// getIntegerTypeOrder - Returns the highest ranked integer type:
/// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If
/// LHS < RHS, return -1.
int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) {
Chris Lattner
committed
Type *LHSC = getCanonicalType(LHS).getTypePtr();
Type *RHSC = getCanonicalType(RHS).getTypePtr();
if (LHSC == RHSC) return 0;
Chris Lattner
committed
Chris Lattner
committed
bool LHSUnsigned = LHSC->isUnsignedIntegerType();
bool RHSUnsigned = RHSC->isUnsignedIntegerType();
unsigned LHSRank = getIntegerRank(LHSC);
unsigned RHSRank = getIntegerRank(RHSC);
if (LHSUnsigned == RHSUnsigned) { // Both signed or both unsigned.
if (LHSRank == RHSRank) return 0;
return LHSRank > RHSRank ? 1 : -1;
}
// Otherwise, the LHS is signed and the RHS is unsigned or visa versa.
if (LHSUnsigned) {
// If the unsigned [LHS] type is larger, return it.
if (LHSRank >= RHSRank)
return 1;
// If the signed type can represent all values of the unsigned type, it
// wins. Because we are dealing with 2's complement and types that are
// powers of two larger than each other, this is always safe.
return -1;
}
// If the unsigned [RHS] type is larger, return it.
if (RHSRank >= LHSRank)
return -1;
// If the signed type can represent all values of the unsigned type, it
// wins. Because we are dealing with 2's complement and types that are
// powers of two larger than each other, this is always safe.
return 1;
// getCFConstantStringType - Return the type used for constant CFStrings.
QualType ASTContext::getCFConstantStringType() {
if (!CFConstantStringTypeDecl) {
CFConstantStringTypeDecl =
RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
Ted Kremenek
committed
&Idents.get("NSConstantString"));
QualType FieldTypes[4];
// const int *isa;
FieldTypes[0] = getPointerType(IntTy.getQualifiedType(QualType::Const));
// int flags;
FieldTypes[1] = IntTy;
FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const));
FieldTypes[3] = LongTy;
FieldDecl *FieldDecls[4];
for (unsigned i = 0; i < 4; ++i)
FieldDecls[i] = FieldDecl::Create(*this, SourceLocation(), 0,
Ted Kremenek
committed
CFConstantStringTypeDecl->defineBody(*this, FieldDecls, 4);
}
return getTagDeclType(CFConstantStringTypeDecl);
QualType ASTContext::getObjCFastEnumerationStateType()
{
if (!ObjCFastEnumerationStateTypeDecl) {
QualType FieldTypes[] = {
UnsignedLongTy,
getPointerType(ObjCIdType),
getPointerType(UnsignedLongTy),
getConstantArrayType(UnsignedLongTy,
llvm::APInt(32, 5), ArrayType::Normal, 0)
};
FieldDecl *FieldDecls[4];
for (size_t i = 0; i < 4; ++i)
FieldDecls[i] = FieldDecl::Create(*this, SourceLocation(), 0,
FieldTypes[i]);
ObjCFastEnumerationStateTypeDecl =
RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
Ted Kremenek
committed
&Idents.get("__objcFastEnumerationState"));
Ted Kremenek
committed
ObjCFastEnumerationStateTypeDecl->defineBody(*this, FieldDecls, 4);
}
return getTagDeclType(ObjCFastEnumerationStateTypeDecl);
}
// This returns true if a type has been typedefed to BOOL:
// typedef <type> BOOL;
if (const TypedefType *TT = dyn_cast<TypedefType>(T))
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
int ASTContext::getObjCEncodingTypeSize(QualType type) {
uint64_t sz = getTypeSize(type);
// Make all integer and enum types at least as large as an int
if (sz > 0 && type->isIntegralType())
sz = std::max(sz, getTypeSize(IntTy));
// Treat arrays as pointers, since that's how they're passed in.
else if (type->isArrayType())
sz = getTypeSize(VoidPtrTy);
return sz / getTypeSize(CharTy);
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
// FIXME: This is not very efficient.
Fariborz Jahanian
committed
// Encode type qualifer, 'in', 'inout', etc. for the return type.
getObjCEncodingForTypeQualifier(Decl->getObjCDeclQualifier(), S);
getObjCEncodingForType(Decl->getResultType(), S);
// Compute size of all parameters.
// Start with computing size of a pointer in number of bytes.
// FIXME: There might(should) be a better way of doing this computation!
SourceLocation Loc;
int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy);
// The first two arguments (self and _cmd) are pointers; account for
// their size.
int ParmOffset = 2 * PtrSize;
int NumOfParams = Decl->getNumParams();
for (int i = 0; i < NumOfParams; i++) {
QualType PType = Decl->getParamDecl(i)->getType();
int sz = getObjCEncodingTypeSize (PType);
assert (sz > 0 && "getObjCEncodingForMethodDecl - Incomplete param type");
ParmOffset += sz;
}
S += llvm::utostr(ParmOffset);
S += "@0:";
S += llvm::utostr(PtrSize);
// Argument types.
ParmOffset = 2 * PtrSize;
for (int i = 0; i < NumOfParams; i++) {
QualType PType = Decl->getParamDecl(i)->getType();
Fariborz Jahanian
committed
// Process argument qualifiers for user supplied arguments; such as,
getObjCEncodingForTypeQualifier(
Decl->getParamDecl(i)->getObjCDeclQualifier(), S);
getObjCEncodingForType(PType, S);
ParmOffset += getObjCEncodingTypeSize(PType);
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
/// getObjCEncodingForPropertyDecl - Return the encoded type for this
/// method declaration. If non-NULL, Container must be either an
/// ObjCCategoryImplDecl or ObjCImplementationDecl; it should only be
/// NULL when getting encodings for protocol properties.
void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
const Decl *Container,
std::string& S)
{
// Collect information from the property implementation decl(s).
bool Dynamic = false;
ObjCPropertyImplDecl *SynthesizePID = 0;
// FIXME: Duplicated code due to poor abstraction.
if (Container) {
if (const ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(Container)) {
for (ObjCCategoryImplDecl::propimpl_iterator
i = CID->propimpl_begin(), e = CID->propimpl_end(); i != e; ++i) {
ObjCPropertyImplDecl *PID = *i;
if (PID->getPropertyDecl() == PD) {
if (PID->getPropertyImplementation()==ObjCPropertyImplDecl::Dynamic) {
Dynamic = true;
} else {
SynthesizePID = PID;
}
}
}
} else {
const ObjCImplementationDecl *OID=cast<ObjCImplementationDecl>(Container);
for (ObjCCategoryImplDecl::propimpl_iterator
i = OID->propimpl_begin(), e = OID->propimpl_end(); i != e; ++i) {
ObjCPropertyImplDecl *PID = *i;
if (PID->getPropertyDecl() == PD) {
if (PID->getPropertyImplementation()==ObjCPropertyImplDecl::Dynamic) {
Dynamic = true;
} else {
SynthesizePID = PID;
}
}
}
}
}
// FIXME: This is not very efficient.
S = "T";
// Encode result type.
// FIXME: GCC uses a generating_property_type_encoding mode during
// this part. Investigate.
getObjCEncodingForType(PD->getType(), S);
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
if (PD->isReadOnly()) {
S += ",R";
} else {
switch (PD->getSetterKind()) {
case ObjCPropertyDecl::Assign: break;
case ObjCPropertyDecl::Copy: S += ",C"; break;
case ObjCPropertyDecl::Retain: S += ",&"; break;
}
}
// It really isn't clear at all what this means, since properties
// are "dynamic by default".
if (Dynamic)
S += ",D";
if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) {
S += ",G";
S += PD->getGetterName().getName();
}
if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) {
S += ",S";
S += PD->getSetterName().getName();
}
if (SynthesizePID) {
const ObjCIvarDecl *OID = SynthesizePID->getPropertyIvarDecl();
S += ",V";
S += OID->getName();
}
// FIXME: OBJCGC: weak & strong
}
Fariborz Jahanian
committed
void ASTContext::getObjCEncodingForType(QualType T, std::string& S,
// We follow the behavior of gcc, expanding structures which are
// directly pointed to, and expanding embedded structures. Note that
// these rules are sufficient to prevent recursive encoding of the
// same type.
getObjCEncodingForTypeImpl(T, S, true, true, NameFields);
}
void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
bool ExpandPointedToStructures,
bool ExpandStructures,
if (const BuiltinType *BT = T->getAsBuiltinType()) {
char encoding;
switch (BT->getKind()) {
default: assert(0 && "Unhandled builtin type kind");
case BuiltinType::Void: encoding = 'v'; break;
case BuiltinType::Bool: encoding = 'B'; break;
case BuiltinType::UChar: encoding = 'C'; break;
case BuiltinType::UShort: encoding = 'S'; break;
case BuiltinType::UInt: encoding = 'I'; break;
case BuiltinType::ULong: encoding = 'L'; break;
case BuiltinType::ULongLong: encoding = 'Q'; break;
case BuiltinType::SChar: encoding = 'c'; break;
case BuiltinType::Short: encoding = 's'; break;
case BuiltinType::Int: encoding = 'i'; break;
case BuiltinType::Long: encoding = 'l'; break;
case BuiltinType::LongLong: encoding = 'q'; break;
case BuiltinType::Float: encoding = 'f'; break;
case BuiltinType::Double: encoding = 'd'; break;
case BuiltinType::LongDouble: encoding = 'd'; break;
Fariborz Jahanian
committed
}
else if (T->isObjCQualifiedIdType()) {
Fariborz Jahanian
committed
// Treat id<P...> same as 'id' for encoding purposes.
return getObjCEncodingForTypeImpl(getObjCIdType(), S,
ExpandPointedToStructures,
ExpandStructures, NameFields);
Fariborz Jahanian
committed
}
else if (const PointerType *PT = T->getAsPointerType()) {
QualType PointeeTy = PT->getPointeeType();
if (isObjCIdType(PointeeTy) || PointeeTy->isObjCInterfaceType()) {
} else if (isObjCClassType(PointeeTy)) {
} else if (isObjCSelType(PointeeTy)) {
if (PointeeTy->isCharType()) {
// char pointer types should be encoded as '*' unless it is a
// type that has been typedef'd to 'BOOL'.
S += '*';
return;
}
}
S += '^';
getObjCEncodingForTypeImpl(PT->getPointeeType(), S,
false, ExpandPointedToStructures,
NameFields);
} else if (const ArrayType *AT =
// Ignore type qualifiers etc.
dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) {
S += '[';
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
S += llvm::utostr(CAT->getSize().getZExtValue());
else
assert(0 && "Unhandled array type!");
getObjCEncodingForTypeImpl(AT->getElementType(), S,
false, ExpandStructures, NameFields);
} else if (T->getAsFunctionType()) {
S += '?';
} else if (const RecordType *RTy = T->getAsRecordType()) {
RecordDecl *RDecl = RTy->getDecl();
S += RDecl->isUnion() ? '(' : '{';
// Anonymous structures print as '?'
if (const IdentifierInfo *II = RDecl->getIdentifier()) {
S += II->getName();
} else {
S += '?';
}
if (ExpandStructures) {
Fariborz Jahanian
committed
S += '=';
for (int i = 0; i < RDecl->getNumMembers(); i++) {
FieldDecl *FD = RDecl->getMember(i);
if (NameFields) {
S += '"';
S += FD->getName();
S += '"';
}
// Special case bit-fields.
if (const Expr *E = FD->getBitWidth()) {
// FIXME: Fix constness.
ASTContext *Ctx = const_cast<ASTContext*>(this);
unsigned N = E->getIntegerConstantExprValue(*Ctx).getZExtValue();
// FIXME: Obj-C is losing information about the type size
// here. Investigate if this is a problem.
S += 'b';
S += llvm::utostr(N);
} else {
getObjCEncodingForTypeImpl(FD->getType(), S, false, true, NameFields);
Fariborz Jahanian
committed
}
S += RDecl->isUnion() ? ')' : '}';
Steve Naroff
committed
} else if (T->isBlockPointerType()) {
S += '^'; // This type string is the same as general pointers.
void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
Fariborz Jahanian
committed
std::string& S) const {
if (QT & Decl::OBJC_TQ_In)
S += 'n';
if (QT & Decl::OBJC_TQ_Inout)
S += 'N';
if (QT & Decl::OBJC_TQ_Out)
S += 'o';
if (QT & Decl::OBJC_TQ_Bycopy)
S += 'O';
if (QT & Decl::OBJC_TQ_Byref)
S += 'R';
if (QT & Decl::OBJC_TQ_Oneway)
S += 'V';
}
void ASTContext::setBuiltinVaListType(QualType T)
{
assert(BuiltinVaListType.isNull() && "__builtin_va_list type already set!");
BuiltinVaListType = T;
}
void ASTContext::setObjCIdType(TypedefDecl *TD)
ObjCIdType = getTypedefType(TD);
// typedef struct objc_object *id;
const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
assert(ptr && "'id' incorrectly typed");
const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
assert(rec && "'id' incorrectly typed");
IdStructType = rec;
}
void ASTContext::setObjCSelType(TypedefDecl *TD)
Fariborz Jahanian
committed
{
ObjCSelType = getTypedefType(TD);
Fariborz Jahanian
committed
// typedef struct objc_selector *SEL;
const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
assert(ptr && "'SEL' incorrectly typed");
const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
assert(rec && "'SEL' incorrectly typed");
SelStructType = rec;
}
void ASTContext::setObjCProtoType(QualType QT)
ObjCProtoType = QT;
void ASTContext::setObjCClassType(TypedefDecl *TD)
ObjCClassType = getTypedefType(TD);
// 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;
}
void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
assert(ObjCConstantStringType.isNull() &&
ObjCConstantStringType = getObjCInterfaceType(Decl);
//===----------------------------------------------------------------------===//
// Type Predicates.
//===----------------------------------------------------------------------===//
/// isObjCObjectPointerType - Returns true if type is an Objective-C pointer
/// to an object type. This includes "id" and "Class" (two 'special' pointers
/// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified
/// ID type).
bool ASTContext::isObjCObjectPointerType(QualType Ty) const {
if (Ty->isObjCQualifiedIdType())
return true;
Steve Naroff
committed
// Blocks are objects.
if (Ty->isBlockPointerType())
return true;
// All other object types are pointers.
if (!Ty->isPointerType())
return false;
// Check to see if this is 'id' or 'Class', both of which are typedefs for
// pointer types. This looks for the typedef specifically, not for the
// underlying type.
if (Ty == getObjCIdType() || Ty == getObjCClassType())
return true;
// If this a pointer to an interface (e.g. NSString*), it is ok.
return Ty->getAsPointerType()->getPointeeType()->isObjCInterfaceType();
}
//===----------------------------------------------------------------------===//
// Type Compatibility Testing
//===----------------------------------------------------------------------===//
/// typesAreBlockCompatible - This routine is called when comparing two
Steve Naroff
committed
/// block types. Types must be strictly compatible here. For example,
/// C unfortunately doesn't produce an error for the following:
///
/// int (*emptyArgFunc)();
/// int (*intArgList)(int) = emptyArgFunc;
///
/// For blocks, we will produce an error for the following (similar to C++):
///
/// int (^emptyArgBlock)();
/// int (^intArgBlock)(int) = emptyArgBlock;
///
/// FIXME: When the dust settles on this integration, fold this into mergeTypes.
///
bool ASTContext::typesAreBlockCompatible(QualType lhs, QualType rhs) {
return getCanonicalType(lhs) == getCanonicalType(rhs);
/// areCompatVectorTypes - Return true if the two specified vector types are
/// compatible.
static bool areCompatVectorTypes(const VectorType *LHS,
const VectorType *RHS) {
assert(LHS->isCanonical() && RHS->isCanonical());
return LHS->getElementType() == RHS->getElementType() &&
LHS->getNumElements() == RHS->getNumElements();
/// canAssignObjCInterfaces - Return true if the two interface types are
/// compatible for assignment from RHS to LHS. This handles validation of any
/// protocol qualifiers on the LHS or RHS.
///
bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
const ObjCInterfaceType *RHS) {
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
// Verify that the base decls are compatible: the RHS must be a subclass of
// the LHS.
if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
return false;
// RHS must have a superset of the protocols in the LHS. If the LHS is not
// protocol qualified at all, then we are good.
if (!isa<ObjCQualifiedInterfaceType>(LHS))
return true;
// Okay, we know the LHS has protocol qualifiers. If the RHS doesn't, then it
// isn't a superset.
if (!isa<ObjCQualifiedInterfaceType>(RHS))
return true; // FIXME: should return false!
// Finally, we must have two protocol-qualified interfaces.
const ObjCQualifiedInterfaceType *LHSP =cast<ObjCQualifiedInterfaceType>(LHS);
const ObjCQualifiedInterfaceType *RHSP =cast<ObjCQualifiedInterfaceType>(RHS);
ObjCQualifiedInterfaceType::qual_iterator LHSPI = LHSP->qual_begin();
ObjCQualifiedInterfaceType::qual_iterator LHSPE = LHSP->qual_end();
ObjCQualifiedInterfaceType::qual_iterator RHSPI = RHSP->qual_begin();
ObjCQualifiedInterfaceType::qual_iterator RHSPE = RHSP->qual_end();
// All protocols in LHS must have a presence in RHS. Since the protocol lists
// are both sorted alphabetically and have no duplicates, we can scan RHS and
// LHS in a single parallel scan until we run out of elements in LHS.
assert(LHSPI != LHSPE && "Empty LHS protocol list?");
ObjCProtocolDecl *LHSProto = *LHSPI;
while (RHSPI != RHSPE) {
ObjCProtocolDecl *RHSProto = *RHSPI++;
// If the RHS has a protocol that the LHS doesn't, ignore it.
if (RHSProto != LHSProto)
continue;
// Otherwise, the RHS does have this element.
++LHSPI;
if (LHSPI == LHSPE)
return true; // All protocols in LHS exist in RHS.
LHSProto = *LHSPI;
}
// If we got here, we didn't find one of the LHS's protocols in the RHS list.
return false;
}
/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible,
/// both shall have the identically qualified version of a compatible type.
/// C99 6.2.7p1: Two types have compatible types if their types are the
/// same. See 6.7.[2,3,5] for additional rules.
bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) {
return !mergeTypes(LHS, RHS).isNull();
}
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
const FunctionType *lbase = lhs->getAsFunctionType();
const FunctionType *rbase = rhs->getAsFunctionType();
const FunctionTypeProto *lproto = dyn_cast<FunctionTypeProto>(lbase);
const FunctionTypeProto *rproto = dyn_cast<FunctionTypeProto>(rbase);
bool allLTypes = true;
bool allRTypes = true;
// Check return type
QualType retType = mergeTypes(lbase->getResultType(), rbase->getResultType());
if (retType.isNull()) return QualType();
if (getCanonicalType(retType) != getCanonicalType(lbase->getResultType()))
allLTypes = false;
if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType()))
allRTypes = false;
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
if (lproto && rproto) { // two C99 style function prototypes
unsigned lproto_nargs = lproto->getNumArgs();
unsigned rproto_nargs = rproto->getNumArgs();
// Compatible functions must have the same number of arguments
if (lproto_nargs != rproto_nargs)
return QualType();
// Variadic and non-variadic functions aren't compatible
if (lproto->isVariadic() != rproto->isVariadic())
return QualType();
// Check argument compatibility
llvm::SmallVector<QualType, 10> types;
for (unsigned i = 0; i < lproto_nargs; i++) {
QualType largtype = lproto->getArgType(i).getUnqualifiedType();
QualType rargtype = rproto->getArgType(i).getUnqualifiedType();
QualType argtype = mergeTypes(largtype, rargtype);
if (argtype.isNull()) return QualType();
types.push_back(argtype);
if (getCanonicalType(argtype) != getCanonicalType(largtype))
allLTypes = false;
if (getCanonicalType(argtype) != getCanonicalType(rargtype))
allRTypes = false;
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
}
if (allLTypes) return lhs;
if (allRTypes) return rhs;
return getFunctionType(retType, types.begin(), types.size(),
lproto->isVariadic());
}
if (lproto) allRTypes = false;
if (rproto) allLTypes = false;
const FunctionTypeProto *proto = lproto ? lproto : rproto;
if (proto) {
if (proto->isVariadic()) return QualType();
// Check that the types are compatible with the types that
// would result from default argument promotions (C99 6.7.5.3p15).
// The only types actually affected are promotable integer
// types and floats, which would be passed as a different
// type depending on whether the prototype is visible.
unsigned proto_nargs = proto->getNumArgs();
for (unsigned i = 0; i < proto_nargs; ++i) {
QualType argTy = proto->getArgType(i);
if (argTy->isPromotableIntegerType() ||
getCanonicalType(argTy).getUnqualifiedType() == FloatTy)
return QualType();
}
if (allLTypes) return lhs;
if (allRTypes) return rhs;
return getFunctionType(retType, proto->arg_type_begin(),
proto->getNumArgs(), lproto->isVariadic());
}
if (allLTypes) return lhs;
if (allRTypes) return rhs;
return getFunctionTypeNoProto(retType);
}
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
// C++ [expr]: If an expression initially has the type "reference to T", the
// type is adjusted to "T" prior to any further analysis, the expression
// designates the object or function denoted by the reference, and the