llvm-project/clang/lib/AST/ASTContext.cpp
Chris Lattner e0ea37ace7 move sorting of qualifying protocols from the parser into
sema.  This allows clients of the parser to have the unmolested 
list if desired, and guarantees that noone can create an
ObjCQualifiedInterfaceType with an unsorted list.

llvm-svn: 49310
2008-04-07 04:56:42 +00:00

1916 lines
70 KiB
C++

//===--- ASTContext.cpp - Context to hold long-lived AST nodes ------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the ASTContext interface.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/Serialize.h"
#include "llvm/Bitcode/Deserialize.h"
using namespace clang;
enum FloatingRank {
FloatRank, DoubleRank, LongDoubleRank
};
ASTContext::~ASTContext() {
// Deallocate all the types.
while (!Types.empty()) {
if (FunctionTypeProto *FT = dyn_cast<FunctionTypeProto>(Types.back())) {
// Destroy the object, but don't call delete. These are malloc'd.
FT->~FunctionTypeProto();
free(FT);
} else {
delete Types.back();
}
Types.pop_back();
}
}
void ASTContext::PrintStats() const {
fprintf(stderr, "*** AST Context Stats:\n");
fprintf(stderr, " %d types total.\n", (int)Types.size());
unsigned NumBuiltin = 0, NumPointer = 0, NumArray = 0, NumFunctionP = 0;
unsigned NumVector = 0, NumComplex = 0;
unsigned NumFunctionNP = 0, NumTypeName = 0, NumTagged = 0, NumReference = 0;
unsigned NumTagStruct = 0, NumTagUnion = 0, NumTagEnum = 0, NumTagClass = 0;
unsigned NumObjCInterfaces = 0, NumObjCQualifiedInterfaces = 0;
unsigned NumObjCQualifiedIds = 0;
for (unsigned i = 0, e = Types.size(); i != e; ++i) {
Type *T = Types[i];
if (isa<BuiltinType>(T))
++NumBuiltin;
else if (isa<PointerType>(T))
++NumPointer;
else if (isa<ReferenceType>(T))
++NumReference;
else if (isa<ComplexType>(T))
++NumComplex;
else if (isa<ArrayType>(T))
++NumArray;
else if (isa<VectorType>(T))
++NumVector;
else if (isa<FunctionTypeNoProto>(T))
++NumFunctionNP;
else if (isa<FunctionTypeProto>(T))
++NumFunctionP;
else if (isa<TypedefType>(T))
++NumTypeName;
else if (TagType *TT = dyn_cast<TagType>(T)) {
++NumTagged;
switch (TT->getDecl()->getKind()) {
default: assert(0 && "Unknown tagged type!");
case Decl::Struct: ++NumTagStruct; break;
case Decl::Union: ++NumTagUnion; break;
case Decl::Class: ++NumTagClass; break;
case Decl::Enum: ++NumTagEnum; break;
}
} else if (isa<ObjCInterfaceType>(T))
++NumObjCInterfaces;
else if (isa<ObjCQualifiedInterfaceType>(T))
++NumObjCQualifiedInterfaces;
else if (isa<ObjCQualifiedIdType>(T))
++NumObjCQualifiedIds;
else {
QualType(T, 0).dump();
assert(0 && "Unknown type!");
}
}
fprintf(stderr, " %d builtin types\n", NumBuiltin);
fprintf(stderr, " %d pointer types\n", NumPointer);
fprintf(stderr, " %d reference types\n", NumReference);
fprintf(stderr, " %d complex types\n", NumComplex);
fprintf(stderr, " %d array types\n", NumArray);
fprintf(stderr, " %d vector types\n", NumVector);
fprintf(stderr, " %d function types with proto\n", NumFunctionP);
fprintf(stderr, " %d function types with no proto\n", NumFunctionNP);
fprintf(stderr, " %d typename (typedef) types\n", NumTypeName);
fprintf(stderr, " %d tagged types\n", NumTagged);
fprintf(stderr, " %d struct types\n", NumTagStruct);
fprintf(stderr, " %d union types\n", NumTagUnion);
fprintf(stderr, " %d class types\n", NumTagClass);
fprintf(stderr, " %d enum types\n", NumTagEnum);
fprintf(stderr, " %d interface types\n", NumObjCInterfaces);
fprintf(stderr, " %d protocol qualified interface types\n",
NumObjCQualifiedInterfaces);
fprintf(stderr, " %d protocol qualified id types\n",
NumObjCQualifiedIds);
fprintf(stderr, "Total bytes = %d\n", int(NumBuiltin*sizeof(BuiltinType)+
NumPointer*sizeof(PointerType)+NumArray*sizeof(ArrayType)+
NumComplex*sizeof(ComplexType)+NumVector*sizeof(VectorType)+
NumFunctionP*sizeof(FunctionTypeProto)+
NumFunctionNP*sizeof(FunctionTypeNoProto)+
NumTypeName*sizeof(TypedefType)+NumTagged*sizeof(TagType)));
}
void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) {
Types.push_back((R = QualType(new BuiltinType(K),0)).getTypePtr());
}
void ASTContext::InitBuiltinTypes() {
assert(VoidTy.isNull() && "Context reinitialized?");
// C99 6.2.5p19.
InitBuiltinType(VoidTy, BuiltinType::Void);
// C99 6.2.5p2.
InitBuiltinType(BoolTy, BuiltinType::Bool);
// C99 6.2.5p3.
if (Target.isCharSigned())
InitBuiltinType(CharTy, BuiltinType::Char_S);
else
InitBuiltinType(CharTy, BuiltinType::Char_U);
// C99 6.2.5p4.
InitBuiltinType(SignedCharTy, BuiltinType::SChar);
InitBuiltinType(ShortTy, BuiltinType::Short);
InitBuiltinType(IntTy, BuiltinType::Int);
InitBuiltinType(LongTy, BuiltinType::Long);
InitBuiltinType(LongLongTy, BuiltinType::LongLong);
// C99 6.2.5p6.
InitBuiltinType(UnsignedCharTy, BuiltinType::UChar);
InitBuiltinType(UnsignedShortTy, BuiltinType::UShort);
InitBuiltinType(UnsignedIntTy, BuiltinType::UInt);
InitBuiltinType(UnsignedLongTy, BuiltinType::ULong);
InitBuiltinType(UnsignedLongLongTy, BuiltinType::ULongLong);
// C99 6.2.5p10.
InitBuiltinType(FloatTy, BuiltinType::Float);
InitBuiltinType(DoubleTy, BuiltinType::Double);
InitBuiltinType(LongDoubleTy, BuiltinType::LongDouble);
// C99 6.2.5p11.
FloatComplexTy = getComplexType(FloatTy);
DoubleComplexTy = getComplexType(DoubleTy);
LongDoubleComplexTy = getComplexType(LongDoubleTy);
BuiltinVaListType = QualType();
ObjCIdType = QualType();
IdStructType = 0;
ObjCClassType = QualType();
ClassStructType = 0;
ObjCConstantStringType = QualType();
// void * type
VoidPtrTy = getPointerType(VoidTy);
}
//===----------------------------------------------------------------------===//
// Type Sizing and Analysis
//===----------------------------------------------------------------------===//
/// getTypeSize - Return the size of the specified type, in bits. This method
/// does not work on incomplete types.
std::pair<uint64_t, unsigned>
ASTContext::getTypeInfo(QualType T) {
T = getCanonicalType(T);
uint64_t Width;
unsigned Align;
switch (T->getTypeClass()) {
case Type::TypeName: assert(0 && "Not a canonical type!");
case Type::FunctionNoProto:
case Type::FunctionProto:
default:
assert(0 && "Incomplete types have no size!");
case Type::VariableArray:
assert(0 && "VLAs not implemented yet!");
case Type::ConstantArray: {
ConstantArrayType *CAT = cast<ConstantArrayType>(T);
std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(CAT->getElementType());
Width = EltInfo.first*CAT->getSize().getZExtValue();
Align = EltInfo.second;
break;
}
case Type::OCUVector:
case Type::Vector: {
std::pair<uint64_t, unsigned> EltInfo =
getTypeInfo(cast<VectorType>(T)->getElementType());
Width = EltInfo.first*cast<VectorType>(T)->getNumElements();
// FIXME: Vector alignment is not the alignment of its elements.
Align = EltInfo.second;
break;
}
case Type::Builtin:
// FIXME: need to use TargetInfo to derive the target specific sizes. This
// implementation will suffice for play with vector support.
switch (cast<BuiltinType>(T)->getKind()) {
default: assert(0 && "Unknown builtin type!");
case BuiltinType::Void:
assert(0 && "Incomplete types have no size!");
case BuiltinType::Bool:
Width = Target.getBoolWidth();
Align = Target.getBoolAlign();
break;
case BuiltinType::Char_S:
case BuiltinType::Char_U:
case BuiltinType::UChar:
case BuiltinType::SChar:
Width = Target.getCharWidth();
Align = Target.getCharAlign();
break;
case BuiltinType::UShort:
case BuiltinType::Short:
Width = Target.getShortWidth();
Align = Target.getShortAlign();
break;
case BuiltinType::UInt:
case BuiltinType::Int:
Width = Target.getIntWidth();
Align = Target.getIntAlign();
break;
case BuiltinType::ULong:
case BuiltinType::Long:
Width = Target.getLongWidth();
Align = Target.getLongAlign();
break;
case BuiltinType::ULongLong:
case BuiltinType::LongLong:
Width = Target.getLongLongWidth();
Align = Target.getLongLongAlign();
break;
case BuiltinType::Float:
Width = Target.getFloatWidth();
Align = Target.getFloatAlign();
break;
case BuiltinType::Double:
Width = Target.getDoubleWidth();
Align = Target.getDoubleAlign();
break;
case BuiltinType::LongDouble:
Width = Target.getLongDoubleWidth();
Align = Target.getLongDoubleAlign();
break;
}
break;
case Type::ASQual:
// FIXME: Pointers into different addr spaces could have different sizes and
// alignment requirements: getPointerInfo should take an AddrSpace.
return getTypeInfo(QualType(cast<ASQualType>(T)->getBaseType(), 0));
case Type::ObjCQualifiedId:
Width = Target.getPointerWidth(0);
Align = Target.getPointerAlign(0);
break;
case Type::Pointer: {
unsigned AS = cast<PointerType>(T)->getPointeeType().getAddressSpace();
Width = Target.getPointerWidth(AS);
Align = Target.getPointerAlign(AS);
break;
}
case Type::Reference:
// "When applied to a reference or a reference type, the result is the size
// of the referenced type." C++98 5.3.3p2: expr.sizeof.
// FIXME: This is wrong for struct layout: a reference in a struct has
// pointer size.
return getTypeInfo(cast<ReferenceType>(T)->getPointeeType());
case Type::Complex: {
// Complex types have the same alignment as their elements, but twice the
// size.
std::pair<uint64_t, unsigned> EltInfo =
getTypeInfo(cast<ComplexType>(T)->getElementType());
Width = EltInfo.first*2;
Align = EltInfo.second;
break;
}
case Type::Tagged: {
if (EnumType *ET = dyn_cast<EnumType>(cast<TagType>(T)))
return getTypeInfo(ET->getDecl()->getIntegerType());
RecordType *RT = cast<RecordType>(T);
const ASTRecordLayout &Layout = getASTRecordLayout(RT->getDecl());
Width = Layout.getSize();
Align = Layout.getAlignment();
break;
}
}
assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2");
return std::make_pair(Width, Align);
}
/// getASTRecordLayout - Get or compute information about the layout of the
/// specified record (struct/union/class), which indicates its size and field
/// position information.
const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
assert(D->isDefinition() && "Cannot get layout of forward declarations!");
// Look up this layout, if already laid out, return what we have.
const ASTRecordLayout *&Entry = ASTRecordLayouts[D];
if (Entry) return *Entry;
// Allocate and assign into ASTRecordLayouts here. The "Entry" reference can
// be invalidated (dangle) if the ASTRecordLayouts hashtable is inserted into.
ASTRecordLayout *NewEntry = new ASTRecordLayout();
Entry = NewEntry;
uint64_t *FieldOffsets = new uint64_t[D->getNumMembers()];
uint64_t RecordSize = 0;
unsigned RecordAlign = 8; // Default alignment = 1 byte = 8 bits.
if (D->getKind() != Decl::Union) {
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
RecordAlign = std::max(RecordAlign, AA->getAlignment());
bool StructIsPacked = D->getAttr<PackedAttr>();
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) {
const FieldDecl *FD = D->getMember(i);
bool FieldIsPacked = StructIsPacked || FD->getAttr<PackedAttr>();
uint64_t FieldSize;
unsigned FieldAlign;
if (const Expr *BitWidthExpr = FD->getBitWidth()) {
llvm::APSInt I(32);
bool BitWidthIsICE =
BitWidthExpr->isIntegerConstantExpr(I, *this);
assert (BitWidthIsICE && "Invalid BitField size expression");
FieldSize = I.getZExtValue();
std::pair<uint64_t, unsigned> TypeInfo = getTypeInfo(FD->getType());
uint64_t TypeSize = TypeInfo.first;
if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>())
FieldAlign = AA->getAlignment();
else if (FieldIsPacked)
FieldAlign = 8;
else {
// FIXME: This is X86 specific, use 32-bit alignment for long long.
if (FD->getType()->isIntegerType() && TypeInfo.second > 32)
FieldAlign = 32;
else
FieldAlign = TypeInfo.second;
}
// Check if we need to add padding to give the field the correct
// alignment.
if (RecordSize % FieldAlign + FieldSize > TypeSize)
RecordSize = (RecordSize+FieldAlign-1) & ~(FieldAlign-1);
} else {
if (FD->getType()->isIncompleteType()) {
// This must be a flexible array member; we can't directly
// query getTypeInfo about these, so we figure it out here.
// Flexible array members don't have any size, but they
// have to be aligned appropriately for their element type.
if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>())
FieldAlign = AA->getAlignment();
else if (FieldIsPacked)
FieldAlign = 8;
else {
const ArrayType* ATy = FD->getType()->getAsArrayType();
FieldAlign = getTypeAlign(ATy->getElementType());
}
FieldSize = 0;
} else {
std::pair<uint64_t, unsigned> FieldInfo = getTypeInfo(FD->getType());
FieldSize = FieldInfo.first;
if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>())
FieldAlign = AA->getAlignment();
else if (FieldIsPacked)
FieldAlign = 8;
else
FieldAlign = FieldInfo.second;
}
// Round up the current record size to the field's alignment boundary.
RecordSize = (RecordSize+FieldAlign-1) & ~(FieldAlign-1);
}
// Place this field at the current location.
FieldOffsets[i] = RecordSize;
// Reserve space for this field.
RecordSize += FieldSize;
// Remember max struct/class alignment.
RecordAlign = std::max(RecordAlign, FieldAlign);
}
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
RecordSize = (RecordSize+RecordAlign-1) & ~(RecordAlign-1);
} else {
// Union layout just puts each member at the start of the record.
for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) {
const FieldDecl *FD = D->getMember(i);
std::pair<uint64_t, unsigned> FieldInfo = getTypeInfo(FD->getType());
uint64_t FieldSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
// FIXME: This is X86 specific, use 32-bit alignment for long long.
if (FD->getType()->isIntegerType() && FieldAlign > 32)
FieldAlign = 32;
// Round up the current record size to the field's alignment boundary.
RecordSize = std::max(RecordSize, FieldSize);
// Place this field at the start of the record.
FieldOffsets[i] = 0;
// Remember max struct/class alignment.
RecordAlign = std::max(RecordAlign, FieldAlign);
}
}
NewEntry->SetLayout(RecordSize, RecordAlign, FieldOffsets);
return *NewEntry;
}
//===----------------------------------------------------------------------===//
// Type creation/memoization methods
//===----------------------------------------------------------------------===//
QualType ASTContext::getASQualType(QualType T, unsigned AddressSpace) {
QualType CanT = getCanonicalType(T);
if (CanT.getAddressSpace() == AddressSpace)
return T;
// Type's cannot have multiple ASQuals, therefore we know we only have to deal
// with CVR qualifiers from here on out.
assert(CanT.getAddressSpace() == 0 &&
"Type is already address space qualified");
// Check if we've already instantiated an address space qual'd type of this
// type.
llvm::FoldingSetNodeID ID;
ASQualType::Profile(ID, T.getTypePtr(), AddressSpace);
void *InsertPos = 0;
if (ASQualType *ASQy = ASQualTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(ASQy, 0);
// If the base type isn't canonical, this won't be a canonical type either,
// so fill in the canonical type field.
QualType Canonical;
if (!T->isCanonical()) {
Canonical = getASQualType(CanT, AddressSpace);
// Get the new insert position for the node we care about.
ASQualType *NewIP = ASQualTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!");
}
ASQualType *New = new ASQualType(T.getTypePtr(), Canonical, AddressSpace);
ASQualTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, T.getCVRQualifiers());
}
/// getComplexType - Return the uniqued reference to the type for a complex
/// number with the specified element type.
QualType ASTContext::getComplexType(QualType T) {
// Unique pointers, to guarantee there is only one pointer of a particular
// structure.
llvm::FoldingSetNodeID ID;
ComplexType::Profile(ID, T);
void *InsertPos = 0;
if (ComplexType *CT = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(CT, 0);
// If the pointee type isn't canonical, this won't be a canonical type either,
// so fill in the canonical type field.
QualType Canonical;
if (!T->isCanonical()) {
Canonical = getComplexType(getCanonicalType(T));
// Get the new insert position for the node we care about.
ComplexType *NewIP = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!");
}
ComplexType *New = new ComplexType(T, Canonical);
Types.push_back(New);
ComplexTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
}
/// getPointerType - Return the uniqued reference to the type for a pointer to
/// the specified type.
QualType ASTContext::getPointerType(QualType T) {
// Unique pointers, to guarantee there is only one pointer of a particular
// structure.
llvm::FoldingSetNodeID ID;
PointerType::Profile(ID, T);
void *InsertPos = 0;
if (PointerType *PT = PointerTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(PT, 0);
// If the pointee type isn't canonical, this won't be a canonical type either,
// so fill in the canonical type field.
QualType Canonical;
if (!T->isCanonical()) {
Canonical = getPointerType(getCanonicalType(T));
// Get the new insert position for the node we care about.
PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!");
}
PointerType *New = new PointerType(T, Canonical);
Types.push_back(New);
PointerTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
}
/// getReferenceType - Return the uniqued reference to the type for a reference
/// to the specified type.
QualType ASTContext::getReferenceType(QualType T) {
// Unique pointers, to guarantee there is only one pointer of a particular
// structure.
llvm::FoldingSetNodeID ID;
ReferenceType::Profile(ID, T);
void *InsertPos = 0;
if (ReferenceType *RT = ReferenceTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(RT, 0);
// If the referencee type isn't canonical, this won't be a canonical type
// either, so fill in the canonical type field.
QualType Canonical;
if (!T->isCanonical()) {
Canonical = getReferenceType(getCanonicalType(T));
// Get the new insert position for the node we care about.
ReferenceType *NewIP = ReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!");
}
ReferenceType *New = new ReferenceType(T, Canonical);
Types.push_back(New);
ReferenceTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
}
/// getConstantArrayType - Return the unique reference to the type for an
/// array of the specified element type.
QualType ASTContext::getConstantArrayType(QualType EltTy,
const llvm::APInt &ArySize,
ArrayType::ArraySizeModifier ASM,
unsigned EltTypeQuals) {
llvm::FoldingSetNodeID ID;
ConstantArrayType::Profile(ID, EltTy, ArySize);
void *InsertPos = 0;
if (ConstantArrayType *ATP =
ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(ATP, 0);
// If the element type isn't canonical, this won't be a canonical type either,
// so fill in the canonical type field.
QualType Canonical;
if (!EltTy->isCanonical()) {
Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize,
ASM, EltTypeQuals);
// Get the new insert position for the node we care about.
ConstantArrayType *NewIP =
ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!");
}
ConstantArrayType *New = new ConstantArrayType(EltTy, Canonical, ArySize,
ASM, EltTypeQuals);
ConstantArrayTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
}
/// getVariableArrayType - Returns a non-unique reference to the type for a
/// variable array of the specified element type.
QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts,
ArrayType::ArraySizeModifier ASM,
unsigned EltTypeQuals) {
// Since we don't unique expressions, it isn't possible to unique VLA's
// that have an expression provided for their size.
VariableArrayType *New = new VariableArrayType(EltTy, QualType(), NumElts,
ASM, EltTypeQuals);
VariableArrayTypes.push_back(New);
Types.push_back(New);
return QualType(New, 0);
}
QualType ASTContext::getIncompleteArrayType(QualType EltTy,
ArrayType::ArraySizeModifier ASM,
unsigned EltTypeQuals) {
llvm::FoldingSetNodeID ID;
IncompleteArrayType::Profile(ID, EltTy);
void *InsertPos = 0;
if (IncompleteArrayType *ATP =
IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(ATP, 0);
// If the element type isn't canonical, this won't be a canonical type
// either, so fill in the canonical type field.
QualType Canonical;
if (!EltTy->isCanonical()) {
Canonical = getIncompleteArrayType(getCanonicalType(EltTy),
ASM, EltTypeQuals);
// Get the new insert position for the node we care about.
IncompleteArrayType *NewIP =
IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!");
}
IncompleteArrayType *New = new IncompleteArrayType(EltTy, Canonical,
ASM, EltTypeQuals);
IncompleteArrayTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
}
/// getVectorType - Return the unique reference to a vector type of
/// the specified element type and size. VectorType must be a built-in type.
QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) {
BuiltinType *baseType;
baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr());
assert(baseType != 0 && "getVectorType(): Expecting a built-in type");
// Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID;
VectorType::Profile(ID, vecType, NumElts, Type::Vector);
void *InsertPos = 0;
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(VTP, 0);
// If the element type isn't canonical, this won't be a canonical type either,
// so fill in the canonical type field.
QualType Canonical;
if (!vecType->isCanonical()) {
Canonical = getVectorType(getCanonicalType(vecType), NumElts);
// Get the new insert position for the node we care about.
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!");
}
VectorType *New = new VectorType(vecType, NumElts, Canonical);
VectorTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
}
/// getOCUVectorType - Return the unique reference to an OCU vector type of
/// the specified element type and size. VectorType must be a built-in type.
QualType ASTContext::getOCUVectorType(QualType vecType, unsigned NumElts) {
BuiltinType *baseType;
baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr());
assert(baseType != 0 && "getOCUVectorType(): Expecting a built-in type");
// Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID;
VectorType::Profile(ID, vecType, NumElts, Type::OCUVector);
void *InsertPos = 0;
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(VTP, 0);
// If the element type isn't canonical, this won't be a canonical type either,
// so fill in the canonical type field.
QualType Canonical;
if (!vecType->isCanonical()) {
Canonical = getOCUVectorType(getCanonicalType(vecType), NumElts);
// Get the new insert position for the node we care about.
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!");
}
OCUVectorType *New = new OCUVectorType(vecType, NumElts, Canonical);
VectorTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
}
/// getFunctionTypeNoProto - Return a K&R style C function type like 'int()'.
///
QualType ASTContext::getFunctionTypeNoProto(QualType ResultTy) {
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
FunctionTypeNoProto::Profile(ID, ResultTy);
void *InsertPos = 0;
if (FunctionTypeNoProto *FT =
FunctionTypeNoProtos.FindNodeOrInsertPos(ID, InsertPos))
return QualType(FT, 0);
QualType Canonical;
if (!ResultTy->isCanonical()) {
Canonical = getFunctionTypeNoProto(getCanonicalType(ResultTy));
// Get the new insert position for the node we care about.
FunctionTypeNoProto *NewIP =
FunctionTypeNoProtos.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!");
}
FunctionTypeNoProto *New = new FunctionTypeNoProto(ResultTy, Canonical);
Types.push_back(New);
FunctionTypeNoProtos.InsertNode(New, InsertPos);
return QualType(New, 0);
}
/// getFunctionType - Return a normal function type with a typed argument
/// list. isVariadic indicates whether the argument list includes '...'.
QualType ASTContext::getFunctionType(QualType ResultTy, QualType *ArgArray,
unsigned NumArgs, bool isVariadic) {
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
FunctionTypeProto::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic);
void *InsertPos = 0;
if (FunctionTypeProto *FTP =
FunctionTypeProtos.FindNodeOrInsertPos(ID, InsertPos))
return QualType(FTP, 0);
// Determine whether the type being created is already canonical or not.
bool isCanonical = ResultTy->isCanonical();
for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
if (!ArgArray[i]->isCanonical())
isCanonical = false;
// If this type isn't canonical, get the canonical version of it.
QualType Canonical;
if (!isCanonical) {
llvm::SmallVector<QualType, 16> CanonicalArgs;
CanonicalArgs.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
CanonicalArgs.push_back(getCanonicalType(ArgArray[i]));
Canonical = getFunctionType(getCanonicalType(ResultTy),
&CanonicalArgs[0], NumArgs,
isVariadic);
// Get the new insert position for the node we care about.
FunctionTypeProto *NewIP =
FunctionTypeProtos.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!");
}
// FunctionTypeProto objects are not allocated with new because they have a
// variable size array (for parameter types) at the end of them.
FunctionTypeProto *FTP =
(FunctionTypeProto*)malloc(sizeof(FunctionTypeProto) +
NumArgs*sizeof(QualType));
new (FTP) FunctionTypeProto(ResultTy, ArgArray, NumArgs, isVariadic,
Canonical);
Types.push_back(FTP);
FunctionTypeProtos.InsertNode(FTP, InsertPos);
return QualType(FTP, 0);
}
/// getTypedefType - Return the unique reference to the type for the
/// specified typename decl.
QualType ASTContext::getTypedefType(TypedefDecl *Decl) {
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
QualType Canonical = getCanonicalType(Decl->getUnderlyingType());
Decl->TypeForDecl = new TypedefType(Type::TypeName, Decl, Canonical);
Types.push_back(Decl->TypeForDecl);
return QualType(Decl->TypeForDecl, 0);
}
/// getObjCInterfaceType - Return the unique reference to the type for the
/// specified ObjC interface decl.
QualType ASTContext::getObjCInterfaceType(ObjCInterfaceDecl *Decl) {
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
Decl->TypeForDecl = new ObjCInterfaceType(Type::ObjCInterface, Decl);
Types.push_back(Decl->TypeForDecl);
return QualType(Decl->TypeForDecl, 0);
}
/// CmpProtocolNames - Comparison predicate for sorting protocols
/// alphabetically.
static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
const ObjCProtocolDecl *RHS) {
return strcmp(LHS->getName(), RHS->getName()) < 0;
}
static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols,
unsigned &NumProtocols) {
ObjCProtocolDecl **ProtocolsEnd = Protocols+NumProtocols;
// 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, 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.
QualType ASTContext::getObjCQualifiedIdType(QualType idType,
ObjCProtocolDecl **Protocols,
unsigned NumProtocols) {
// Sort the protocol list alphabetically to canonicalize it.
SortAndUniqueProtocols(Protocols, NumProtocols);
llvm::FoldingSetNodeID ID;
ObjCQualifiedIdType::Profile(ID, Protocols, NumProtocols);
void *InsertPos = 0;
if (ObjCQualifiedIdType *QT =
ObjCQualifiedIdTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(QT, 0);
// No Match;
QualType Canonical;
if (!idType->isCanonical()) {
Canonical = getObjCQualifiedIdType(getCanonicalType(idType),
Protocols, NumProtocols);
ObjCQualifiedIdType *NewQT =
ObjCQualifiedIdTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewQT == 0 && "Shouldn't be in the map!");
}
ObjCQualifiedIdType *QType =
new ObjCQualifiedIdType(Canonical, Protocols, NumProtocols);
Types.push_back(QType);
ObjCQualifiedIdTypes.InsertNode(QType, InsertPos);
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).
QualType ASTContext::getTypeOfExpr(Expr *tofExpr) {
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).
QualType ASTContext::getTypeOfType(QualType tofType) {
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.
QualType ASTContext::getTagDeclType(TagDecl *Decl) {
assert (Decl);
// The decl stores the type cache.
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
TagType* T = new TagType(Decl, QualType());
Types.push_back(T);
Decl->TypeForDecl = T;
return QualType(T, 0);
}
/// 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
/// needs to agree with the definition in <stddef.h>.
QualType ASTContext::getSizeType() const {
// 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 {
// On Darwin, wchar_t is defined as a "int".
// FIXME: should derive from "Target".
return IntTy;
}
/// 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();
return QualType(CanType.getTypePtr(),
T.getCVRQualifiers() | CanType.getCVRQualifiers());
}
/// 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) {
// Handle the common case where typedefs are not involved directly.
QualType EltTy;
unsigned ArrayQuals = 0;
unsigned PointerQuals = 0;
if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
// Since T "isa" an array type, it could not have had an address space
// qualifier, just CVR qualifiers. The properly qualified element pointer
// gets the union of the CVR qualifiers from the element and the array, and
// keeps any address space qualifier on the element type if present.
EltTy = AT->getElementType();
ArrayQuals = Ty.getCVRQualifiers();
PointerQuals = AT->getIndexTypeQualifier();
} else {
// Otherwise, we have an ASQualType or a typedef, etc. Make sure we don't
// lose qualifiers when dealing with typedefs. Example:
// typedef int arr[10];
// void test2() {
// const arr b;
// b[4] = 1;
// }
//
// The decayed type of b is "const int*" even though the element type of the
// array is "int".
QualType CanTy = getCanonicalType(Ty);
const ArrayType *PrettyArrayType = Ty->getAsArrayType();
assert(PrettyArrayType && "Not an array type!");
// Get the element type with 'getAsArrayType' so that we don't lose any
// typedefs in the element type of the array.
EltTy = PrettyArrayType->getElementType();
// If the array was address-space qualifier, make sure to ASQual the element
// type. We can just grab the address space from the canonical type.
if (unsigned AS = CanTy.getAddressSpace())
EltTy = getASQualType(EltTy, AS);
// To properly handle [multiple levels of] typedefs, typeof's etc, we take
// the CVR qualifiers directly from the canonical type, which is guaranteed
// to have the full set unioned together.
ArrayQuals = CanTy.getCVRQualifiers();
PointerQuals = PrettyArrayType->getIndexTypeQualifier();
}
// 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."
EltTy = EltTy.getQualifiedType(ArrayQuals | EltTy.getCVRQualifiers());
QualType PtrTy = getPointerType(EltTy);
// int x[restrict 4] -> int *restrict
PtrTy = PtrTy.getQualifiedType(PointerQuals);
return PtrTy;
}
/// 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) {
if (const ComplexType *CT = T->getAsComplexType())
return getFloatingRank(CT->getElementType());
switch (T->getAsBuiltinType()->getKind()) {
default: assert(0 && "getFloatingRank(): not a floating type");
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) {
default: assert(0 && "getFloatingRank(): illegal value for rank");
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)
return 0;
if (LHSR > RHSR)
return 1;
return -1;
}
/// 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;
}
}
/// 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) {
Type *LHSC = getCanonicalType(LHS).getTypePtr();
Type *RHSC = getCanonicalType(RHS).getTypePtr();
if (LHSC == RHSC) return 0;
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, Decl::Struct, NULL, SourceLocation(),
&Idents.get("NSConstantString"), 0);
QualType FieldTypes[4];
// const int *isa;
FieldTypes[0] = getPointerType(IntTy.getQualifiedType(QualType::Const));
// int flags;
FieldTypes[1] = IntTy;
// const char *str;
FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const));
// long length;
FieldTypes[3] = LongTy;
// Create fields
FieldDecl *FieldDecls[4];
for (unsigned i = 0; i < 4; ++i)
FieldDecls[i] = FieldDecl::Create(*this, SourceLocation(), 0,
FieldTypes[i]);
CFConstantStringTypeDecl->defineBody(FieldDecls, 4);
}
return getTagDeclType(CFConstantStringTypeDecl);
}
// This returns true if a type has been typedefed to BOOL:
// typedef <type> BOOL;
static bool isTypeTypedefedAsBOOL(QualType T) {
if (const TypedefType *TT = dyn_cast<TypedefType>(T))
return !strcmp(TT->getDecl()->getName(), "BOOL");
return false;
}
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
/// purpose.
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
/// declaration.
void ASTContext::getObjCEncodingForMethodDecl(ObjCMethodDecl *Decl,
std::string& S)
{
// Encode type qualifer, 'in', 'inout', etc. for the return type.
getObjCEncodingForTypeQualifier(Decl->getObjCDeclQualifier(), S);
// Encode result type.
getObjCEncodingForType(Decl->getResultType(), S, EncodingRecordTypes);
// 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();
// Process argument qualifiers for user supplied arguments; such as,
// 'in', 'inout', etc.
getObjCEncodingForTypeQualifier(
Decl->getParamDecl(i)->getObjCDeclQualifier(), S);
getObjCEncodingForType(PType, S, EncodingRecordTypes);
S += llvm::utostr(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
}
void ASTContext::getObjCEncodingForType(QualType T, std::string& S,
llvm::SmallVector<const RecordType *, 8> &ERType) const
{
// FIXME: This currently doesn't encode:
// @ An object (whether statically typed or typed id)
// # A class object (Class)
// : A method selector (SEL)
// {name=type...} A structure
// (name=type...) A union
// bnum A bit field of num bits
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::Char_U:
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::Char_S:
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;
}
S += encoding;
}
else if (T->isObjCQualifiedIdType()) {
// Treat id<P...> same as 'id' for encoding purposes.
return getObjCEncodingForType(getObjCIdType(), S, ERType);
}
else if (const PointerType *PT = T->getAsPointerType()) {
QualType PointeeTy = PT->getPointeeType();
if (isObjCIdType(PointeeTy) || PointeeTy->isObjCInterfaceType()) {
S += '@';
return;
} else if (isObjCClassType(PointeeTy)) {
S += '#';
return;
} else if (isObjCSelType(PointeeTy)) {
S += ':';
return;
}
if (PointeeTy->isCharType()) {
// char pointer types should be encoded as '*' unless it is a
// type that has been typedef'd to 'BOOL'.
if (!isTypeTypedefedAsBOOL(PointeeTy)) {
S += '*';
return;
}
}
S += '^';
getObjCEncodingForType(PT->getPointeeType(), S, ERType);
} else if (const ArrayType *AT = T->getAsArrayType()) {
S += '[';
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
S += llvm::utostr(CAT->getSize().getZExtValue());
else
assert(0 && "Unhandled array type!");
getObjCEncodingForType(AT->getElementType(), S, ERType);
S += ']';
} else if (T->getAsFunctionType()) {
S += '?';
} else if (const RecordType *RTy = T->getAsRecordType()) {
RecordDecl *RDecl= RTy->getDecl();
S += '{';
S += RDecl->getName();
bool found = false;
for (unsigned i = 0, e = ERType.size(); i != e; ++i)
if (ERType[i] == RTy) {
found = true;
break;
}
if (!found) {
ERType.push_back(RTy);
S += '=';
for (int i = 0; i < RDecl->getNumMembers(); i++) {
FieldDecl *field = RDecl->getMember(i);
getObjCEncodingForType(field->getType(), S, ERType);
}
assert(ERType.back() == RTy && "Record Type stack mismatch.");
ERType.pop_back();
}
S += '}';
} else if (T->isEnumeralType()) {
S += 'i';
} else
assert(0 && "@encode for type not implemented!");
}
void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
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)
{
assert(ObjCIdType.isNull() && "'id' type already set!");
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)
{
assert(ObjCSelType.isNull() && "'SEL' type already set!");
ObjCSelType = getTypedefType(TD);
// 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)
{
assert(ObjCProtoType.isNull() && "'Protocol' type already set!");
ObjCProtoType = QT;
}
void ASTContext::setObjCClassType(TypedefDecl *TD)
{
assert(ObjCClassType.isNull() && "'Class' type already set!");
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() &&
"'NSConstantString' type already set!");
ObjCConstantStringType = getObjCInterfaceType(Decl);
}
bool ASTContext::builtinTypesAreCompatible(QualType lhs, QualType rhs) {
const BuiltinType *lBuiltin = lhs->getAsBuiltinType();
const BuiltinType *rBuiltin = rhs->getAsBuiltinType();
return lBuiltin->getKind() == rBuiltin->getKind();
}
/// objcTypesAreCompatible - This routine is called when two types
/// are of different class; one is interface type or is
/// a qualified interface type and the other type is of a different class.
/// Example, II or II<P>.
bool ASTContext::objcTypesAreCompatible(QualType LHS, QualType RHS) {
// ID is compatible with all interface types.
if (LHS->isObjCInterfaceType() && isObjCIdType(RHS))
return true;
else if (isObjCIdType(LHS) && RHS->isObjCInterfaceType())
return true;
// II is compatible with II<P> if the base is the same. Otherwise, no two
// qualified interface types are the same.
if (const ObjCInterfaceType *LHSIT = LHS->getAsObjCInterfaceType()) {
if (const ObjCInterfaceType *RHSIT = RHS->getAsObjCInterfaceType()) {
// If the base decls match and one is a qualified interface and one isn't,
// then they are compatible.
return LHSIT->getDecl() == RHSIT->getDecl() &&
isa<ObjCQualifiedInterfaceType>(LHSIT) !=
isa<ObjCQualifiedInterfaceType>(RHSIT);
}
}
return false;
}
/// areCompatObjCQualInterfaces - Return true if the two qualified interface
/// types are compatible for assignment from RHS to LHS.
///
static bool
areCompatObjCQualInterfaces(const ObjCQualifiedInterfaceType *LHS,
const ObjCQualifiedInterfaceType *RHS) {
// Verify that the base decls are compatible: the RHS must be a subclass of
// the LHS.
if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
return false;
// All protocols in LHS must have a presence in RHS.
for (unsigned i = 0; i != LHS->getNumProtocols(); ++i) {
bool match = false;
ObjCProtocolDecl *lhsProto = LHS->getProtocols(i);
for (unsigned j = 0; j != RHS->getNumProtocols(); ++j) {
ObjCProtocolDecl *rhsProto = RHS->getProtocols(j);
if (lhsProto == rhsProto) {
match = true;
break;
}
}
if (!match)
return false;
}
return true;
}
/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the
/// inheritance hierarchy of 'rProto'.
static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
ObjCProtocolDecl *rProto) {
if (lProto == rProto)
return true;
ObjCProtocolDecl** RefPDecl = rProto->getReferencedProtocols();
for (unsigned i = 0; i < rProto->getNumReferencedProtocols(); i++)
if (ProtocolCompatibleWithProtocol(lProto, RefPDecl[i]))
return true;
return false;
}
/// ClassImplementsProtocol - Checks that 'lProto' protocol
/// has been implemented in IDecl class, its super class or categories (if
/// lookupCategory is true).
static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto,
ObjCInterfaceDecl *IDecl,
bool lookupCategory) {
// 1st, look up the class.
ObjCProtocolDecl **protoList = IDecl->getReferencedProtocols();
for (unsigned i = 0; i < IDecl->getNumIntfRefProtocols(); i++) {
if (ProtocolCompatibleWithProtocol(lProto, protoList[i]))
return true;
}
// 2nd, look up the category.
if (lookupCategory)
for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl;
CDecl = CDecl->getNextClassCategory()) {
protoList = CDecl->getReferencedProtocols();
for (unsigned i = 0; i < CDecl->getNumReferencedProtocols(); i++) {
if (ProtocolCompatibleWithProtocol(lProto, protoList[i]))
return true;
}
}
// 3rd, look up the super class(s)
if (IDecl->getSuperClass())
return
ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory);
return false;
}
/// ObjCQualifiedIdTypesAreCompatible - Compares two types, at least
/// one of which is a protocol qualified 'id' type. When 'compare'
/// is true it is for comparison; when false, for assignment/initialization.
bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs,
QualType rhs,
bool compare) {
// match id<P..> with an 'id' type in all cases.
if (const PointerType *PT = lhs->getAsPointerType()) {
QualType PointeeTy = PT->getPointeeType();
if (isObjCIdType(PointeeTy) || PointeeTy->isVoidType())
return true;
} else if (const PointerType *PT = rhs->getAsPointerType()) {
QualType PointeeTy = PT->getPointeeType();
if (isObjCIdType(PointeeTy) || PointeeTy->isVoidType())
return true;
}
ObjCQualifiedInterfaceType *lhsQI = 0;
ObjCQualifiedInterfaceType *rhsQI = 0;
ObjCInterfaceDecl *lhsID = 0;
ObjCInterfaceDecl *rhsID = 0;
ObjCQualifiedIdType *lhsQID = dyn_cast<ObjCQualifiedIdType>(lhs);
ObjCQualifiedIdType *rhsQID = dyn_cast<ObjCQualifiedIdType>(rhs);
if (lhsQID) {
if (!rhsQID && rhs->getTypeClass() == Type::Pointer) {
QualType rtype =
cast<PointerType>(rhs.getCanonicalType())->getPointeeType();
rhsQI =
dyn_cast<ObjCQualifiedInterfaceType>(
rtype.getCanonicalType().getTypePtr());
if (!rhsQI) {
ObjCInterfaceType *IT = dyn_cast<ObjCInterfaceType>(
rtype.getCanonicalType().getTypePtr());
if (IT)
rhsID = IT->getDecl();
}
}
if (!rhsQI && !rhsQID && !rhsID)
return false;
ObjCQualifiedIdType::qual_iterator RHSProtoI, RHSProtoE;
if (rhsQI) {
RHSProtoI = rhsQI->qual_begin();
RHSProtoE = rhsQI->qual_end();
} else if (rhsQID) {
RHSProtoI = rhsQID->qual_begin();
RHSProtoE = rhsQID->qual_end();
}
for (unsigned i =0; i < lhsQID->getNumProtocols(); i++) {
ObjCProtocolDecl *lhsProto = lhsQID->getProtocols(i);
bool match = false;
// when comparing an id<P> on lhs with a static type on rhs,
// see if static class implements all of id's protocols, directly or
// through its super class and categories.
if (rhsID) {
if (ClassImplementsProtocol(lhsProto, rhsID, true))
match = true;
} else {
for (; RHSProtoI != RHSProtoE; ++RHSProtoI) {
ObjCProtocolDecl *rhsProto = *RHSProtoI;
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) {
match = true;
break;
}
}
}
if (!match)
return false;
}
}
else if (rhsQID) {
if (!lhsQID && lhs->getTypeClass() == Type::Pointer) {
QualType ltype =
cast<PointerType>(lhs.getCanonicalType())->getPointeeType();
lhsQI =
dyn_cast<ObjCQualifiedInterfaceType>(
ltype.getCanonicalType().getTypePtr());
if (!lhsQI) {
ObjCInterfaceType *IT = dyn_cast<ObjCInterfaceType>(
ltype.getCanonicalType().getTypePtr());
if (IT)
lhsID = IT->getDecl();
}
}
if (!lhsQI && !lhsQID && !lhsID)
return false;
ObjCQualifiedIdType::qual_iterator LHSProtoI, LHSProtoE;
if (lhsQI) {
LHSProtoI = lhsQI->qual_begin();
LHSProtoE = lhsQI->qual_end();
} else if (lhsQID) {
LHSProtoI = lhsQID->qual_begin();
LHSProtoE = lhsQID->qual_end();
}
bool match = false;
// for static type vs. qualified 'id' type, check that class implements
// one of 'id's protocols.
if (lhsID) {
for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) {
ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j);
if (ClassImplementsProtocol(rhsProto, lhsID, compare)) {
match = true;
break;
}
}
} else {
for (; LHSProtoI != LHSProtoE; ++LHSProtoI) {
match = false;
ObjCProtocolDecl *lhsProto = *LHSProtoI;
for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) {
ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j);
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) {
match = true;
break;
}
}
}
}
if (!match)
return false;
}
return true;
}
bool ASTContext::vectorTypesAreCompatible(QualType lhs, QualType rhs) {
const VectorType *lVector = lhs->getAsVectorType();
const VectorType *rVector = rhs->getAsVectorType();
if ((lVector->getElementType().getCanonicalType() ==
rVector->getElementType().getCanonicalType()) &&
(lVector->getNumElements() == rVector->getNumElements()))
return true;
return false;
}
// C99 6.2.7p1: If both are complete types, then the following additional
// requirements apply...FIXME (handle compatibility across source files).
bool ASTContext::tagTypesAreCompatible(QualType lhs, QualType rhs) {
// "Class" and "id" are compatible built-in structure types.
if (isObjCIdType(lhs) && isObjCClassType(rhs) ||
isObjCClassType(lhs) && isObjCIdType(rhs))
return true;
// Within a translation unit a tag type is
// only compatible with itself.
return lhs.getCanonicalType() == rhs.getCanonicalType();
}
bool ASTContext::pointerTypesAreCompatible(QualType lhs, QualType rhs) {
// C99 6.7.5.1p2: For two pointer types to be compatible, both shall be
// identically qualified and both shall be pointers to compatible types.
if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers() ||
lhs.getAddressSpace() != rhs.getAddressSpace())
return false;
QualType ltype = cast<PointerType>(lhs.getCanonicalType())->getPointeeType();
QualType rtype = cast<PointerType>(rhs.getCanonicalType())->getPointeeType();
return typesAreCompatible(ltype, rtype);
}
// C++ 5.17p6: When the left operand of an assignment operator denotes a
// reference to T, the operation assigns to the object of type T denoted by the
// reference.
bool ASTContext::referenceTypesAreCompatible(QualType lhs, QualType rhs) {
QualType ltype = lhs;
if (lhs->isReferenceType())
ltype = cast<ReferenceType>(lhs.getCanonicalType())->getPointeeType();
QualType rtype = rhs;
if (rhs->isReferenceType())
rtype = cast<ReferenceType>(rhs.getCanonicalType())->getPointeeType();
return typesAreCompatible(ltype, rtype);
}
bool ASTContext::functionTypesAreCompatible(QualType lhs, QualType rhs) {
const FunctionType *lbase = cast<FunctionType>(lhs.getCanonicalType());
const FunctionType *rbase = cast<FunctionType>(rhs.getCanonicalType());
const FunctionTypeProto *lproto = dyn_cast<FunctionTypeProto>(lbase);
const FunctionTypeProto *rproto = dyn_cast<FunctionTypeProto>(rbase);
// first check the return types (common between C99 and K&R).
if (!typesAreCompatible(lbase->getResultType(), rbase->getResultType()))
return false;
if (lproto && rproto) { // two C99 style function prototypes
unsigned lproto_nargs = lproto->getNumArgs();
unsigned rproto_nargs = rproto->getNumArgs();
if (lproto_nargs != rproto_nargs)
return false;
// both prototypes have the same number of arguments.
if ((lproto->isVariadic() && !rproto->isVariadic()) ||
(rproto->isVariadic() && !lproto->isVariadic()))
return false;
// The use of ellipsis agree...now check the argument types.
for (unsigned i = 0; i < lproto_nargs; i++)
// C99 6.7.5.3p15: ...and each parameter declared with qualified type
// is taken as having the unqualified version of it's declared type.
if (!typesAreCompatible(lproto->getArgType(i).getUnqualifiedType(),
rproto->getArgType(i).getUnqualifiedType()))
return false;
return true;
}
if (!lproto && !rproto) // two K&R style function decls, nothing to do.
return true;
// we have a mixture of K&R style with C99 prototypes
const FunctionTypeProto *proto = lproto ? lproto : rproto;
if (proto->isVariadic())
return false;
// FIXME: Each parameter type T in the prototype must be compatible with the
// type resulting from applying the usual argument conversions to T.
return true;
}
bool ASTContext::arrayTypesAreCompatible(QualType lhs, QualType rhs) {
// Compatible arrays must have compatible element types
QualType ltype = lhs->getAsArrayType()->getElementType();
QualType rtype = rhs->getAsArrayType()->getElementType();
if (!typesAreCompatible(ltype, rtype))
return false;
// Compatible arrays must be the same size
if (const ConstantArrayType* LCAT = lhs->getAsConstantArrayType())
if (const ConstantArrayType* RCAT = rhs->getAsConstantArrayType())
return RCAT->getSize() == LCAT->getSize();
return true;
}
/// 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_NC, QualType RHS_NC) {
QualType LHS = LHS_NC.getCanonicalType();
QualType RHS = RHS_NC.getCanonicalType();
// If two types are identical, they are are compatible
if (LHS == RHS)
return true;
if (LHS.getCVRQualifiers() != RHS.getCVRQualifiers() ||
LHS.getAddressSpace() != RHS.getAddressSpace())
return false;
// 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
// expression is an lvalue.
if (ReferenceType *RT = dyn_cast<ReferenceType>(LHS))
LHS = RT->getPointeeType();
if (ReferenceType *RT = dyn_cast<ReferenceType>(RHS))
RHS = RT->getPointeeType();
Type::TypeClass LHSClass = LHS->getTypeClass();
Type::TypeClass RHSClass = RHS->getTypeClass();
// We want to consider the two function types to be the same for these
// comparisons, just force one to the other.
if (LHSClass == Type::FunctionProto) LHSClass = Type::FunctionNoProto;
if (RHSClass == Type::FunctionProto) RHSClass = Type::FunctionNoProto;
// Same as above for arrays
if (LHSClass == Type::VariableArray) LHSClass = Type::ConstantArray;
if (RHSClass == Type::VariableArray) RHSClass = Type::ConstantArray;
if (LHSClass == Type::IncompleteArray) LHSClass = Type::ConstantArray;
if (RHSClass == Type::IncompleteArray) RHSClass = Type::ConstantArray;
// If the canonical type classes don't match...
if (LHSClass != RHSClass) {
// For Objective-C, it is possible for two types to be compatible
// when their classes don't match (when dealing with "id"). If either type
// is an interface, we defer to objcTypesAreCompatible().
if (LHS->isObjCInterfaceType() || RHS->isObjCInterfaceType())
return objcTypesAreCompatible(LHS, RHS);
// C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
// a signed integer type, or an unsigned integer type.
if (LHS->isEnumeralType() && RHS->isIntegralType()) {
EnumDecl* EDecl = cast<EnumType>(LHS)->getDecl();
return EDecl->getIntegerType() == RHS;
}
if (RHS->isEnumeralType() && LHS->isIntegralType()) {
EnumDecl* EDecl = cast<EnumType>(RHS)->getDecl();
return EDecl->getIntegerType() == LHS;
}
return false;
}
// The canonical type classes match.
switch (LHSClass) {
case Type::FunctionProto: assert(0 && "Canonicalized away above");
case Type::Pointer:
return pointerTypesAreCompatible(LHS, RHS);
case Type::ConstantArray:
case Type::VariableArray:
case Type::IncompleteArray:
return arrayTypesAreCompatible(LHS, RHS);
case Type::FunctionNoProto:
return functionTypesAreCompatible(LHS, RHS);
case Type::Tagged: // handle structures, unions
return tagTypesAreCompatible(LHS, RHS);
case Type::Builtin:
return builtinTypesAreCompatible(LHS, RHS);
case Type::ObjCInterface:
// The LHS must be a superclass of the RHS.
return cast<ObjCInterfaceType>(LHS)->getDecl()->isSuperClassOf(
cast<ObjCInterfaceType>(RHS)->getDecl());
case Type::Vector:
case Type::OCUVector:
return vectorTypesAreCompatible(LHS, RHS);
case Type::ObjCQualifiedInterface:
return areCompatObjCQualInterfaces(cast<ObjCQualifiedInterfaceType>(LHS),
cast<ObjCQualifiedInterfaceType>(RHS));
default:
assert(0 && "unexpected type");
}
return true; // should never get here...
}
/// Emit - Serialize an ASTContext object to Bitcode.
void ASTContext::Emit(llvm::Serializer& S) const {
S.EmitRef(SourceMgr);
S.EmitRef(Target);
S.EmitRef(Idents);
S.EmitRef(Selectors);
// Emit the size of the type vector so that we can reserve that size
// when we reconstitute the ASTContext object.
S.EmitInt(Types.size());
for (std::vector<Type*>::const_iterator I=Types.begin(), E=Types.end();
I!=E;++I)
(*I)->Emit(S);
// FIXME: S.EmitOwnedPtr(CFConstantStringTypeDecl);
}
ASTContext* ASTContext::Create(llvm::Deserializer& D) {
SourceManager &SM = D.ReadRef<SourceManager>();
TargetInfo &t = D.ReadRef<TargetInfo>();
IdentifierTable &idents = D.ReadRef<IdentifierTable>();
SelectorTable &sels = D.ReadRef<SelectorTable>();
unsigned size_reserve = D.ReadInt();
ASTContext* A = new ASTContext(SM,t,idents,sels,size_reserve);
for (unsigned i = 0; i < size_reserve; ++i)
Type::Create(*A,i,D);
// FIXME: A->CFConstantStringTypeDecl = D.ReadOwnedPtr<RecordDecl>();
return A;
}