Newer
Older
//===--- ASTContext.cpp - Context to hold long-lived AST nodes ------------===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Chris Lattner and 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/Basic/TargetInfo.h"
Chris Lattner
committed
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
enum FloatingRank {
FloatRank, DoubleRank, LongDoubleRank
};
ASTContext::~ASTContext() {
// Deallocate all the types.
while (!Types.empty()) {
Chris Lattner
committed
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 NumFunctionNP = 0, NumTypeName = 0, NumTagged = 0, NumReference = 0;
unsigned NumTagStruct = 0, NumTagUnion = 0, NumTagEnum = 0, NumTagClass = 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<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;
++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;
}
assert(0 && "Unknown type!");
}
}
fprintf(stderr, " %d builtin types\n", NumBuiltin);
fprintf(stderr, " %d pointer types\n", NumPointer);
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, "Total bytes = %d\n", int(NumBuiltin*sizeof(BuiltinType)+
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.
Chris Lattner
committed
InitBuiltinType(VoidTy, BuiltinType::Void);
// C99 6.2.5p2.
Chris Lattner
committed
InitBuiltinType(BoolTy, BuiltinType::Bool);
// C99 6.2.5p3.
Chris Lattner
committed
if (Target.isCharSigned(SourceLocation()))
InitBuiltinType(CharTy, BuiltinType::Char_S);
else
InitBuiltinType(CharTy, BuiltinType::Char_U);
// C99 6.2.5p4.
Chris Lattner
committed
InitBuiltinType(SignedCharTy, BuiltinType::SChar);
InitBuiltinType(ShortTy, BuiltinType::Short);
InitBuiltinType(IntTy, BuiltinType::Int);
InitBuiltinType(LongTy, BuiltinType::Long);
InitBuiltinType(LongLongTy, BuiltinType::LongLong);
// C99 6.2.5p6.
Chris Lattner
committed
InitBuiltinType(UnsignedCharTy, BuiltinType::UChar);
InitBuiltinType(UnsignedShortTy, BuiltinType::UShort);
InitBuiltinType(UnsignedIntTy, BuiltinType::UInt);
InitBuiltinType(UnsignedLongTy, BuiltinType::ULong);
InitBuiltinType(UnsignedLongLongTy, BuiltinType::ULongLong);
// C99 6.2.5p10.
Chris Lattner
committed
InitBuiltinType(FloatTy, BuiltinType::Float);
InitBuiltinType(DoubleTy, BuiltinType::Double);
InitBuiltinType(LongDoubleTy, BuiltinType::LongDouble);
// C99 6.2.5p11.
Chris Lattner
committed
FloatComplexTy = getComplexType(FloatTy);
DoubleComplexTy = getComplexType(DoubleTy);
LongDoubleComplexTy = getComplexType(LongDoubleTy);
BuiltinVaListType = QualType();
ObjcIdType = QualType();
IdStructType = 0;
// 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, SourceLocation L) {
T = T.getCanonicalType();
uint64_t Size;
unsigned Align;
switch (T->getTypeClass()) {
Chris Lattner
committed
case Type::TypeName: assert(0 && "Not a canonical type!");
case Type::FunctionNoProto:
case Type::FunctionProto:
assert(0 && "Incomplete types have no size!");
case Type::VariableArray:
assert(0 && "VLAs not implemented yet!");
case Type::ConstantArray: {
ConstantArrayType *CAT = cast<ConstantArrayType>(T);
Chris Lattner
committed
std::pair<uint64_t, unsigned> EltInfo =
getTypeInfo(CAT->getElementType(), L);
Size = EltInfo.first*CAT->getSize().getZExtValue();
Chris Lattner
committed
Align = EltInfo.second;
break;
}
case Type::Vector: {
std::pair<uint64_t, unsigned> EltInfo =
getTypeInfo(cast<VectorType>(T)->getElementType(), L);
Size = 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.
const llvm::fltSemantics *F;
switch (cast<BuiltinType>(T)->getKind()) {
default: assert(0 && "Unknown builtin type!");
case BuiltinType::Void:
assert(0 && "Incomplete types have no size!");
case BuiltinType::Bool: Target.getBoolInfo(Size, Align, L); break;
case BuiltinType::Char_S:
case BuiltinType::Char_U:
case BuiltinType::UChar:
case BuiltinType::SChar: Target.getCharInfo(Size, Align, L); break;
case BuiltinType::UShort:
case BuiltinType::Short: Target.getShortInfo(Size, Align, L); break;
case BuiltinType::UInt:
case BuiltinType::Int: Target.getIntInfo(Size, Align, L); break;
case BuiltinType::ULong:
case BuiltinType::Long: Target.getLongInfo(Size, Align, L); break;
case BuiltinType::ULongLong:
case BuiltinType::LongLong: Target.getLongLongInfo(Size, Align, L); break;
case BuiltinType::Float: Target.getFloatInfo(Size, Align, F, L); break;
case BuiltinType::Double: Target.getDoubleInfo(Size, Align, F, L);break;
case BuiltinType::LongDouble:Target.getLongDoubleInfo(Size,Align,F,L);break;
}
break;
}
case Type::Pointer: Target.getPointerInfo(Size, Align, L); 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!
return getTypeInfo(cast<ReferenceType>(T)->getReferenceeType(), L);
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(), L);
Size = EltInfo.first*2;
Align = EltInfo.second;
break;
}
case Type::Tagged:
TagType *TT = cast<TagType>(T);
if (RecordType *RT = dyn_cast<RecordType>(TT)) {
const RecordLayout &Layout = getRecordLayout(RT->getDecl(), L);
Size = Layout.getSize();
Align = Layout.getAlignment();
} else if (EnumDecl *ED = dyn_cast<EnumDecl>(TT->getDecl())) {
return getTypeInfo(ED->getIntegerType(), L);
assert(0 && "Unimplemented type sizes!");
}
assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2");
return std::make_pair(Size, Align);
}
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
/// getRecordLayout - Get or compute information about the layout of the
/// specified record (struct/union/class), which indicates its size and field
/// position information.
const RecordLayout &ASTContext::getRecordLayout(const RecordDecl *D,
SourceLocation L) {
assert(D->isDefinition() && "Cannot get layout of forward declarations!");
// Look up this layout, if already laid out, return what we have.
const RecordLayout *&Entry = RecordLayoutInfo[D];
if (Entry) return *Entry;
// Allocate and assign into RecordLayoutInfo here. The "Entry" reference can
// be invalidated (dangle) if the RecordLayoutInfo hashtable is inserted into.
RecordLayout *NewEntry = new RecordLayout();
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) {
// 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);
std::pair<uint64_t, unsigned> FieldInfo = getTypeInfo(FD->getType(), L);
uint64_t FieldSize = FieldInfo.first;
unsigned 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(), L);
uint64_t FieldSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
// 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
//===----------------------------------------------------------------------===//
Chris Lattner
committed
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
/// 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(T.getCanonicalType());
// 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.
// Unique pointers, to guarantee there is only one pointer of a particular
// structure.
Chris Lattner
committed
llvm::FoldingSetNodeID ID;
PointerType::Profile(ID, T);
void *InsertPos = 0;
if (PointerType *PT = PointerTypes.FindNodeOrInsertPos(ID, InsertPos))
Chris Lattner
committed
// If the pointee type isn't canonical, this won't be a canonical type either,
// so fill in the canonical type field.
if (!T->isCanonical()) {
// 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);
/// 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.
Chris Lattner
committed
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(T.getCanonicalType());
// 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,
Steve Naroff
committed
const llvm::APInt &ArySize,
ArrayType::ArraySizeModifier ASM,
unsigned EltTypeQuals) {
Chris Lattner
committed
llvm::FoldingSetNodeID ID;
void *InsertPos = 0;
if (ConstantArrayType *ATP = ArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
Chris Lattner
committed
// If the element type isn't canonical, this won't be a canonical type either,
// so fill in the canonical type field.
if (!EltTy->isCanonical()) {
Steve Naroff
committed
Canonical = getConstantArrayType(EltTy.getCanonicalType(), ArySize,
ASM, EltTypeQuals);
// Get the new insert position for the node we care about.
ConstantArrayType *NewIP = ArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!");
}
Chris Lattner
committed
Steve Naroff
committed
ConstantArrayType *New = new ConstantArrayType(EltTy, Canonical, ArySize,
ASM, EltTypeQuals);
ArrayTypes.InsertNode(New, InsertPos);
Types.push_back(New);
Chris Lattner
committed
}
/// getVariableArrayType - Returns a non-unique reference to the type for a
/// variable array of the specified element type.
Steve Naroff
committed
QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts,
ArrayType::ArraySizeModifier ASM,
unsigned EltTypeQuals) {
if (NumElts) {
// 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);
CompleteVariableArrayTypes.push_back(New);
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
Types.push_back(New);
return QualType(New, 0);
}
else {
// No size is provided for the VLA. These we can unique.
llvm::FoldingSetNodeID ID;
VariableArrayType::Profile(ID, EltTy);
void *InsertPos = 0;
if (VariableArrayType *ATP =
IncompleteVariableArrayTypes.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 = getVariableArrayType(EltTy.getCanonicalType(), NumElts,
ASM, EltTypeQuals);
// Get the new insert position for the node we care about.
VariableArrayType *NewIP =
IncompleteVariableArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!");
}
VariableArrayType *New = new VariableArrayType(EltTy, QualType(), NumElts,
ASM, EltTypeQuals);
IncompleteVariableArrayTypes.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>(vecType.getCanonicalType().getTypePtr());
// Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID;
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()) {
// 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);
}
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
/// 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>(vecType.getCanonicalType().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(vecType.getCanonicalType(), 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);
}
Chris Lattner
committed
/// getFunctionTypeNoProto - Return a K&R style C function type like 'int()'.
///
Chris Lattner
committed
// Unique functions, to guarantee there is only one function of a particular
// structure.
Chris Lattner
committed
llvm::FoldingSetNodeID ID;
Chris Lattner
committed
FunctionTypeNoProto::Profile(ID, ResultTy);
void *InsertPos = 0;
if (FunctionTypeNoProto *FT =
FunctionTypeNoProtos.FindNodeOrInsertPos(ID, InsertPos))
Chris Lattner
committed
Chris Lattner
committed
if (!ResultTy->isCanonical()) {
Chris Lattner
committed
// 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!");
}
Chris Lattner
committed
Chris Lattner
committed
FunctionTypeNoProto *New = new FunctionTypeNoProto(ResultTy, Canonical);
Types.push_back(New);
FunctionTypeProtos.InsertNode(New, InsertPos);
Chris Lattner
committed
}
/// 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) {
Chris Lattner
committed
// Unique functions, to guarantee there is only one function of a particular
// structure.
Chris Lattner
committed
llvm::FoldingSetNodeID ID;
FunctionTypeProto::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic);
void *InsertPos = 0;
if (FunctionTypeProto *FTP =
FunctionTypeProtos.FindNodeOrInsertPos(ID, InsertPos))
Chris Lattner
committed
// 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.
Chris Lattner
committed
if (!isCanonical) {
Chris Lattner
committed
llvm::SmallVector<QualType, 16> CanonicalArgs;
Chris Lattner
committed
CanonicalArgs.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
CanonicalArgs.push_back(ArgArray[i].getCanonicalType());
Canonical = getFunctionType(ResultTy.getCanonicalType(),
&CanonicalArgs[0], NumArgs,
// 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!");
Chris Lattner
committed
}
// 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));
Chris Lattner
committed
new (FTP) FunctionTypeProto(ResultTy, ArgArray, NumArgs, isVariadic,
Canonical);
Types.push_back(FTP);
FunctionTypeProtos.InsertNode(FTP, InsertPos);
Chris Lattner
committed
}
/// 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 = Decl->getUnderlyingType().getCanonicalType();
Decl->TypeForDecl = new TypedefType(Decl, Canonical);
Types.push_back(Decl->TypeForDecl);
}
/// 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(Decl);
Types.push_back(Decl->TypeForDecl);
return QualType(Decl->TypeForDecl, 0);
}
/// getObjcQualifiedInterfaceType - Return a
/// ObjcQualifiedInterfaceType type for the given interface decl and
/// the conforming protocol list.
QualType ASTContext::getObjcQualifiedInterfaceType(ObjcInterfaceDecl *Decl,
ObjcProtocolDecl **Protocols, unsigned NumProtocols) {
ObjcInterfaceType *IType =
cast<ObjcInterfaceType>(getObjcInterfaceType(Decl));
llvm::FoldingSetNodeID ID;
ObjcQualifiedInterfaceType::Profile(ID, IType, Protocols, NumProtocols);
void *InsertPos = 0;
if (ObjcQualifiedInterfaceType *QT =
ObjcQualifiedInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(QT, 0);
// No Match;
ObjcQualifiedInterfaceType *QType =
new ObjcQualifiedInterfaceType(IType, Protocols, NumProtocols);
Types.push_back(QType);
ObjcQualifiedInterfaceTypes.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).
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 = tofType.getCanonicalType();
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.
// The decl stores the type cache.
Types.push_back(Decl->TypeForDecl);
}
/// 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;
}
/// 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;
}
/// 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.
static int getIntegerRank(QualType t) {
if (const TagType *TT = dyn_cast<TagType>(t.getCanonicalType())) {
assert(TT->getDecl()->getKind() == Decl::Enum && "not an int or enum");
return 4;
}
const BuiltinType *BT = cast<BuiltinType>(t.getCanonicalType());
switch (BT->getKind()) {
default:
assert(0 && "getIntegerRank(): not a built-in integer");
case BuiltinType::Bool:
return 1;
Chris Lattner
committed
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;
/// getFloatingRank - Return a relative rank for floating point types.
/// This routine will assert if passed a built-in type that isn't a float.
Chris Lattner
committed
static int getFloatingRank(QualType T) {
T = T.getCanonicalType();
if (ComplexType *CT = dyn_cast<ComplexType>(T))
return getFloatingRank(CT->getElementType());
switch (cast<BuiltinType>(T)->getKind()) {
default: assert(0 && "getFloatingPointRank(): 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 typeSize, QualType typeDomain) const {
if (typeDomain->isComplexType()) {
switch (getFloatingRank(typeSize)) {
case FloatRank: return FloatComplexTy;
case DoubleRank: return DoubleComplexTy;
case LongDoubleRank: return LongDoubleComplexTy;
}
}
if (typeDomain->isRealFloatingType()) {
switch (getFloatingRank(typeSize)) {
case FloatRank: return FloatTy;
case DoubleRank: return DoubleTy;
case LongDoubleRank: return LongDoubleTy;
}
//an invalid return value, but the assert
//will ensure that this code is never reached.
return VoidTy;
Steve Naroff
committed
/// compareFloatingType - Handles 3 different combos:
/// float/float, float/complex, complex/complex.
/// If lt > rt, return 1. If lt == rt, return 0. If lt < rt, return -1.
int ASTContext::compareFloatingType(QualType lt, QualType rt) {
if (getFloatingRank(lt) == getFloatingRank(rt))
return 0;
if (getFloatingRank(lt) > getFloatingRank(rt))
return 1;
return -1;
// maxIntegerType - Returns the highest ranked integer type. Handles 3 case:
// unsigned/unsigned, signed/signed, signed/unsigned. C99 6.3.1.8p1.
Chris Lattner
committed
if (lhs == rhs) return lhs;
bool t1Unsigned = lhs->isUnsignedIntegerType();
bool t2Unsigned = rhs->isUnsignedIntegerType();
if ((t1Unsigned && t2Unsigned) || (!t1Unsigned && !t2Unsigned))
return getIntegerRank(lhs) >= getIntegerRank(rhs) ? lhs : rhs;
// We have two integer types with differing signs
QualType unsignedType = t1Unsigned ? lhs : rhs;
QualType signedType = t1Unsigned ? rhs : lhs;
if (getIntegerRank(unsignedType) >= getIntegerRank(signedType))
return unsignedType;
else {
// FIXME: Need to check if the signed type can represent all values of the
// unsigned type. If it can, then the result is the signed type.
// If it can't, then the result is the unsigned version of the signed type.
// Should probably add a helper that returns a signed integer type from
// an unsigned (and vice versa). C99 6.3.1.8.
return signedType;
}
// getCFConstantStringType - Return the type used for constant CFStrings.
QualType ASTContext::getCFConstantStringType() {
if (!CFConstantStringTypeDecl) {
CFConstantStringTypeDecl = new RecordDecl(Decl::Struct, SourceLocation(),
&Idents.get("__builtin_CFString"),
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)
CFConstantStringTypeDecl->defineBody(FieldDecls, 4);
}
return getTagDeclType(CFConstantStringTypeDecl);
// This returns true if a type has been typedefed to BOOL:
// typedef <type> BOOL;
if (const TypedefType *TT = dyn_cast<TypedefType>(T))
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
/// getObjcEncodingTypeSize returns size of type for objective-c encoding
/// purpose.
int ASTContext::getObjcEncodingTypeSize(QualType type) {
SourceLocation Loc;
uint64_t sz = getTypeSize(type, Loc);
// Make all integer and enum types at least as large as an int
if (sz > 0 && type->isIntegralType())
sz = std::max(sz, getTypeSize(IntTy, Loc));
// Treat arrays as pointers, since that's how they're passed in.
else if (type->isArrayType())
sz = getTypeSize(VoidPtrTy, Loc);
return sz / getTypeSize(CharTy, Loc);
}
/// getObjcEncodingForMethodDecl - Return the encoded type for this method
/// declaration.
void ASTContext::getObjcEncodingForMethodDecl(ObjcMethodDecl *Decl,
std::string& S)
{
// TODO: First encode type qualifer, 'in', 'inout', etc. for the return type.
// Encode result type.
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, Loc) / getTypeSize(CharTy, Loc);
// 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();
// TODO: Process argument qualifiers for user supplied arguments; such as,
// 'in', 'inout', etc.
getObjcEncodingForType(PType, S);
S += llvm::utostr(ParmOffset);
ParmOffset += getObjcEncodingTypeSize(PType);
}
}
void ASTContext::getObjcEncodingForType(QualType T, std::string& S) 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()) {
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
char encoding;
switch (BT->getKind()) {
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;