diff options
Diffstat (limited to 'AST')
-rw-r--r-- | AST/ASTContext.cpp | 531 | ||||
-rw-r--r-- | AST/Builtins.cpp | 125 | ||||
-rw-r--r-- | AST/Decl.cpp | 161 | ||||
-rw-r--r-- | AST/Expr.cpp | 536 | ||||
-rw-r--r-- | AST/Makefile | 22 | ||||
-rw-r--r-- | AST/Stmt.cpp | 81 | ||||
-rw-r--r-- | AST/StmtPrinter.cpp | 436 | ||||
-rw-r--r-- | AST/StmtVisitor.cpp | 26 | ||||
-rw-r--r-- | AST/Type.cpp | 593 |
9 files changed, 2511 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; + } +} diff --git a/AST/Builtins.cpp b/AST/Builtins.cpp new file mode 100644 index 0000000000..454085bf2a --- /dev/null +++ b/AST/Builtins.cpp @@ -0,0 +1,125 @@ +//===--- Builtins.cpp - Builtin function implementation -------------------===// +// +// 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 various things for builtin functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Builtins.h" +#include "clang/AST/ASTContext.h" +#include "clang/Lex/IdentifierTable.h" +#include "clang/Basic/TargetInfo.h" +using namespace clang; + +static const Builtin::Info BuiltinInfo[] = { + { "not a builtin function", 0, 0 }, +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS }, +#include "clang/AST/Builtins.def" +}; + +const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const { + if (ID < Builtin::FirstTSBuiltin) + return BuiltinInfo[ID]; + assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!"); + return TSRecords[ID - Builtin::FirstTSBuiltin]; +} + + +/// InitializeBuiltins - Mark the identifiers for all the builtins with their +/// appropriate builtin ID # and mark any non-portable builtin identifiers as +/// such. +void Builtin::Context::InitializeBuiltins(IdentifierTable &Table, + const TargetInfo &Target) { + // Step #1: mark all target-independent builtins with their ID's. + for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) + Table.get(BuiltinInfo[i].Name).setBuiltinID(i); + + // Step #2: handle target builtins. + std::vector<const char *> NonPortableBuiltins; + Target.getTargetBuiltins(TSRecords, NumTSRecords, NonPortableBuiltins); + + // Step #2a: Register target-specific builtins. + for (unsigned i = 0, e = NumTSRecords; i != e; ++i) + Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin); + + // Step #2b: Mark non-portable builtins as such. + for (unsigned i = 0, e = NonPortableBuiltins.size(); i != e; ++i) + Table.get(NonPortableBuiltins[i]).setNonPortableBuiltin(true); +} + +/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the +/// pointer over the consumed characters. This returns the resultant type. +static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context) { + // Modifiers. + bool Long = false, LongLong = false, Signed = false, Unsigned = false; + + // Read the modifiers first. + bool Done = false; + while (!Done) { + switch (*Str++) { + default: Done = true; --Str; break; + case 'S': + assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!"); + assert(!Signed && "Can't use 'S' modifier multiple times!"); + Signed = true; + break; + case 'U': + assert(!Signed && "Can't use both 'S' and 'U' modifiers!"); + assert(!Unsigned && "Can't use 'S' modifier multiple times!"); + Unsigned = true; + break; + case 'L': + assert(!LongLong && "Can't have LLL modifier"); + if (Long) + LongLong = true; + else + Long = true; + break; + } + } + + // Read the base type. + switch (*Str++) { + default: assert(0 && "Unknown builtin type letter!"); + case 'v': + assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'f'!"); + return Context.VoidTy; + case 'f': + assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'f'!"); + return Context.FloatTy; + case 'd': + assert(!LongLong && !Signed && !Unsigned && "Bad modifiers used with 'd'!"); + if (Long) + return Context.LongDoubleTy; + return Context.DoubleTy; + case 's': + assert(!LongLong && "Bad modifiers used with 's'!"); + if (Unsigned) + return Context.UnsignedShortTy; + return Context.ShortTy; + //case 'i': + } +} + +/// GetBuiltinType - Return the type for the specified builtin. +QualType Builtin::Context::GetBuiltinType(unsigned id, ASTContext &Context)const{ + const char *TypeStr = GetRecord(id).Type; + + llvm::SmallVector<QualType, 8> ArgTypes; + + QualType ResType = DecodeTypeFromStr(TypeStr, Context); + while (TypeStr[0] && TypeStr[0] != '.') + ArgTypes.push_back(DecodeTypeFromStr(TypeStr, Context)); + + assert((TypeStr[0] != '.' || TypeStr[1] == 0) && + "'.' should only occur at end of builtin type list!"); + + return Context.getFunctionType(ResType, &ArgTypes[0], ArgTypes.size(), + TypeStr[0] == '.'); +} diff --git a/AST/Decl.cpp b/AST/Decl.cpp new file mode 100644 index 0000000000..22fbabbd30 --- /dev/null +++ b/AST/Decl.cpp @@ -0,0 +1,161 @@ +//===--- Decl.cpp - Declaration AST Node Implementation -------------------===// +// +// 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 Decl class and subclasses. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Decl.h" +#include "clang/Lex/IdentifierTable.h" +using namespace clang; + +// temporary statistics gathering +static unsigned nFuncs = 0; +static unsigned nBlockVars = 0; +static unsigned nFileVars = 0; +static unsigned nParmVars = 0; +static unsigned nSUC = 0; +static unsigned nEnumConst = 0; +static unsigned nEnumDecls = 0; +static unsigned nTypedef = 0; +static unsigned nFieldDecls = 0; +static bool StatSwitch = false; + +bool Decl::CollectingStats(bool enable) { + if (enable) StatSwitch = true; + return StatSwitch; +} + +void Decl::PrintStats() { + fprintf(stderr, "*** Decl Stats:\n"); + fprintf(stderr, " %d decls total.\n", + int(nFuncs+nBlockVars+nFileVars+nParmVars+nFieldDecls+nSUC+ + nEnumDecls+nEnumConst+nTypedef)); + fprintf(stderr, " %d function decls, %d each (%d bytes)\n", + nFuncs, (int)sizeof(FunctionDecl), int(nFuncs*sizeof(FunctionDecl))); + fprintf(stderr, " %d block variable decls, %d each (%d bytes)\n", + nBlockVars, (int)sizeof(BlockVarDecl), + int(nBlockVars*sizeof(BlockVarDecl))); + fprintf(stderr, " %d file variable decls, %d each (%d bytes)\n", + nFileVars, (int)sizeof(FileVarDecl), + int(nFileVars*sizeof(FileVarDecl))); + fprintf(stderr, " %d parameter variable decls, %d each (%d bytes)\n", + nParmVars, (int)sizeof(ParmVarDecl), + int(nParmVars*sizeof(ParmVarDecl))); + fprintf(stderr, " %d field decls, %d each (%d bytes)\n", + nFieldDecls, (int)sizeof(FieldDecl), + int(nFieldDecls*sizeof(FieldDecl))); + fprintf(stderr, " %d struct/union/class decls, %d each (%d bytes)\n", + nSUC, (int)sizeof(RecordDecl), + int(nSUC*sizeof(RecordDecl))); + fprintf(stderr, " %d enum decls, %d each (%d bytes)\n", + nEnumDecls, (int)sizeof(EnumDecl), + int(nEnumDecls*sizeof(EnumDecl))); + fprintf(stderr, " %d enum constant decls, %d each (%d bytes)\n", + nEnumConst, (int)sizeof(EnumConstantDecl), + int(nEnumConst*sizeof(EnumConstantDecl))); + fprintf(stderr, " %d typedef decls, %d each (%d bytes)\n", + nTypedef, (int)sizeof(TypedefDecl),int(nTypedef*sizeof(TypedefDecl))); + fprintf(stderr, "Total bytes = %d\n", + int(nFuncs*sizeof(FunctionDecl)+nBlockVars*sizeof(BlockVarDecl)+ + nFileVars*sizeof(FileVarDecl)+nParmVars*sizeof(ParmVarDecl)+ + nFieldDecls*sizeof(FieldDecl)+nSUC*sizeof(RecordDecl)+ + nEnumDecls*sizeof(EnumDecl)+nEnumConst*sizeof(EnumConstantDecl)+ + nTypedef*sizeof(TypedefDecl))); +} + +void Decl::addDeclKind(const Kind k) { + switch (k) { + case Typedef: + nTypedef++; + break; + case Function: + nFuncs++; + break; + case BlockVariable: + nBlockVars++; + break; + case FileVariable: + nFileVars++; + break; + case ParmVariable: + nParmVars++; + break; + case EnumConstant: + nEnumConst++; + break; + case Field: + nFieldDecls++; + break; + case Struct: + case Union: + case Class: + nSUC++; + break; + case Enum: + nEnumDecls++; + break; + } +} + +// Out-of-line virtual method providing a home for Decl. +Decl::~Decl() { +} + +const char *Decl::getName() const { + if (const IdentifierInfo *II = getIdentifier()) + return II->getName(); + return ""; +} + + +FunctionDecl::~FunctionDecl() { + delete[] ParamInfo; +} + +unsigned FunctionDecl::getNumParams() const { + return cast<FunctionTypeProto>(getType().getTypePtr())->getNumArgs(); +} + +void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) { + assert(ParamInfo == 0 && "Already has param info!"); + assert(NumParams == getNumParams() && "Parameter count mismatch!"); + + // Zero params -> null pointer. + if (NumParams) { + ParamInfo = new ParmVarDecl*[NumParams]; + memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); + } +} + + +/// defineBody - When created, RecordDecl's correspond to a forward declared +/// record. This method is used to mark the decl as being defined, with the +/// specified contents. +void RecordDecl::defineBody(FieldDecl **members, unsigned numMembers) { + assert(!isDefinition() && "Cannot redefine record!"); + setDefinition(true); + NumMembers = numMembers; + if (numMembers) { + Members = new FieldDecl*[numMembers]; + memcpy(Members, members, numMembers*sizeof(Decl*)); + } +} + +FieldDecl* RecordDecl::getMember(IdentifierInfo *name) { + if (Members == 0 || NumMembers < 0) + return 0; + + // linear search. When C++ classes come along, will likely need to revisit. + for (int i = 0; i < NumMembers; ++i) { + if (Members[i]->getIdentifier() == name) + return Members[i]; + } + return 0; +}
\ No newline at end of file diff --git a/AST/Expr.cpp b/AST/Expr.cpp new file mode 100644 index 0000000000..b7dbcc7de6 --- /dev/null +++ b/AST/Expr.cpp @@ -0,0 +1,536 @@ +//===--- Expr.cpp - Expression AST Node Implementation --------------------===// +// +// 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 Expr class and subclasses. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Expr.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Lex/IdentifierTable.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Primary Expressions. +//===----------------------------------------------------------------------===// + +StringLiteral::StringLiteral(const char *strData, unsigned byteLength, + bool Wide, QualType t, SourceLocation firstLoc, + SourceLocation lastLoc) : + Expr(StringLiteralClass, t) { + // OPTIMIZE: could allocate this appended to the StringLiteral. + char *AStrData = new char[byteLength]; + memcpy(AStrData, strData, byteLength); + StrData = AStrData; + ByteLength = byteLength; + IsWide = Wide; + firstTokLoc = firstLoc; + lastTokLoc = lastLoc; +} + +StringLiteral::~StringLiteral() { + delete[] StrData; +} + +bool UnaryOperator::isPostfix(Opcode Op) { + switch (Op) { + case PostInc: + case PostDec: + return true; + default: + return false; + } +} + +/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it +/// corresponds to, e.g. "sizeof" or "[pre]++". +const char *UnaryOperator::getOpcodeStr(Opcode Op) { + switch (Op) { + default: assert(0 && "Unknown unary operator"); + case PostInc: return "++"; + case PostDec: return "--"; + case PreInc: return "++"; + case PreDec: return "--"; + case AddrOf: return "&"; + case Deref: return "*"; + case Plus: return "+"; + case Minus: return "-"; + case Not: return "~"; + case LNot: return "!"; + case Real: return "__real"; + case Imag: return "__imag"; + case SizeOf: return "sizeof"; + case AlignOf: return "alignof"; + case Extension: return "__extension__"; + } +} + +//===----------------------------------------------------------------------===// +// Postfix Operators. +//===----------------------------------------------------------------------===// + +CallExpr::CallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t, + SourceLocation rparenloc) + : Expr(CallExprClass, t), Fn(fn), NumArgs(numargs) { + Args = new Expr*[numargs]; + for (unsigned i = 0; i != numargs; ++i) + Args[i] = args[i]; + RParenLoc = rparenloc; +} + +/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it +/// corresponds to, e.g. "<<=". +const char *BinaryOperator::getOpcodeStr(Opcode Op) { + switch (Op) { + default: assert(0 && "Unknown binary operator"); + case Mul: return "*"; + case Div: return "/"; + case Rem: return "%"; + case Add: return "+"; + case Sub: return "-"; + case Shl: return "<<"; + case Shr: return ">>"; + case LT: return "<"; + case GT: return ">"; + case LE: return "<="; + case GE: return ">="; + case EQ: return "=="; + case NE: return "!="; + case And: return "&"; + case Xor: return "^"; + case Or: return "|"; + case LAnd: return "&&"; + case LOr: return "||"; + case Assign: return "="; + case MulAssign: return "*="; + case DivAssign: return "/="; + case RemAssign: return "%="; + case AddAssign: return "+="; + case SubAssign: return "-="; + case ShlAssign: return "<<="; + case ShrAssign: return ">>="; + case AndAssign: return "&="; + case XorAssign: return "^="; + case OrAssign: return "|="; + case Comma: return ","; + } +} + + +//===----------------------------------------------------------------------===// +// Generic Expression Routines +//===----------------------------------------------------------------------===// + +/// hasLocalSideEffect - Return true if this immediate expression has side +/// effects, not counting any sub-expressions. +bool Expr::hasLocalSideEffect() const { + switch (getStmtClass()) { + default: + return false; + case ParenExprClass: + return cast<ParenExpr>(this)->getSubExpr()->hasLocalSideEffect(); + case UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(this); + + switch (UO->getOpcode()) { + default: return false; + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: + return true; // ++/-- + + case UnaryOperator::Deref: + // Dereferencing a volatile pointer is a side-effect. + return getType().isVolatileQualified(); + case UnaryOperator::Real: + case UnaryOperator::Imag: + // accessing a piece of a volatile complex is a side-effect. + return UO->getSubExpr()->getType().isVolatileQualified(); + + case UnaryOperator::Extension: + return UO->getSubExpr()->hasLocalSideEffect(); + } + } + case BinaryOperatorClass: + return cast<BinaryOperator>(this)->isAssignmentOp(); + + case MemberExprClass: + case ArraySubscriptExprClass: + // If the base pointer or element is to a volatile pointer/field, accessing + // if is a side effect. + return getType().isVolatileQualified(); + + case CallExprClass: + // TODO: check attributes for pure/const. "void foo() { strlen("bar"); }" + // should warn. + return true; + + case CastExprClass: + // If this is a cast to void, check the operand. Otherwise, the result of + // the cast is unused. + if (getType()->isVoidType()) + return cast<CastExpr>(this)->getSubExpr()->hasLocalSideEffect(); + return false; + } +} + +/// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an +/// incomplete type other than void. Nonarray expressions that can be lvalues: +/// - name, where name must be a variable +/// - e[i] +/// - (e), where e must be an lvalue +/// - e.name, where e must be an lvalue +/// - e->name +/// - *e, the type of e cannot be a function type +/// - string-constant +/// +Expr::isLvalueResult Expr::isLvalue() { + // first, check the type (C99 6.3.2.1) + if (isa<FunctionType>(TR.getCanonicalType())) // from isObjectType() + return LV_NotObjectType; + + if (TR->isIncompleteType() && TR->isVoidType()) + return LV_IncompleteVoidType; + + // the type looks fine, now check the expression + switch (getStmtClass()) { + case StringLiteralClass: // C99 6.5.1p4 + case ArraySubscriptExprClass: // C99 6.5.3p4 (e1[e2] == (*((e1)+(e2)))) + // For vectors, make sure base is an lvalue (i.e. not a function call). + if (cast<ArraySubscriptExpr>(this)->getBase()->getType()->isVectorType()) + return cast<ArraySubscriptExpr>(this)->getBase()->isLvalue(); + return LV_Valid; + case DeclRefExprClass: // C99 6.5.1p2 + if (isa<VarDecl>(cast<DeclRefExpr>(this)->getDecl())) + return LV_Valid; + break; + case MemberExprClass: // C99 6.5.2.3p4 + const MemberExpr *m = cast<MemberExpr>(this); + return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(); + case UnaryOperatorClass: // C99 6.5.3p4 + if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref) + return LV_Valid; + break; + case ParenExprClass: // C99 6.5.1p5 + return cast<ParenExpr>(this)->getSubExpr()->isLvalue(); + default: + break; + } + return LV_InvalidExpression; +} + +/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, +/// does not have an incomplete type, does not have a const-qualified type, and +/// if it is a structure or union, does not have any member (including, +/// recursively, any member or element of all contained aggregates or unions) +/// with a const-qualified type. +Expr::isModifiableLvalueResult Expr::isModifiableLvalue() { + isLvalueResult lvalResult = isLvalue(); + + switch (lvalResult) { + case LV_Valid: break; + case LV_NotObjectType: return MLV_NotObjectType; + case LV_IncompleteVoidType: return MLV_IncompleteVoidType; + case LV_InvalidExpression: return MLV_InvalidExpression; + } + if (TR.isConstQualified()) + return MLV_ConstQualified; + if (TR->isArrayType()) + return MLV_ArrayType; + if (TR->isIncompleteType()) + return MLV_IncompleteType; + + if (const RecordType *r = dyn_cast<RecordType>(TR.getCanonicalType())) { + if (r->hasConstFields()) + return MLV_ConstQualified; + } + return MLV_Valid; +} + +/// isIntegerConstantExpr - this recursive routine will test if an expression is +/// an integer constant expression. Note: With the introduction of VLA's in +/// C99 the result of the sizeof operator is no longer always a constant +/// expression. The generalization of the wording to include any subexpression +/// that is not evaluated (C99 6.6p3) means that nonconstant subexpressions +/// can appear as operands to other operators (e.g. &&, ||, ?:). For instance, +/// "0 || f()" can be treated as a constant expression. In C90 this expression, +/// occurring in a context requiring a constant, would have been a constraint +/// violation. FIXME: This routine currently implements C90 semantics. +/// To properly implement C99 semantics this routine will need to evaluate +/// expressions involving operators previously mentioned. + +/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero, +/// comma, etc +/// +/// FIXME: This should ext-warn on overflow during evaluation! ISO C does not +/// permit this. +bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, SourceLocation *Loc, + bool isEvaluated) const { + switch (getStmtClass()) { + default: + if (Loc) *Loc = getLocStart(); + return false; + case ParenExprClass: + return cast<ParenExpr>(this)->getSubExpr()-> + isIntegerConstantExpr(Result, Loc, isEvaluated); + case IntegerLiteralClass: + Result = cast<IntegerLiteral>(this)->getValue(); + break; + case CharacterLiteralClass: + // FIXME: This doesn't set the right width etc. + Result.zextOrTrunc(32); // FIXME: NOT RIGHT IN GENERAL. + Result = cast<CharacterLiteral>(this)->getValue(); + break; + case DeclRefExprClass: + if (const EnumConstantDecl *D = + dyn_cast<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl())) { + Result = D->getInitVal(); + break; + } + if (Loc) *Loc = getLocStart(); + return false; + case UnaryOperatorClass: { + const UnaryOperator *Exp = cast<UnaryOperator>(this); + + // Get the operand value. If this is sizeof/alignof, do not evalute the + // operand. This affects C99 6.6p3. + if (Exp->isSizeOfAlignOfOp()) isEvaluated = false; + if (!Exp->getSubExpr()->isIntegerConstantExpr(Result, Loc, isEvaluated)) + return false; + + switch (Exp->getOpcode()) { + // Address, indirect, pre/post inc/dec, etc are not valid constant exprs. + // See C99 6.6p3. + default: + if (Loc) *Loc = Exp->getOperatorLoc(); + return false; + case UnaryOperator::Extension: + return true; + case UnaryOperator::SizeOf: + case UnaryOperator::AlignOf: + // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. + if (!Exp->getSubExpr()->getType()->isConstantSizeType(Loc)) + return false; + + // FIXME: Evaluate sizeof/alignof. + Result.zextOrTrunc(32); // FIXME: NOT RIGHT IN GENERAL. + Result = 1; // FIXME: Obviously bogus + break; + case UnaryOperator::LNot: { + bool Val = Result != 0; + Result.zextOrTrunc(32); // FIXME: NOT RIGHT IN GENERAL. + Result = Val; + break; + } + case UnaryOperator::Plus: + // FIXME: Do usual unary promotions here! + break; + case UnaryOperator::Minus: + // FIXME: Do usual unary promotions here! + Result = -Result; + break; + case UnaryOperator::Not: + // FIXME: Do usual unary promotions here! + Result = ~Result; + break; + } + break; + } + case SizeOfAlignOfTypeExprClass: { + const SizeOfAlignOfTypeExpr *Exp = cast<SizeOfAlignOfTypeExpr>(this); + // alignof always evaluates to a constant. + if (Exp->isSizeOf() && !Exp->getArgumentType()->isConstantSizeType(Loc)) + return false; + + // FIXME: Evaluate sizeof/alignof. + Result.zextOrTrunc(32); // FIXME: NOT RIGHT IN GENERAL. + Result = 1; // FIXME: Obviously bogus + break; + } + case BinaryOperatorClass: { + const BinaryOperator *Exp = cast<BinaryOperator>(this); + + // The LHS of a constant expr is always evaluated and needed. + if (!Exp->getLHS()->isIntegerConstantExpr(Result, Loc, isEvaluated)) + return false; + + llvm::APSInt RHS(Result); + + // The short-circuiting &&/|| operators don't necessarily evaluate their + // RHS. Make sure to pass isEvaluated down correctly. + if (Exp->isLogicalOp()) { + bool RHSEval; + if (Exp->getOpcode() == BinaryOperator::LAnd) + RHSEval = Result != 0; + else { + assert(Exp->getOpcode() == BinaryOperator::LOr &&"Unexpected logical"); + RHSEval = Result == 0; + } + + if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Loc, + isEvaluated & RHSEval)) + return false; + } else { + if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Loc, isEvaluated)) + return false; + } + + // FIXME: These should all do the standard promotions, etc. + switch (Exp->getOpcode()) { + default: + if (Loc) *Loc = getLocStart(); + return false; + case BinaryOperator::Mul: + Result *= RHS; + break; + case BinaryOperator::Div: + if (RHS == 0) { + if (!isEvaluated) break; + if (Loc) *Loc = getLocStart(); + return false; + } + Result /= RHS; + break; + case BinaryOperator::Rem: + if (RHS == 0) { + if (!isEvaluated) break; + if (Loc) *Loc = getLocStart(); + return false; + } + Result %= RHS; + break; + case BinaryOperator::Add: Result += RHS; break; + case BinaryOperator::Sub: Result -= RHS; break; + case BinaryOperator::Shl: + Result <<= RHS.getLimitedValue(Result.getBitWidth()-1); + break; + case BinaryOperator::Shr: + Result >>= RHS.getLimitedValue(Result.getBitWidth()-1); + break; + case BinaryOperator::LT: Result = Result < RHS; break; + case BinaryOperator::GT: Result = Result > RHS; break; + case BinaryOperator::LE: Result = Result <= RHS; break; + case BinaryOperator::GE: Result = Result >= RHS; break; + case BinaryOperator::EQ: Result = Result == RHS; break; + case BinaryOperator::NE: Result = Result != RHS; break; + case BinaryOperator::And: Result &= RHS; break; + case BinaryOperator::Xor: Result ^= RHS; break; + case BinaryOperator::Or: Result |= RHS; break; + case BinaryOperator::LAnd: + Result = Result != 0 && RHS != 0; + break; + case BinaryOperator::LOr: + Result = Result != 0 || RHS != 0; + break; + + case BinaryOperator::Comma: + // C99 6.6p3: "shall not contain assignment, ..., or comma operators, + // *except* when they are contained within a subexpression that is not + // evaluated". Note that Assignment can never happen due to constraints + // on the LHS subexpr, so we don't need to check it here. + if (isEvaluated) { + if (Loc) *Loc = getLocStart(); + return false; + } + + // The result of the constant expr is the RHS. + Result = RHS; + return true; + } + + assert(!Exp->isAssignmentOp() && "LHS can't be a constant expr!"); + break; + } + case CastExprClass: { + const CastExpr *Exp = cast<CastExpr>(this); + // C99 6.6p6: shall only convert arithmetic types to integer types. + if (!Exp->getSubExpr()->getType()->isArithmeticType() || + !Exp->getDestType()->isIntegerType()) { + if (Loc) *Loc = Exp->getSubExpr()->getLocStart(); + return false; + } + + // Handle simple integer->integer casts. + if (Exp->getSubExpr()->getType()->isIntegerType()) { + if (!Exp->getSubExpr()->isIntegerConstantExpr(Result, Loc, isEvaluated)) + return false; + // FIXME: do the conversion on Result. + break; + } + + // Allow floating constants that are the immediate operands of casts or that + // are parenthesized. + const Expr *Operand = Exp->getSubExpr(); + while (const ParenExpr *PE = dyn_cast<ParenExpr>(Operand)) + Operand = PE->getSubExpr(); + + if (const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(Operand)) { + // FIXME: Evaluate this correctly! + Result = (int)FL->getValue(); + break; + } + if (Loc) *Loc = Operand->getLocStart(); + return false; + } + case ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast<ConditionalOperator>(this); + + if (!Exp->getCond()->isIntegerConstantExpr(Result, Loc, isEvaluated)) + return false; + + const Expr *TrueExp = Exp->getLHS(); + const Expr *FalseExp = Exp->getRHS(); + if (Result == 0) std::swap(TrueExp, FalseExp); + + // Evaluate the false one first, discard the result. + if (!FalseExp->isIntegerConstantExpr(Result, Loc, false)) + return false; + // Evalute the true one, capture the result. + if (!TrueExp->isIntegerConstantExpr(Result, Loc, isEvaluated)) + return false; + // FIXME: promotions on result. + break; + } + } + + // Cases that are valid constant exprs fall through to here. + Result.setIsUnsigned(getType()->isUnsignedIntegerType()); + return true; +} + + +/// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an +/// integer constant expression with the value zero, or if this is one that is +/// cast to void*. +bool Expr::isNullPointerConstant() const { + // Strip off a cast to void*, if it exists. + if (const CastExpr *CE = dyn_cast<CastExpr>(this)) { + // Check that it is a cast to void*. + if (const PointerType *PT = dyn_cast<PointerType>(CE->getType())) { + QualType Pointee = PT->getPointeeType(); + if (Pointee.getQualifiers() == 0 && Pointee->isVoidType() && // to void* + CE->getSubExpr()->getType()->isIntegerType()) // from int. + return CE->getSubExpr()->isNullPointerConstant(); + } + } else if (const ParenExpr *PE = dyn_cast<ParenExpr>(this)) { + // Accept ((void*)0) as a null pointer constant, as many other + // implementations do. + return PE->getSubExpr()->isNullPointerConstant(); + } + + // This expression must be an integer type. + if (!getType()->isIntegerType()) + return false; + + // If we have an integer constant expression, we need to *evaluate* it and + // test for the value 0. + llvm::APSInt Val(32); + return isIntegerConstantExpr(Val, 0, true) && Val == 0; +} diff --git a/AST/Makefile b/AST/Makefile new file mode 100644 index 0000000000..17abef6e73 --- /dev/null +++ b/AST/Makefile @@ -0,0 +1,22 @@ +##===- clang/AST/Makefile ----------------------------------*- Makefile -*-===## +# +# 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 implements the AST library for the C-Language front-end. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME := clangAST +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../include + +include $(LEVEL)/Makefile.common + diff --git a/AST/Stmt.cpp b/AST/Stmt.cpp new file mode 100644 index 0000000000..e43f03c404 --- /dev/null +++ b/AST/Stmt.cpp @@ -0,0 +1,81 @@ +//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===// +// +// 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 Stmt class and statement subclasses. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Stmt.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Lex/IdentifierTable.h" +using namespace clang; + +// Implement all the AST node visit methods using the StmtNodes.def database. +#define STMT(N, CLASS, PARENT) \ +void CLASS::visit(StmtVisitor &V) { return V.Visit##CLASS(this); } + +STMT(0, Stmt, ) +#include "clang/AST/StmtNodes.def" + +static struct StmtClassNameTable { + int enumValue; + const char *className; + unsigned counter; + unsigned size; +} sNames[] = { +#define STMT(N, CLASS, PARENT) { N, #CLASS, 0, sizeof(CLASS) }, +#include "clang/AST/StmtNodes.def" + { 0, 0, 0, 0 } +}; + +const char *Stmt::getStmtClassName() const { + for (int i = 0; sNames[i].className; i++) { + if (sClass == sNames[i].enumValue) + return sNames[i].className; + } + return 0; // should never happen.... +} + +void Stmt::PrintStats() { + unsigned sum = 0; + fprintf(stderr, "*** Stmt/Expr Stats:\n"); + for (int i = 0; sNames[i].className; i++) { + sum += sNames[i].counter; + } + fprintf(stderr, " %d stmts/exprs total.\n", sum); + sum = 0; + for (int i = 0; sNames[i].className; i++) { + fprintf(stderr, " %d %s, %d each (%d bytes)\n", + sNames[i].counter, sNames[i].className, sNames[i].size, sNames[i].counter*sNames[i].size); + sum += sNames[i].counter*sNames[i].size; + } + fprintf(stderr, "Total bytes = %d\n", sum); +} + +void Stmt::addStmtClass(StmtClass s) { + for (int i = 0; sNames[i].className; i++) { + if (s == sNames[i].enumValue) + sNames[i].counter++; + } +} + +static bool StatSwitch = false; + +bool Stmt::CollectingStats(bool enable) { + if (enable) StatSwitch = true; + return StatSwitch; +} + + + +const char *LabelStmt::getName() const { + return getID()->getName(); +} + diff --git a/AST/StmtPrinter.cpp b/AST/StmtPrinter.cpp new file mode 100644 index 0000000000..e90b9f2c3f --- /dev/null +++ b/AST/StmtPrinter.cpp @@ -0,0 +1,436 @@ +//===--- StmtPrinter.cpp - Printing implementation for Stmt ASTs ----------===// +// +// 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 Stmt::dump/Stmt::print methods. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/Decl.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Lex/IdentifierTable.h" +#include "llvm/Support/Compiler.h" +#include <iostream> +using namespace clang; + +//===----------------------------------------------------------------------===// +// StmtPrinter Visitor +//===----------------------------------------------------------------------===// + +namespace { + class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor { + std::ostream &OS; + unsigned IndentLevel; + public: + StmtPrinter(std::ostream &os) : OS(os), IndentLevel(0) {} + + void PrintStmt(Stmt *S, int SubIndent = 1) { + IndentLevel += SubIndent; + if (S && isa<Expr>(S)) { + // If this is an expr used in a stmt context, indent and newline it. + Indent(); + S->visit(*this); + OS << ";\n"; + } else if (S) { + S->visit(*this); + } else { + Indent() << "<<<NULL STATEMENT>>>\n"; + } + IndentLevel -= SubIndent; + } + + void PrintRawCompoundStmt(CompoundStmt *S); + void PrintRawDecl(Decl *D); + void PrintRawIfStmt(IfStmt *If); + + void PrintExpr(Expr *E) { + if (E) + E->visit(*this); + else + OS << "<null expr>"; + } + + std::ostream &Indent(int Delta = 0) const { + for (int i = 0, e = IndentLevel+Delta; i < e; ++i) + OS << " "; + return OS; + } + + virtual void VisitStmt(Stmt *Node); +#define STMT(N, CLASS, PARENT) \ + virtual void Visit##CLASS(CLASS *Node); +#include "clang/AST/StmtNodes.def" + }; +} + +//===----------------------------------------------------------------------===// +// Stmt printing methods. +//===----------------------------------------------------------------------===// + +void StmtPrinter::VisitStmt(Stmt *Node) { + Indent() << "<<unknown stmt type>>\n"; +} + +/// PrintRawCompoundStmt - Print a compound stmt without indenting the {, and +/// with no newline after the }. +void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) { + OS << "{\n"; + for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end(); + I != E; ++I) + PrintStmt(*I); + + Indent() << "}"; +} + +void StmtPrinter::PrintRawDecl(Decl *D) { + // FIXME: Need to complete/beautify this... this code simply shows the + // nodes are where they need to be. + if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) { + OS << "typedef " << localType->getUnderlyingType().getAsString(); + OS << " " << localType->getName(); + } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + // Emit storage class for vardecls. + if (VarDecl *V = dyn_cast<VarDecl>(VD)) { + switch (V->getStorageClass()) { + default: assert(0 && "Unknown storage class!"); + case VarDecl::None: break; + case VarDecl::Extern: OS << "extern "; break; + case VarDecl::Static: OS << "static "; break; + case VarDecl::Auto: OS << "auto "; break; + case VarDecl::Register: OS << "register "; break; + } + } + + std::string Name = VD->getName(); + VD->getType().getAsStringInternal(Name); + OS << Name; + + // FIXME: Initializer for vardecl + } else { + // FIXME: "struct x;" + assert(0 && "Unexpected decl"); + } +} + + +void StmtPrinter::VisitNullStmt(NullStmt *Node) { + Indent() << ";\n"; +} + +void StmtPrinter::VisitDeclStmt(DeclStmt *Node) { + for (Decl *D = Node->getDecl(); D; D = D->getNextDeclarator()) { + Indent(); + PrintRawDecl(D); + OS << ";\n"; + } +} + +void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) { + Indent(); + PrintRawCompoundStmt(Node); + OS << "\n"; +} + +void StmtPrinter::VisitCaseStmt(CaseStmt *Node) { + Indent(-1) << "case "; + PrintExpr(Node->getLHS()); + if (Node->getRHS()) { + OS << " ... "; + PrintExpr(Node->getRHS()); + } + OS << ":\n"; + + PrintStmt(Node->getSubStmt(), 0); +} + +void StmtPrinter::VisitDefaultStmt(DefaultStmt *Node) { + Indent(-1) << "default:\n"; + PrintStmt(Node->getSubStmt(), 0); +} + +void StmtPrinter::VisitLabelStmt(LabelStmt *Node) { + Indent(-1) << Node->getName() << ":\n"; + PrintStmt(Node->getSubStmt(), 0); +} + +void StmtPrinter::PrintRawIfStmt(IfStmt *If) { + OS << "if "; + PrintExpr(If->getCond()); + + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) { + OS << ' '; + PrintRawCompoundStmt(CS); + OS << (If->getElse() ? ' ' : '\n'); + } else { + OS << '\n'; + PrintStmt(If->getThen()); + if (If->getElse()) Indent(); + } + + if (Stmt *Else = If->getElse()) { + OS << "else"; + + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Else)) { + OS << ' '; + PrintRawCompoundStmt(CS); + OS << '\n'; + } else if (IfStmt *ElseIf = dyn_cast<IfStmt>(Else)) { + OS << ' '; + PrintRawIfStmt(ElseIf); + } else { + OS << '\n'; + PrintStmt(If->getElse()); + } + } +} + +void StmtPrinter::VisitIfStmt(IfStmt *If) { + Indent(); + PrintRawIfStmt(If); +} + +void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) { + Indent() << "switch ("; + PrintExpr(Node->getCond()); + OS << ")"; + + // Pretty print compoundstmt bodies (very common). + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { + OS << " "; + PrintRawCompoundStmt(CS); + OS << "\n"; + } else { + OS << "\n"; + PrintStmt(Node->getBody()); + } +} + +void StmtPrinter::VisitWhileStmt(WhileStmt *Node) { + Indent() << "while ("; + PrintExpr(Node->getCond()); + OS << ")\n"; + PrintStmt(Node->getBody()); +} + +void StmtPrinter::VisitDoStmt(DoStmt *Node) { + Indent() << "do\n"; + PrintStmt(Node->getBody()); + Indent() << "while "; + PrintExpr(Node->getCond()); + OS << ";\n"; +} + +void StmtPrinter::VisitForStmt(ForStmt *Node) { + Indent() << "for ("; + if (Node->getInit()) { + if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getInit())) + PrintRawDecl(DS->getDecl()); + else + PrintExpr(cast<Expr>(Node->getInit())); + } + OS << "; "; + if (Node->getCond()) + PrintExpr(Node->getCond()); + OS << "; "; + if (Node->getInc()) + PrintExpr(Node->getInc()); + OS << ")\n"; + PrintStmt(Node->getBody()); +} + +void StmtPrinter::VisitGotoStmt(GotoStmt *Node) { + Indent() << "goto " << Node->getLabel()->getName() << ";\n"; +} + +void StmtPrinter::VisitIndirectGotoStmt(IndirectGotoStmt *Node) { + Indent() << "goto *"; + PrintExpr(Node->getTarget()); + OS << ";\n"; +} + +void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) { + Indent() << "continue;\n"; +} + +void StmtPrinter::VisitBreakStmt(BreakStmt *Node) { + Indent() << "break;\n"; +} + + +void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) { + Indent() << "return"; + if (Node->getRetValue()) { + OS << " "; + PrintExpr(Node->getRetValue()); + } + OS << ";\n"; +} + +//===----------------------------------------------------------------------===// +// Expr printing methods. +//===----------------------------------------------------------------------===// + +void StmtPrinter::VisitExpr(Expr *Node) { + OS << "<<unknown expr type>>"; +} + +void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { + OS << Node->getDecl()->getName(); +} + +void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) { + // FIXME: print value. + OS << "x"; +} + +void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { + bool isSigned = Node->getType()->isSignedIntegerType(); + OS << Node->getValue().toString(10, isSigned); + + // Emit suffixes. Integer literals are always a builtin integer type. + switch (cast<BuiltinType>(Node->getType().getCanonicalType())->getKind()) { + default: assert(0 && "Unexpected type for integer literal!"); + case BuiltinType::Int: break; // no suffix. + case BuiltinType::UInt: OS << 'U'; break; + case BuiltinType::Long: OS << 'L'; break; + case BuiltinType::ULong: OS << "UL"; break; + case BuiltinType::LongLong: OS << "LL"; break; + case BuiltinType::ULongLong: OS << "ULL"; break; + } +} +void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) { + // FIXME: print value. + OS << "~1.0~"; +} +void StmtPrinter::VisitStringLiteral(StringLiteral *Str) { + if (Str->isWide()) OS << 'L'; + OS << '"'; + + // FIXME: this doesn't print wstrings right. + for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { + switch (Str->getStrData()[i]) { + default: OS << Str->getStrData()[i]; break; + // Handle some common ones to make dumps prettier. + case '\\': OS << "\\\\"; break; + case '"': OS << "\\\""; break; + case '\n': OS << "\\n"; break; + case '\t': OS << "\\t"; break; + case '\a': OS << "\\a"; break; + case '\b': OS << "\\b"; break; + } + } + OS << '"'; +} +void StmtPrinter::VisitParenExpr(ParenExpr *Node) { + OS << "("; + PrintExpr(Node->getSubExpr()); + OS << ")"; +} +void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) { + if (!Node->isPostfix()) + OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); + PrintExpr(Node->getSubExpr()); + + if (Node->isPostfix()) + OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); + +} +void StmtPrinter::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) { + OS << (Node->isSizeOf() ? "sizeof(" : "__alignof("); + OS << Node->getArgumentType().getAsString() << ")"; +} +void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) { + PrintExpr(Node->getBase()); + OS << "["; + PrintExpr(Node->getIdx()); + OS << "]"; +} + +void StmtPrinter::VisitCallExpr(CallExpr *Call) { + PrintExpr(Call->getCallee()); + OS << "("; + for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) { + if (i) OS << ", "; + PrintExpr(Call->getArg(i)); + } + OS << ")"; +} +void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + + FieldDecl *Field = Node->getMemberDecl(); + assert(Field && "MemberExpr should alway reference a field!"); + OS << Field->getName(); +} +void StmtPrinter::VisitCastExpr(CastExpr *Node) { + OS << "(" << Node->getDestType().getAsString() << ")"; + PrintExpr(Node->getSubExpr()); +} +void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) { + PrintExpr(Node->getLHS()); + OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " "; + PrintExpr(Node->getRHS()); +} +void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) { + PrintExpr(Node->getCond()); + OS << " ? "; + PrintExpr(Node->getLHS()); + OS << " : "; + PrintExpr(Node->getRHS()); +} + +// GNU extensions. + +void StmtPrinter::VisitAddrLabel(AddrLabel *Node) { + OS << "&&" << Node->getLabel()->getName(); + +} + +// C++ + +void StmtPrinter::VisitCXXCastExpr(CXXCastExpr *Node) { + switch (Node->getOpcode()) { + default: + assert(0 && "Not a C++ cast expression"); + abort(); + case CXXCastExpr::ConstCast: OS << "const_cast<"; break; + case CXXCastExpr::DynamicCast: OS << "dynamic_cast<"; break; + case CXXCastExpr::ReinterpretCast: OS << "reinterpret_cast<"; break; + case CXXCastExpr::StaticCast: OS << "static_cast<"; break; + } + + OS << Node->getDestType().getAsString() << ">("; + PrintExpr(Node->getSubExpr()); + OS << ")"; +} + +void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { + OS << (Node->getValue() ? "true" : "false"); +} + + +//===----------------------------------------------------------------------===// +// Stmt method implementations +//===----------------------------------------------------------------------===// + +void Stmt::dump() const { + // FIXME: eliminate use of <iostream> + print(std::cerr); +} + +void Stmt::print(std::ostream &OS) const { + if (this == 0) { + OS << "<NULL>"; + return; + } + + StmtPrinter P(OS); + const_cast<Stmt*>(this)->visit(P); +} diff --git a/AST/StmtVisitor.cpp b/AST/StmtVisitor.cpp new file mode 100644 index 0000000000..9171ef7566 --- /dev/null +++ b/AST/StmtVisitor.cpp @@ -0,0 +1,26 @@ +//===--- StmtVisitor.cpp - Visitor for Stmt subclasses --------------------===// +// +// 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 StmtVisitor class. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/ExprCXX.h" +using namespace clang; + +StmtVisitor::~StmtVisitor() { + // Out-of-line virtual dtor. +} + +// Implement all of the delegation visitor methods. +#define STMT(N, FROM, TO) \ + void StmtVisitor::Visit##FROM(FROM *Node) { Visit##TO(Node); } +#include "clang/AST/StmtNodes.def" + diff --git a/AST/Type.cpp b/AST/Type.cpp new file mode 100644 index 0000000000..cd06c7e783 --- /dev/null +++ b/AST/Type.cpp @@ -0,0 +1,593 @@ +//===--- Type.cpp - Type representation and manipulation ------------------===// +// +// 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 type-related functionality. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/IdentifierTable.h" +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/Support/Streams.h" +#include "llvm/ADT/StringExtras.h" +using namespace clang; + +Type::~Type() {} + +/// isVoidType - Helper method to determine if this is the 'void' type. +bool Type::isVoidType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Void; + return false; +} + +bool Type::isObjectType() const { + if (isa<FunctionType>(CanonicalType)) + return false; + else if (CanonicalType->isIncompleteType()) + return false; + else + return true; +} + +bool Type::isDerivedType() const { + switch (CanonicalType->getTypeClass()) { + case Pointer: + case Array: + case FunctionProto: + case FunctionNoProto: + case Reference: + return true; + case Tagged: { + const TagType *TT = cast<TagType>(CanonicalType); + const Decl::Kind Kind = TT->getDecl()->getKind(); + return Kind == Decl::Struct || Kind == Decl::Union; + } + default: + return false; + } +} + +bool Type::isFunctionType() const { + return isa<FunctionType>(CanonicalType); +} + +bool Type::isPointerType() const { + return isa<PointerType>(CanonicalType); +} + +bool Type::isReferenceType() const { + return isa<ReferenceType>(CanonicalType); +} + +bool Type::isArrayType() const { + return isa<ArrayType>(CanonicalType); +} + +bool Type::isStructureType() const { + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) { + if (TT->getDecl()->getKind() == Decl::Struct) + return true; + } + return false; +} + +bool Type::isUnionType() const { + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) { + if (TT->getDecl()->getKind() == Decl::Union) + 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 Type::tagTypesAreCompatible(QualType lhs, QualType rhs) { + TagDecl *ldecl = cast<TagType>(lhs.getCanonicalType())->getDecl(); + TagDecl *rdecl = cast<TagType>(rhs.getCanonicalType())->getDecl(); + + if (ldecl->getKind() == Decl::Struct && rdecl->getKind() == Decl::Struct) { + if (ldecl->getIdentifier() == rdecl->getIdentifier()) + return true; + } + if (ldecl->getKind() == Decl::Union && rdecl->getKind() == Decl::Union) { + if (ldecl->getIdentifier() == rdecl->getIdentifier()) + return true; + } + return false; +} + +bool Type::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.getQualifiers() != rhs.getQualifiers()) + 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 opperand of an assignment operator denotes a +// reference to T, the operation assigns to the object of type T denoted by the +// reference. +bool Type::referenceTypesAreCompatible(QualType lhs, QualType rhs) { + QualType ltype = lhs; + + if (lhs->isReferenceType()) + ltype = cast<ReferenceType>(lhs.getCanonicalType())->getReferenceeType(); + + QualType rtype = rhs; + + if (rhs->isReferenceType()) + rtype = cast<ReferenceType>(rhs.getCanonicalType())->getReferenceeType(); + + return typesAreCompatible(ltype, rtype); +} + +bool Type::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++) + if (!typesAreCompatible(lproto->getArgType(i), rproto->getArgType(i))) + 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 Type::arrayTypesAreCompatible(QualType lhs, QualType rhs) { + QualType ltype = cast<ArrayType>(lhs.getCanonicalType())->getElementType(); + QualType rtype = cast<ArrayType>(rhs.getCanonicalType())->getElementType(); + + if (!typesAreCompatible(ltype, rtype)) + return false; + + // FIXME: If both types specify constant sizes, then the sizes must also be + // the same. Even if the sizes are the same, GCC produces an error. + 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 Type::typesAreCompatible(QualType lhs, QualType rhs) { + QualType lcanon = lhs.getCanonicalType(); + QualType rcanon = rhs.getCanonicalType(); + + // If two types are identical, they are are compatible + if (lcanon == rcanon) + return true; + + // If the canonical type classes don't match, they can't be compatible + if (lcanon->getTypeClass() != rcanon->getTypeClass()) + return false; + + switch (lcanon->getTypeClass()) { + case Type::Pointer: + return pointerTypesAreCompatible(lcanon, rcanon); + case Type::Reference: + return referenceTypesAreCompatible(lcanon, rcanon); + case Type::Array: + return arrayTypesAreCompatible(lcanon, rcanon); + case Type::FunctionNoProto: + case Type::FunctionProto: + return functionTypesAreCompatible(lcanon, rcanon); + case Type::Tagged: // handle structures, unions + return tagTypesAreCompatible(lcanon, rcanon); + case Type::Builtin: + return false; + default: + assert(0 && "unexpected type"); + } + return true; // should never get here... +} + +bool Type::isIntegerType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::LongLong; + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) + if (TT->getDecl()->getKind() == Decl::Enum) + return true; + return false; +} + +bool Type::isSignedIntegerType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + return BT->getKind() >= BuiltinType::Char_S && + BT->getKind() <= BuiltinType::LongLong; + } + return false; +} + +bool Type::isUnsignedIntegerType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::ULongLong; + } + return false; +} + +bool Type::isFloatingType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Float && + BT->getKind() <= BuiltinType::LongDouble; + if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType)) + return CT->isFloatingType(); + return false; +} + +bool Type::isRealFloatingType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Float && + BT->getKind() <= BuiltinType::LongDouble; + return false; +} + +bool Type::isRealType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::LongDouble; + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) + return TT->getDecl()->getKind() == Decl::Enum; + return false; +} + +bool Type::isComplexType() const { + return isa<ComplexType>(CanonicalType); +} + +bool Type::isVectorType() const { + return isa<VectorType>(CanonicalType); +} + +bool Type::isArithmeticType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() != BuiltinType::Void; + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) + if (TT->getDecl()->getKind() == Decl::Enum) + return true; + return isa<ComplexType>(CanonicalType) || isa<VectorType>(CanonicalType); +} + +bool Type::isScalarType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() != BuiltinType::Void; + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) { + if (TT->getDecl()->getKind() == Decl::Enum) + return true; + return false; + } + return isa<PointerType>(CanonicalType) || isa<ComplexType>(CanonicalType); +} + +bool Type::isAggregateType() const { + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) { + if (TT->getDecl()->getKind() == Decl::Struct) + return true; + return false; + } + return CanonicalType->getTypeClass() == Array; +} + +// The only variable size types are auto arrays within a function. Structures +// cannot contain a VLA member. They can have a flexible array member, however +// the structure is still constant size (C99 6.7.2.1p16). +bool Type::isConstantSizeType(SourceLocation *loc) const { + if (const ArrayType *Ary = dyn_cast<ArrayType>(CanonicalType)) { + assert(Ary->getSize() && "Incomplete types don't have a size at all!"); + return Ary->getSize()->isIntegerConstantExpr(loc); // Variable Length Array? + } + return true; +} + +/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1) +/// - a type that can describe objects, but which lacks information needed to +/// determine its size. +bool Type::isIncompleteType() const { + switch (CanonicalType->getTypeClass()) { + default: return false; + case Builtin: + // Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never + // be completed. + return isVoidType(); + case Tagged: + // A tagged type (struct/union/enum/class) is incomplete if the decl is a + // forward declaration, but not a full definition (C99 6.2.5p22). + return !cast<TagType>(CanonicalType)->getDecl()->isDefinition(); + case Array: + // An array of unknown size is an incomplete type (C99 6.2.5p22). + return cast<ArrayType>(CanonicalType)->getSize() == 0; + } +} + +bool Type::isPromotableIntegerType() const { + const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType); + if (!BT) return false; + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::Short: + case BuiltinType::UShort: + return true; + default: + return false; + } +} + +const char *BuiltinType::getName() const { + switch (getKind()) { + default: assert(0 && "Unknown builtin type!"); + case Void: return "void"; + case Bool: return "_Bool"; + case Char_S: return "char"; + case Char_U: return "char"; + case SChar: return "signed char"; + case Short: return "short"; + case Int: return "int"; + case Long: return "long"; + case LongLong: return "long long"; + case UChar: return "unsigned char"; + case UShort: return "unsigned short"; + case UInt: return "unsigned int"; + case ULong: return "unsigned long"; + case ULongLong: return "unsigned long long"; + case Float: return "float"; + case Double: return "double"; + case LongDouble: return "long double"; + } +} + +// FIXME: need to use TargetInfo to derive the target specific sizes. This +// implementation will suffice for play with vector support. +unsigned BuiltinType::getSize() const { + switch (getKind()) { + default: assert(0 && "Unknown builtin type!"); + case Void: return 0; + case Bool: + case Char_S: + case Char_U: return sizeof(char) * 8; + case SChar: return sizeof(signed char) * 8; + case Short: return sizeof(short) * 8; + case Int: return sizeof(int) * 8; + case Long: return sizeof(long) * 8; + case LongLong: return sizeof(long long) * 8; + case UChar: return sizeof(unsigned char) * 8; + case UShort: return sizeof(unsigned short) * 8; + case UInt: return sizeof(unsigned int) * 8; + case ULong: return sizeof(unsigned long) * 8; + case ULongLong: return sizeof(unsigned long long) * 8; + case Float: return sizeof(float) * 8; + case Double: return sizeof(double) * 8; + case LongDouble: return sizeof(long double) * 8; + } +} + +void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID, QualType Result, + QualType* ArgTys, + unsigned NumArgs, bool isVariadic) { + ID.AddPointer(Result.getAsOpaquePtr()); + for (unsigned i = 0; i != NumArgs; ++i) + ID.AddPointer(ArgTys[i].getAsOpaquePtr()); + ID.AddInteger(isVariadic); +} + +void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getResultType(), ArgInfo, NumArgs, isVariadic()); +} + + +bool RecordType::classof(const Type *T) { + if (const TagType *TT = dyn_cast<TagType>(T)) + return isa<RecordDecl>(TT->getDecl()); + return false; +} + + +//===----------------------------------------------------------------------===// +// Type Printing +//===----------------------------------------------------------------------===// + +void QualType::dump(const char *msg) const { + std::string R = "foo"; + getAsStringInternal(R); + if (msg) + fprintf(stderr, "%s: %s\n", msg, R.c_str()); + else + fprintf(stderr, "%s\n", R.c_str()); +} + +static void AppendTypeQualList(std::string &S, unsigned TypeQuals) { + // Note: funkiness to ensure we get a space only between quals. + bool NonePrinted = true; + if (TypeQuals & QualType::Const) + S += "const", NonePrinted = false; + if (TypeQuals & QualType::Volatile) + S += (NonePrinted+" volatile"), NonePrinted = false; + if (TypeQuals & QualType::Restrict) + S += (NonePrinted+" restrict"), NonePrinted = false; +} + +void QualType::getAsStringInternal(std::string &S) const { + if (isNull()) { + S += "NULL TYPE\n"; + return; + } + + // Print qualifiers as appropriate. + if (unsigned TQ = getQualifiers()) { + std::string TQS; + AppendTypeQualList(TQS, TQ); + if (!S.empty()) + S = TQS + ' ' + S; + else + S = TQS; + } + + getTypePtr()->getAsStringInternal(S); +} + +void BuiltinType::getAsStringInternal(std::string &S) const { + if (S.empty()) { + S = getName(); + } else { + // Prefix the basic type, e.g. 'int X'. + S = ' ' + S; + S = getName() + S; + } +} + +void ComplexType::getAsStringInternal(std::string &S) const { + ElementType->getAsStringInternal(S); + S = "_Complex " + S; +} + +void PointerType::getAsStringInternal(std::string &S) const { + S = '*' + S; + + // Handle things like 'int (*A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(PointeeType.getTypePtr())) + S = '(' + S + ')'; + + PointeeType.getAsStringInternal(S); +} + +void ReferenceType::getAsStringInternal(std::string &S) const { + S = '&' + S; + + // Handle things like 'int (&A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(ReferenceeType.getTypePtr())) + S = '(' + S + ')'; + + ReferenceeType.getAsStringInternal(S); +} + +void ArrayType::getAsStringInternal(std::string &S) const { + S += '['; + + if (IndexTypeQuals) { + AppendTypeQualList(S, IndexTypeQuals); + S += ' '; + } + + if (SizeModifier == Static) + S += "static"; + else if (SizeModifier == Star) + S += '*'; + + S += ']'; + + ElementType.getAsStringInternal(S); +} + +void VectorType::getAsStringInternal(std::string &S) const { + S += " __attribute__(( vector_size("; + // FIXME: handle types that are != 32 bits. + S += llvm::utostr_32(NumElements*4); // convert back to bytes. + S += ") ))"; + ElementType.getAsStringInternal(S); +} + +void FunctionTypeNoProto::getAsStringInternal(std::string &S) const { + // If needed for precedence reasons, wrap the inner part in grouping parens. + if (!S.empty()) + S = "(" + S + ")"; + + S += "()"; + getResultType().getAsStringInternal(S); +} + +void FunctionTypeProto::getAsStringInternal(std::string &S) const { + // If needed for precedence reasons, wrap the inner part in grouping parens. + if (!S.empty()) + S = "(" + S + ")"; + + S += "("; + std::string Tmp; + for (unsigned i = 0, e = getNumArgs(); i != e; ++i) { + if (i) S += ", "; + getArgType(i).getAsStringInternal(Tmp); + S += Tmp; + Tmp.clear(); + } + + if (isVariadic()) { + if (getNumArgs()) + S += ", "; + S += "..."; + } else if (getNumArgs() == 0) { + // Do not emit int() if we have a proto, emit 'int(void)'. + S += "void"; + } + + S += ")"; + getResultType().getAsStringInternal(S); +} + + +void TypedefType::getAsStringInternal(std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + InnerString = getDecl()->getIdentifier()->getName() + InnerString; +} + +void TagType::getAsStringInternal(std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + + const char *Kind = getDecl()->getKindName(); + const char *ID; + if (const IdentifierInfo *II = getDecl()->getIdentifier()) + ID = II->getName(); + else + ID = "<anonymous>"; + + InnerString = std::string(Kind) + " " + ID + InnerString; +} |