123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531 |
- //===--- 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;
- }
- }
|