diff options
Diffstat (limited to 'AST/ASTContext.cpp')
-rw-r--r-- | AST/ASTContext.cpp | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp new file mode 100644 index 0000000000..b1c20c98e5 --- /dev/null +++ b/AST/ASTContext.cpp @@ -0,0 +1,531 @@ +//===--- 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/Lex/Preprocessor.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallVector.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 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<ReferenceType>(T)) + ++NumReference; + else if (isa<ArrayType>(T)) + ++NumArray; + 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 { + 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 array types\n", NumArray); + 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)+ + NumPointer*sizeof(PointerType)+NumArray*sizeof(ArrayType)+ + 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(SourceLocation())) + 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); +} + +/// 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. +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(T.getCanonicalType()); + + // 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(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); +} + +/// getArrayType - Return the unique reference to the type for an array of the +/// specified element type. +QualType ASTContext::getArrayType(QualType EltTy,ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals, Expr *NumElts) { + // Unique array types, to guarantee there is only one array of a particular + // structure. + llvm::FoldingSetNodeID ID; + ArrayType::Profile(ID, ASM, EltTypeQuals, EltTy, NumElts); + + void *InsertPos = 0; + if (ArrayType *ATP = ArrayTypes.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 = getArrayType(EltTy.getCanonicalType(), ASM, EltTypeQuals, + NumElts); + + // Get the new insert position for the node we care about. + ArrayType *NewIP = ArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + + ArrayType *New = new ArrayType(EltTy, ASM, EltTypeQuals, Canonical, NumElts); + ArrayTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + +/// convertToVectorType - Return the unique reference to a vector type of +/// the specified element type and size. VectorType can be a pointer, array, +/// function, or built-in type (i.e. _Bool, integer, or float). +QualType ASTContext::convertToVectorType(QualType vecType, unsigned NumElts) { + BuiltinType *baseType; + + baseType = dyn_cast<BuiltinType>(vecType.getCanonicalType().getTypePtr()); + assert(baseType != 0 && + "convertToVectorType(): Complex vector types unimplemented"); + + // Check if we've already instantiated a vector of this type. + llvm::FoldingSetNodeID ID; + VectorType::Profile(ID, vecType, NumElts); + 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 = convertToVectorType(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!"); + } + VectorType *New = new VectorType(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(ResultTy.getCanonicalType()); + + // 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); + FunctionTypeProtos.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(ArgArray[i].getCanonicalType()); + + Canonical = getFunctionType(ResultTy.getCanonicalType(), + &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-1)*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 = Decl->getUnderlyingType().getCanonicalType(); + Decl->TypeForDecl = new TypedefType(Decl, Canonical); + Types.push_back(Decl->TypeForDecl); + return QualType(Decl->TypeForDecl, 0); +} + +/// getTagDeclType - Return the unique reference to the type for the +/// specified TagDecl (struct/union/class/enum) decl. +QualType ASTContext::getTagDeclType(TagDecl *Decl) { + // The decl stores the type cache. + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + Decl->TypeForDecl = new TagType(Decl, QualType()); + Types.push_back(Decl->TypeForDecl); + return QualType(Decl->TypeForDecl, 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; +} + +/// getIntegerBitwidth - Return the bitwidth of the specified integer type +/// according to the target. 'Loc' specifies the source location that +/// requires evaluation of this property. +unsigned ASTContext::getIntegerBitwidth(QualType T, SourceLocation Loc) { + if (const TagType *TT = dyn_cast<TagType>(T.getCanonicalType())) { + assert(TT->getDecl()->getKind() == Decl::Enum && "not an int or enum"); + assert(0 && "FIXME: getIntegerBitwidth(enum) unimplemented!"); + } + + const BuiltinType *BT = cast<BuiltinType>(T.getCanonicalType()); + switch (BT->getKind()) { + default: assert(0 && "getIntegerBitwidth(): not a built-in integer"); + case BuiltinType::Bool: return Target.getBoolWidth(Loc); + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: return Target.getCharWidth(Loc); + case BuiltinType::Short: + case BuiltinType::UShort: return Target.getShortWidth(Loc); + case BuiltinType::Int: + case BuiltinType::UInt: return Target.getIntWidth(Loc); + case BuiltinType::Long: + case BuiltinType::ULong: return Target.getLongWidth(Loc); + case BuiltinType::LongLong: + case BuiltinType::ULongLong: return Target.getLongLongWidth(Loc); + } +} + +/// 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; + 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. +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; + } +} + +// maxComplexType - the following code handles 3 different combinations: +// complex/complex, complex/float, float/complex. +// When both operands are complex, the shorter operand is converted to the +// type of the longer, and that is the type of the result. This corresponds +// to what is done when combining two real floating-point operands. +// The fun begins when size promotion occur across type domains. g +// getFloatingRank & convertFloatingRankToComplexType handle this without +// enumerating all permutations. +// It also allows us to add new types without breakage. +// From H&S 6.3.4: When one operand is complex and the other is a real +// floating-point type, the less precise type is converted, within it's +// real or complex domain, to the precision of the other type. For example, +// when combining a "long double" with a "double _Complex", the +// "double _Complex" is promoted to "long double _Complex". + +QualType ASTContext::maxComplexType(QualType lt, QualType rt) const { + switch (std::max(getFloatingRank(lt), getFloatingRank(rt))) { + default: assert(0 && "convertRankToComplex(): illegal value for rank"); + case FloatRank: return FloatComplexTy; + case DoubleRank: return DoubleComplexTy; + case LongDoubleRank: return LongDoubleComplexTy; + } +} + +// maxFloatingType - handles the simple case, both operands are floats. +QualType ASTContext::maxFloatingType(QualType lt, QualType rt) { + return getFloatingRank(lt) > getFloatingRank(rt) ? lt : rt; +} + +// maxIntegerType - Returns the highest ranked integer type. Handles 3 case: +// unsigned/unsigned, signed/signed, signed/unsigned. C99 6.3.1.8p1. +QualType ASTContext::maxIntegerType(QualType lhs, QualType rhs) { + 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; + } +} |