Compare commits
21 Commits
llvmorg-3.
...
llvmorg-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58b88bd03f | ||
|
|
0f4473a782 | ||
|
|
53b947dca9 | ||
|
|
ad20748b55 | ||
|
|
55c4ece2d6 | ||
|
|
df68032d8e | ||
|
|
97f6d583c4 | ||
|
|
90e8d3d40f | ||
|
|
a7ebb6acd0 | ||
|
|
eb9b0330a1 | ||
|
|
9641951f9c | ||
|
|
23a93dc404 | ||
|
|
eb100b667d | ||
|
|
a4fce9bd7a | ||
|
|
d042361a6e | ||
|
|
03069ea1d8 | ||
|
|
5a2ed42a74 | ||
|
|
adef84650d | ||
|
|
34425ff239 | ||
|
|
0f7f44c3b5 | ||
|
|
7eb310a899 |
@@ -1,800 +0,0 @@
|
|||||||
//===--- 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 NumVector = 0, NumComplex = 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<ComplexType>(T))
|
|
||||||
++NumComplex;
|
|
||||||
else if (isa<ArrayType>(T))
|
|
||||||
++NumArray;
|
|
||||||
else if (isa<VectorType>(T))
|
|
||||||
++NumVector;
|
|
||||||
else if (isa<FunctionTypeNoProto>(T))
|
|
||||||
++NumFunctionNP;
|
|
||||||
else if (isa<FunctionTypeProto>(T))
|
|
||||||
++NumFunctionP;
|
|
||||||
else if (isa<TypedefType>(T))
|
|
||||||
++NumTypeName;
|
|
||||||
else if (TagType *TT = dyn_cast<TagType>(T)) {
|
|
||||||
++NumTagged;
|
|
||||||
switch (TT->getDecl()->getKind()) {
|
|
||||||
default: assert(0 && "Unknown tagged type!");
|
|
||||||
case Decl::Struct: ++NumTagStruct; break;
|
|
||||||
case Decl::Union: ++NumTagUnion; break;
|
|
||||||
case Decl::Class: ++NumTagClass; break;
|
|
||||||
case Decl::Enum: ++NumTagEnum; break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert(0 && "Unknown type!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, " %d builtin types\n", NumBuiltin);
|
|
||||||
fprintf(stderr, " %d pointer types\n", NumPointer);
|
|
||||||
fprintf(stderr, " %d reference types\n", NumReference);
|
|
||||||
fprintf(stderr, " %d complex types\n", NumComplex);
|
|
||||||
fprintf(stderr, " %d array types\n", NumArray);
|
|
||||||
fprintf(stderr, " %d vector types\n", NumVector);
|
|
||||||
fprintf(stderr, " %d function types with proto\n", NumFunctionP);
|
|
||||||
fprintf(stderr, " %d function types with no proto\n", NumFunctionNP);
|
|
||||||
fprintf(stderr, " %d typename (typedef) types\n", NumTypeName);
|
|
||||||
fprintf(stderr, " %d tagged types\n", NumTagged);
|
|
||||||
fprintf(stderr, " %d struct types\n", NumTagStruct);
|
|
||||||
fprintf(stderr, " %d union types\n", NumTagUnion);
|
|
||||||
fprintf(stderr, " %d class types\n", NumTagClass);
|
|
||||||
fprintf(stderr, " %d enum types\n", NumTagEnum);
|
|
||||||
fprintf(stderr, "Total bytes = %d\n", int(NumBuiltin*sizeof(BuiltinType)+
|
|
||||||
NumPointer*sizeof(PointerType)+NumArray*sizeof(ArrayType)+
|
|
||||||
NumComplex*sizeof(ComplexType)+NumVector*sizeof(VectorType)+
|
|
||||||
NumFunctionP*sizeof(FunctionTypeProto)+
|
|
||||||
NumFunctionNP*sizeof(FunctionTypeNoProto)+
|
|
||||||
NumTypeName*sizeof(TypedefType)+NumTagged*sizeof(TagType)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) {
|
|
||||||
Types.push_back((R = QualType(new BuiltinType(K),0)).getTypePtr());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ASTContext::InitBuiltinTypes() {
|
|
||||||
assert(VoidTy.isNull() && "Context reinitialized?");
|
|
||||||
|
|
||||||
// C99 6.2.5p19.
|
|
||||||
InitBuiltinType(VoidTy, BuiltinType::Void);
|
|
||||||
|
|
||||||
// C99 6.2.5p2.
|
|
||||||
InitBuiltinType(BoolTy, BuiltinType::Bool);
|
|
||||||
// C99 6.2.5p3.
|
|
||||||
if (Target.isCharSigned(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Type Sizing and Analysis
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// getTypeSize - Return the size of the specified type, in bits. This method
|
|
||||||
/// does not work on incomplete types.
|
|
||||||
std::pair<uint64_t, unsigned>
|
|
||||||
ASTContext::getTypeInfo(QualType T, SourceLocation L) {
|
|
||||||
T = T.getCanonicalType();
|
|
||||||
uint64_t Size;
|
|
||||||
unsigned Align;
|
|
||||||
switch (T->getTypeClass()) {
|
|
||||||
case Type::TypeName: assert(0 && "Not a canonical type!");
|
|
||||||
case Type::FunctionNoProto:
|
|
||||||
case Type::FunctionProto:
|
|
||||||
default:
|
|
||||||
assert(0 && "Incomplete types have no size!");
|
|
||||||
case Type::VariableArray:
|
|
||||||
assert(0 && "VLAs not implemented yet!");
|
|
||||||
case Type::ConstantArray: {
|
|
||||||
ConstantArrayType *CAT = cast<ConstantArrayType>(T);
|
|
||||||
|
|
||||||
std::pair<uint64_t, unsigned> EltInfo =
|
|
||||||
getTypeInfo(CAT->getElementType(), L);
|
|
||||||
Size = EltInfo.first*CAT->getSize().getZExtValue();
|
|
||||||
Align = EltInfo.second;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Type::Vector: {
|
|
||||||
std::pair<uint64_t, unsigned> EltInfo =
|
|
||||||
getTypeInfo(cast<VectorType>(T)->getElementType(), L);
|
|
||||||
Size = EltInfo.first*cast<VectorType>(T)->getNumElements();
|
|
||||||
// FIXME: Vector alignment is not the alignment of its elements.
|
|
||||||
Align = EltInfo.second;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Type::Builtin: {
|
|
||||||
// FIXME: need to use TargetInfo to derive the target specific sizes. This
|
|
||||||
// implementation will suffice for play with vector support.
|
|
||||||
switch (cast<BuiltinType>(T)->getKind()) {
|
|
||||||
default: assert(0 && "Unknown builtin type!");
|
|
||||||
case BuiltinType::Void:
|
|
||||||
assert(0 && "Incomplete types have no size!");
|
|
||||||
case BuiltinType::Bool: Target.getBoolInfo(Size, Align, L); break;
|
|
||||||
case BuiltinType::Char_S:
|
|
||||||
case BuiltinType::Char_U:
|
|
||||||
case BuiltinType::UChar:
|
|
||||||
case BuiltinType::SChar: Target.getCharInfo(Size, Align, L); break;
|
|
||||||
case BuiltinType::UShort:
|
|
||||||
case BuiltinType::Short: Target.getShortInfo(Size, Align, L); break;
|
|
||||||
case BuiltinType::UInt:
|
|
||||||
case BuiltinType::Int: Target.getIntInfo(Size, Align, L); break;
|
|
||||||
case BuiltinType::ULong:
|
|
||||||
case BuiltinType::Long: Target.getLongInfo(Size, Align, L); break;
|
|
||||||
case BuiltinType::ULongLong:
|
|
||||||
case BuiltinType::LongLong: Target.getLongLongInfo(Size, Align, L); break;
|
|
||||||
case BuiltinType::Float: Target.getFloatInfo(Size, Align, L); break;
|
|
||||||
case BuiltinType::Double: Target.getDoubleInfo(Size, Align, L); break;
|
|
||||||
case BuiltinType::LongDouble: Target.getLongDoubleInfo(Size, Align,L);break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Type::Pointer: Target.getPointerInfo(Size, Align, L); break;
|
|
||||||
case Type::Reference:
|
|
||||||
// "When applied to a reference or a reference type, the result is the size
|
|
||||||
// of the referenced type." C++98 5.3.3p2: expr.sizeof.
|
|
||||||
// FIXME: This is wrong for struct layout!
|
|
||||||
return getTypeInfo(cast<ReferenceType>(T)->getReferenceeType(), L);
|
|
||||||
|
|
||||||
case Type::Complex: {
|
|
||||||
// Complex types have the same alignment as their elements, but twice the
|
|
||||||
// size.
|
|
||||||
std::pair<uint64_t, unsigned> EltInfo =
|
|
||||||
getTypeInfo(cast<ComplexType>(T)->getElementType(), L);
|
|
||||||
Size = EltInfo.first*2;
|
|
||||||
Align = EltInfo.second;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Type::Tagged:
|
|
||||||
TagType *TT = cast<TagType>(T);
|
|
||||||
if (RecordType *RT = dyn_cast<RecordType>(TT)) {
|
|
||||||
const RecordLayout &Layout = getRecordLayout(RT->getDecl(), L);
|
|
||||||
Size = Layout.getSize();
|
|
||||||
Align = Layout.getAlignment();
|
|
||||||
} else if (EnumDecl *ED = dyn_cast<EnumDecl>(TT->getDecl())) {
|
|
||||||
return getTypeInfo(ED->getIntegerType(), L);
|
|
||||||
} else {
|
|
||||||
assert(0 && "Unimplemented type sizes!");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2");
|
|
||||||
return std::make_pair(Size, Align);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getRecordLayout - Get or compute information about the layout of the
|
|
||||||
/// specified record (struct/union/class), which indicates its size and field
|
|
||||||
/// position information.
|
|
||||||
const RecordLayout &ASTContext::getRecordLayout(const RecordDecl *D,
|
|
||||||
SourceLocation L) {
|
|
||||||
assert(D->isDefinition() && "Cannot get layout of forward declarations!");
|
|
||||||
|
|
||||||
// Look up this layout, if already laid out, return what we have.
|
|
||||||
const RecordLayout *&Entry = RecordLayoutInfo[D];
|
|
||||||
if (Entry) return *Entry;
|
|
||||||
|
|
||||||
// Allocate and assign into RecordLayoutInfo here. The "Entry" reference can
|
|
||||||
// be invalidated (dangle) if the RecordLayoutInfo hashtable is inserted into.
|
|
||||||
RecordLayout *NewEntry = new RecordLayout();
|
|
||||||
Entry = NewEntry;
|
|
||||||
|
|
||||||
uint64_t *FieldOffsets = new uint64_t[D->getNumMembers()];
|
|
||||||
uint64_t RecordSize = 0;
|
|
||||||
unsigned RecordAlign = 8; // Default alignment = 1 byte = 8 bits.
|
|
||||||
|
|
||||||
if (D->getKind() != Decl::Union) {
|
|
||||||
// Layout each field, for now, just sequentially, respecting alignment. In
|
|
||||||
// the future, this will need to be tweakable by targets.
|
|
||||||
for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) {
|
|
||||||
const FieldDecl *FD = D->getMember(i);
|
|
||||||
std::pair<uint64_t, unsigned> FieldInfo = getTypeInfo(FD->getType(), L);
|
|
||||||
uint64_t FieldSize = FieldInfo.first;
|
|
||||||
unsigned FieldAlign = FieldInfo.second;
|
|
||||||
|
|
||||||
// Round up the current record size to the field's alignment boundary.
|
|
||||||
RecordSize = (RecordSize+FieldAlign-1) & ~(FieldAlign-1);
|
|
||||||
|
|
||||||
// Place this field at the current location.
|
|
||||||
FieldOffsets[i] = RecordSize;
|
|
||||||
|
|
||||||
// Reserve space for this field.
|
|
||||||
RecordSize += FieldSize;
|
|
||||||
|
|
||||||
// Remember max struct/class alignment.
|
|
||||||
RecordAlign = std::max(RecordAlign, FieldAlign);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, round the size of the total struct up to the alignment of the
|
|
||||||
// struct itself.
|
|
||||||
RecordSize = (RecordSize+RecordAlign-1) & ~(RecordAlign-1);
|
|
||||||
} else {
|
|
||||||
// Union layout just puts each member at the start of the record.
|
|
||||||
for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) {
|
|
||||||
const FieldDecl *FD = D->getMember(i);
|
|
||||||
std::pair<uint64_t, unsigned> FieldInfo = getTypeInfo(FD->getType(), L);
|
|
||||||
uint64_t FieldSize = FieldInfo.first;
|
|
||||||
unsigned FieldAlign = FieldInfo.second;
|
|
||||||
|
|
||||||
// Round up the current record size to the field's alignment boundary.
|
|
||||||
RecordSize = std::max(RecordSize, FieldSize);
|
|
||||||
|
|
||||||
// Place this field at the start of the record.
|
|
||||||
FieldOffsets[i] = 0;
|
|
||||||
|
|
||||||
// Remember max struct/class alignment.
|
|
||||||
RecordAlign = std::max(RecordAlign, FieldAlign);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NewEntry->SetLayout(RecordSize, RecordAlign, FieldOffsets);
|
|
||||||
return *NewEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Type creation/memoization methods
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
|
|
||||||
/// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getConstantArrayType - Return the unique reference to the type for an
|
|
||||||
/// array of the specified element type.
|
|
||||||
QualType ASTContext::getConstantArrayType(QualType EltTy,
|
|
||||||
const llvm::APInt &ArySize,
|
|
||||||
ArrayType::ArraySizeModifier ASM,
|
|
||||||
unsigned EltTypeQuals) {
|
|
||||||
llvm::FoldingSetNodeID ID;
|
|
||||||
ConstantArrayType::Profile(ID, EltTy, ArySize);
|
|
||||||
|
|
||||||
void *InsertPos = 0;
|
|
||||||
if (ConstantArrayType *ATP = 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 = getConstantArrayType(EltTy.getCanonicalType(), ArySize,
|
|
||||||
ASM, EltTypeQuals);
|
|
||||||
// Get the new insert position for the node we care about.
|
|
||||||
ConstantArrayType *NewIP = ArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
||||||
assert(NewIP == 0 && "Shouldn't be in the map!");
|
|
||||||
}
|
|
||||||
|
|
||||||
ConstantArrayType *New = new ConstantArrayType(EltTy, Canonical, ArySize,
|
|
||||||
ASM, EltTypeQuals);
|
|
||||||
ArrayTypes.InsertNode(New, InsertPos);
|
|
||||||
Types.push_back(New);
|
|
||||||
return QualType(New, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getVariableArrayType - Returns a non-unique reference to the type for a
|
|
||||||
/// variable array of the specified element type.
|
|
||||||
QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts,
|
|
||||||
ArrayType::ArraySizeModifier ASM,
|
|
||||||
unsigned EltTypeQuals) {
|
|
||||||
// Since we don't unique expressions, it isn't possible to unique VLA's.
|
|
||||||
ArrayType *New = new VariableArrayType(EltTy, QualType(), NumElts,
|
|
||||||
ASM, EltTypeQuals);
|
|
||||||
Types.push_back(New);
|
|
||||||
return QualType(New, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getVectorType - Return the unique reference to a vector type of
|
|
||||||
/// the specified element type and size. VectorType must be a built-in type.
|
|
||||||
QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) {
|
|
||||||
BuiltinType *baseType;
|
|
||||||
|
|
||||||
baseType = dyn_cast<BuiltinType>(vecType.getCanonicalType().getTypePtr());
|
|
||||||
assert(baseType != 0 && "getVectorType(): Expecting a built-in type");
|
|
||||||
|
|
||||||
// Check if we've already instantiated a vector of this type.
|
|
||||||
llvm::FoldingSetNodeID ID;
|
|
||||||
VectorType::Profile(ID, vecType, NumElts, Type::Vector);
|
|
||||||
void *InsertPos = 0;
|
|
||||||
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
|
|
||||||
return QualType(VTP, 0);
|
|
||||||
|
|
||||||
// If the element type isn't canonical, this won't be a canonical type either,
|
|
||||||
// so fill in the canonical type field.
|
|
||||||
QualType Canonical;
|
|
||||||
if (!vecType->isCanonical()) {
|
|
||||||
Canonical = getVectorType(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getOCUVectorType - Return the unique reference to an OCU vector type of
|
|
||||||
/// the specified element type and size. VectorType must be a built-in type.
|
|
||||||
QualType ASTContext::getOCUVectorType(QualType vecType, unsigned NumElts) {
|
|
||||||
BuiltinType *baseType;
|
|
||||||
|
|
||||||
baseType = dyn_cast<BuiltinType>(vecType.getCanonicalType().getTypePtr());
|
|
||||||
assert(baseType != 0 && "getOCUVectorType(): Expecting a built-in type");
|
|
||||||
|
|
||||||
// Check if we've already instantiated a vector of this type.
|
|
||||||
llvm::FoldingSetNodeID ID;
|
|
||||||
VectorType::Profile(ID, vecType, NumElts, Type::OCUVector);
|
|
||||||
void *InsertPos = 0;
|
|
||||||
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
|
|
||||||
return QualType(VTP, 0);
|
|
||||||
|
|
||||||
// If the element type isn't canonical, this won't be a canonical type either,
|
|
||||||
// so fill in the canonical type field.
|
|
||||||
QualType Canonical;
|
|
||||||
if (!vecType->isCanonical()) {
|
|
||||||
Canonical = getOCUVectorType(vecType.getCanonicalType(), NumElts);
|
|
||||||
|
|
||||||
// Get the new insert position for the node we care about.
|
|
||||||
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
||||||
assert(NewIP == 0 && "Shouldn't be in the map!");
|
|
||||||
}
|
|
||||||
OCUVectorType *New = new OCUVectorType(vecType, NumElts, Canonical);
|
|
||||||
VectorTypes.InsertNode(New, InsertPos);
|
|
||||||
Types.push_back(New);
|
|
||||||
return QualType(New, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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*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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getObjcInterfaceType - Return the unique reference to the type for the
|
|
||||||
/// specified ObjC interface decl.
|
|
||||||
QualType ASTContext::getObjcInterfaceType(ObjcInterfaceDecl *Decl) {
|
|
||||||
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
|
|
||||||
|
|
||||||
Decl->TypeForDecl = new ObjcInterfaceType(Decl);
|
|
||||||
Types.push_back(Decl->TypeForDecl);
|
|
||||||
return QualType(Decl->TypeForDecl, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getTypeOfExpr - Unlike many "get<Type>" functions, we can't unique
|
|
||||||
/// TypeOfExpr AST's (since expression's are never shared). For example,
|
|
||||||
/// multiple declarations that refer to "typeof(x)" all contain different
|
|
||||||
/// DeclRefExpr's. This doesn't effect the type checker, since it operates
|
|
||||||
/// on canonical type's (which are always unique).
|
|
||||||
QualType ASTContext::getTypeOfExpr(Expr *tofExpr) {
|
|
||||||
QualType Canonical = tofExpr->getType().getCanonicalType();
|
|
||||||
TypeOfExpr *toe = new TypeOfExpr(tofExpr, Canonical);
|
|
||||||
Types.push_back(toe);
|
|
||||||
return QualType(toe, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getTypeOfType - Unlike many "get<Type>" functions, we don't unique
|
|
||||||
/// TypeOfType AST's. The only motivation to unique these nodes would be
|
|
||||||
/// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be
|
|
||||||
/// an issue. This doesn't effect the type checker, since it operates
|
|
||||||
/// on canonical type's (which are always unique).
|
|
||||||
QualType ASTContext::getTypeOfType(QualType tofType) {
|
|
||||||
QualType Canonical = tofType.getCanonicalType();
|
|
||||||
TypeOfType *tot = new TypeOfType(tofType, Canonical);
|
|
||||||
Types.push_back(tot);
|
|
||||||
return QualType(tot, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getTagDeclType - Return the unique reference to the type for the
|
|
||||||
/// specified TagDecl (struct/union/class/enum) decl.
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?)
|
|
||||||
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
|
|
||||||
QualType ASTContext::getPointerDiffType() const {
|
|
||||||
// On Darwin, ptrdiff_t is defined as a "int". This seems like a bug...
|
|
||||||
// FIXME: should derive from "Target".
|
|
||||||
return IntTy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This
|
|
||||||
/// routine will assert if passed a built-in type that isn't an integer or enum.
|
|
||||||
static int getIntegerRank(QualType t) {
|
|
||||||
if (const TagType *TT = dyn_cast<TagType>(t.getCanonicalType())) {
|
|
||||||
assert(TT->getDecl()->getKind() == Decl::Enum && "not an int or enum");
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
const BuiltinType *BT = cast<BuiltinType>(t.getCanonicalType());
|
|
||||||
switch (BT->getKind()) {
|
|
||||||
default:
|
|
||||||
assert(0 && "getIntegerRank(): not a built-in integer");
|
|
||||||
case BuiltinType::Bool:
|
|
||||||
return 1;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getFloatingTypeOfSizeWithinDomain - Returns a real floating
|
|
||||||
/// point or a complex type (based on typeDomain/typeSize).
|
|
||||||
/// 'typeDomain' is a real floating point or complex type.
|
|
||||||
/// 'typeSize' is a real floating point or complex type.
|
|
||||||
QualType ASTContext::getFloatingTypeOfSizeWithinDomain(
|
|
||||||
QualType typeSize, QualType typeDomain) const {
|
|
||||||
if (typeDomain->isComplexType()) {
|
|
||||||
switch (getFloatingRank(typeSize)) {
|
|
||||||
default: assert(0 && "getFloatingRank(): illegal value for rank");
|
|
||||||
case FloatRank: return FloatComplexTy;
|
|
||||||
case DoubleRank: return DoubleComplexTy;
|
|
||||||
case LongDoubleRank: return LongDoubleComplexTy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (typeDomain->isRealFloatingType()) {
|
|
||||||
switch (getFloatingRank(typeSize)) {
|
|
||||||
default: assert(0 && "getFloatingRank(): illegal value for rank");
|
|
||||||
case FloatRank: return FloatTy;
|
|
||||||
case DoubleRank: return DoubleTy;
|
|
||||||
case LongDoubleRank: return LongDoubleTy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(0 && "getFloatingTypeOfSizeWithinDomain(): illegal domain");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// compareFloatingType - Handles 3 different combos:
|
|
||||||
/// float/float, float/complex, complex/complex.
|
|
||||||
/// If lt > rt, return 1. If lt == rt, return 0. If lt < rt, return -1.
|
|
||||||
int ASTContext::compareFloatingType(QualType lt, QualType rt) {
|
|
||||||
if (getFloatingRank(lt) == getFloatingRank(rt))
|
|
||||||
return 0;
|
|
||||||
if (getFloatingRank(lt) > getFloatingRank(rt))
|
|
||||||
return 1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// maxIntegerType - Returns the highest ranked integer type. Handles 3 case:
|
|
||||||
// unsigned/unsigned, signed/signed, signed/unsigned. C99 6.3.1.8p1.
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getCFConstantStringType - Return the type used for constant CFStrings.
|
|
||||||
QualType ASTContext::getCFConstantStringType() {
|
|
||||||
if (!CFConstantStringTypeDecl) {
|
|
||||||
CFConstantStringTypeDecl = new RecordDecl(Decl::Struct, SourceLocation(),
|
|
||||||
&Idents.get("__builtin_CFString"),
|
|
||||||
0);
|
|
||||||
|
|
||||||
QualType FieldTypes[4];
|
|
||||||
|
|
||||||
// const int *isa;
|
|
||||||
FieldTypes[0] = getPointerType(IntTy.getQualifiedType(QualType::Const));
|
|
||||||
// int flags;
|
|
||||||
FieldTypes[1] = IntTy;
|
|
||||||
// const char *str;
|
|
||||||
FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const));
|
|
||||||
// long length;
|
|
||||||
FieldTypes[3] = LongTy;
|
|
||||||
// Create fields
|
|
||||||
FieldDecl *FieldDecls[4];
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < 4; ++i)
|
|
||||||
FieldDecls[i] = new FieldDecl(SourceLocation(), 0, FieldTypes[i], 0);
|
|
||||||
|
|
||||||
CFConstantStringTypeDecl->defineBody(FieldDecls, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
return getTagDeclType(CFConstantStringTypeDecl);
|
|
||||||
}
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
//===--- 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QualType Type;
|
|
||||||
|
|
||||||
// Read the base type.
|
|
||||||
switch (*Str++) {
|
|
||||||
default: assert(0 && "Unknown builtin type letter!");
|
|
||||||
case 'v':
|
|
||||||
assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'v'!");
|
|
||||||
Type = Context.VoidTy;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'f'!");
|
|
||||||
Type = Context.FloatTy;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
assert(!LongLong && !Signed && !Unsigned && "Bad modifiers used with 'd'!");
|
|
||||||
if (Long)
|
|
||||||
Type = Context.LongDoubleTy;
|
|
||||||
else
|
|
||||||
Type = Context.DoubleTy;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
assert(!LongLong && "Bad modifiers used with 's'!");
|
|
||||||
if (Unsigned)
|
|
||||||
Type = Context.UnsignedShortTy;
|
|
||||||
else
|
|
||||||
Type = Context.ShortTy;
|
|
||||||
break;
|
|
||||||
case 'i':
|
|
||||||
if (Long)
|
|
||||||
Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy;
|
|
||||||
else if (LongLong)
|
|
||||||
Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy;
|
|
||||||
else if (Unsigned)
|
|
||||||
Type = Context.UnsignedIntTy;
|
|
||||||
else
|
|
||||||
Type = Context.IntTy; // default is signed.
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
assert(!Long && !LongLong && "Bad modifiers used with 'c'!");
|
|
||||||
if (Signed)
|
|
||||||
Type = Context.SignedCharTy;
|
|
||||||
else if (Unsigned)
|
|
||||||
Type = Context.UnsignedCharTy;
|
|
||||||
else
|
|
||||||
Type = Context.CharTy;
|
|
||||||
break;
|
|
||||||
case 'F':
|
|
||||||
Type = Context.getCFConstantStringType();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Done = false;
|
|
||||||
while (!Done) {
|
|
||||||
switch (*Str++) {
|
|
||||||
default: Done = true; --Str; break;
|
|
||||||
case '*':
|
|
||||||
Type = Context.getPointerType(Type);
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
Type = Type.getQualifiedType(QualType::Const);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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!");
|
|
||||||
|
|
||||||
// handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);".
|
|
||||||
if (ArgTypes.size() == 0 && TypeStr[0] == '.')
|
|
||||||
return Context.getFunctionTypeNoProto(ResType);
|
|
||||||
return Context.getFunctionType(ResType, &ArgTypes[0], ArgTypes.size(),
|
|
||||||
TypeStr[0] == '.');
|
|
||||||
}
|
|
||||||
1311
clang/AST/CFG.cpp
1311
clang/AST/CFG.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,201 +0,0 @@
|
|||||||
//===--- 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 unsigned nInterfaceDecls = 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;
|
|
||||||
case ObjcInterface:
|
|
||||||
nInterfaceDecls++;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjcMethodDecl::setMethodParams(ParmVarDecl **NewParamInfo,
|
|
||||||
unsigned NumParams) {
|
|
||||||
assert(ParamInfo == 0 && "Already has param info!");
|
|
||||||
|
|
||||||
// Zero params -> null pointer.
|
|
||||||
if (NumParams) {
|
|
||||||
ParamInfo = new ParmVarDecl*[NumParams];
|
|
||||||
memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
|
|
||||||
NumMethodParams = NumParams;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjcMethodDecl::~ObjcMethodDecl() {
|
|
||||||
delete[] ParamInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// addObjcMethods - Insert instance and methods declarations into
|
|
||||||
/// ObjcInterfaceDecl's InsMethods and ClsMethods fields.
|
|
||||||
///
|
|
||||||
void ObjcInterfaceDecl::ObjcAddMethods(ObjcMethodDecl **insMethods,
|
|
||||||
unsigned numInsMembers,
|
|
||||||
ObjcMethodDecl **clsMethods,
|
|
||||||
unsigned numClsMembers) {
|
|
||||||
NumInsMethods = numInsMembers;
|
|
||||||
if (numInsMembers) {
|
|
||||||
InsMethods = new ObjcMethodDecl*[numInsMembers];
|
|
||||||
memcpy(InsMethods, insMethods, numInsMembers*sizeof(ObjcMethodDecl*));
|
|
||||||
}
|
|
||||||
NumClsMethods = numClsMembers;
|
|
||||||
if (numClsMembers) {
|
|
||||||
ClsMethods = new ObjcMethodDecl*[numClsMembers];
|
|
||||||
memcpy(ClsMethods, clsMethods, numClsMembers*sizeof(ObjcMethodDecl*));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1024
clang/AST/Expr.cpp
1024
clang/AST/Expr.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,33 +0,0 @@
|
|||||||
//===--- ExprCXX.cpp - (C++) Expression AST Node Implementation -----------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Ted Kremenek and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file implements the subclesses of Expr class declared in ExprCXX.h
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/AST/ExprCXX.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Child Iterators for iterating over subexpressions/substatements
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
|
|
||||||
// CXXCastExpr
|
|
||||||
Stmt::child_iterator CXXCastExpr::child_begin() {
|
|
||||||
return reinterpret_cast<Stmt**>(&Op);
|
|
||||||
}
|
|
||||||
|
|
||||||
Stmt::child_iterator CXXCastExpr::child_end() {
|
|
||||||
return child_begin()+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CXXBoolLiteralExpr
|
|
||||||
Stmt::child_iterator CXXBoolLiteralExpr::child_begin() { return NULL; }
|
|
||||||
Stmt::child_iterator CXXBoolLiteralExpr::child_end() { return NULL; }
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
##===- 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
|
|
||||||
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
//===--- 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;
|
|
||||||
|
|
||||||
static struct StmtClassNameTable {
|
|
||||||
const char *Name;
|
|
||||||
unsigned Counter;
|
|
||||||
unsigned Size;
|
|
||||||
} StmtClassInfo[Stmt::lastExprConstant+1];
|
|
||||||
|
|
||||||
static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
|
|
||||||
static bool Initialized = false;
|
|
||||||
if (Initialized)
|
|
||||||
return StmtClassInfo[E];
|
|
||||||
|
|
||||||
// Intialize the table on the first use.
|
|
||||||
Initialized = true;
|
|
||||||
#define STMT(N, CLASS, PARENT) \
|
|
||||||
StmtClassInfo[N].Name = #CLASS; \
|
|
||||||
StmtClassInfo[N].Size = sizeof(CLASS);
|
|
||||||
#include "clang/AST/StmtNodes.def"
|
|
||||||
|
|
||||||
return StmtClassInfo[E];
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *Stmt::getStmtClassName() const {
|
|
||||||
return getStmtInfoTableEntry(sClass).Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stmt::PrintStats() {
|
|
||||||
// Ensure the table is primed.
|
|
||||||
getStmtInfoTableEntry(Stmt::NullStmtClass);
|
|
||||||
|
|
||||||
unsigned sum = 0;
|
|
||||||
fprintf(stderr, "*** Stmt/Expr Stats:\n");
|
|
||||||
for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
|
|
||||||
if (StmtClassInfo[i].Name == 0) continue;
|
|
||||||
sum += StmtClassInfo[i].Counter;
|
|
||||||
}
|
|
||||||
fprintf(stderr, " %d stmts/exprs total.\n", sum);
|
|
||||||
sum = 0;
|
|
||||||
for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
|
|
||||||
if (StmtClassInfo[i].Name == 0) continue;
|
|
||||||
fprintf(stderr, " %d %s, %d each (%d bytes)\n",
|
|
||||||
StmtClassInfo[i].Counter, StmtClassInfo[i].Name,
|
|
||||||
StmtClassInfo[i].Size,
|
|
||||||
StmtClassInfo[i].Counter*StmtClassInfo[i].Size);
|
|
||||||
sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size;
|
|
||||||
}
|
|
||||||
fprintf(stderr, "Total bytes = %d\n", sum);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stmt::addStmtClass(StmtClass s) {
|
|
||||||
++getStmtInfoTableEntry(s).Counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool StatSwitch = false;
|
|
||||||
|
|
||||||
bool Stmt::CollectingStats(bool enable) {
|
|
||||||
if (enable) StatSwitch = true;
|
|
||||||
return StatSwitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char *LabelStmt::getName() const {
|
|
||||||
return getID()->getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is defined here to avoid polluting Stmt.h with importing Expr.h
|
|
||||||
SourceRange ReturnStmt::getSourceRange() const {
|
|
||||||
if (RetExpr)
|
|
||||||
return SourceRange(RetLoc, RetExpr->getLocEnd());
|
|
||||||
else
|
|
||||||
return SourceRange(RetLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Child Iterators for iterating over subexpressions/substatements
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// DeclStmt
|
|
||||||
Stmt::child_iterator DeclStmt::child_begin() { return NULL; }
|
|
||||||
Stmt::child_iterator DeclStmt::child_end() { return NULL; }
|
|
||||||
|
|
||||||
// NullStmt
|
|
||||||
Stmt::child_iterator NullStmt::child_begin() { return NULL; }
|
|
||||||
Stmt::child_iterator NullStmt::child_end() { return NULL; }
|
|
||||||
|
|
||||||
// CompoundStmt
|
|
||||||
Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; }
|
|
||||||
Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+Body.size(); }
|
|
||||||
|
|
||||||
// CaseStmt
|
|
||||||
Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; }
|
|
||||||
Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; }
|
|
||||||
|
|
||||||
// DefaultStmt
|
|
||||||
Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; }
|
|
||||||
Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; }
|
|
||||||
|
|
||||||
// LabelStmt
|
|
||||||
Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; }
|
|
||||||
Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; }
|
|
||||||
|
|
||||||
// IfStmt
|
|
||||||
Stmt::child_iterator IfStmt::child_begin() { return &SubExprs[0]; }
|
|
||||||
Stmt::child_iterator IfStmt::child_end() { return &SubExprs[0]+END_EXPR; }
|
|
||||||
|
|
||||||
// SwitchStmt
|
|
||||||
Stmt::child_iterator SwitchStmt::child_begin() { return &SubExprs[0]; }
|
|
||||||
Stmt::child_iterator SwitchStmt::child_end() { return &SubExprs[0]+END_EXPR; }
|
|
||||||
|
|
||||||
// WhileStmt
|
|
||||||
Stmt::child_iterator WhileStmt::child_begin() { return &SubExprs[0]; }
|
|
||||||
Stmt::child_iterator WhileStmt::child_end() { return &SubExprs[0]+END_EXPR; }
|
|
||||||
|
|
||||||
// DoStmt
|
|
||||||
Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; }
|
|
||||||
Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; }
|
|
||||||
|
|
||||||
// ForStmt
|
|
||||||
Stmt::child_iterator ForStmt::child_begin() { return &SubExprs[0]; }
|
|
||||||
Stmt::child_iterator ForStmt::child_end() { return &SubExprs[0]+END_EXPR; }
|
|
||||||
|
|
||||||
// GotoStmt
|
|
||||||
Stmt::child_iterator GotoStmt::child_begin() { return NULL; }
|
|
||||||
Stmt::child_iterator GotoStmt::child_end() { return NULL; }
|
|
||||||
|
|
||||||
// IndirectGotoStmt
|
|
||||||
Stmt::child_iterator IndirectGotoStmt::child_begin() {
|
|
||||||
return reinterpret_cast<Stmt**>(&Target);
|
|
||||||
}
|
|
||||||
|
|
||||||
Stmt::child_iterator IndirectGotoStmt::child_end() { return child_begin()+1; }
|
|
||||||
|
|
||||||
// ContinueStmt
|
|
||||||
Stmt::child_iterator ContinueStmt::child_begin() { return NULL; }
|
|
||||||
Stmt::child_iterator ContinueStmt::child_end() { return NULL; }
|
|
||||||
|
|
||||||
// BreakStmt
|
|
||||||
Stmt::child_iterator BreakStmt::child_begin() { return NULL; }
|
|
||||||
Stmt::child_iterator BreakStmt::child_end() { return NULL; }
|
|
||||||
|
|
||||||
// ReturnStmt
|
|
||||||
Stmt::child_iterator ReturnStmt::child_begin() {
|
|
||||||
if (RetExpr) return reinterpret_cast<Stmt**>(&RetExpr);
|
|
||||||
else return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Stmt::child_iterator ReturnStmt::child_end() {
|
|
||||||
if (RetExpr) return reinterpret_cast<Stmt**>(&RetExpr)+1;
|
|
||||||
else return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,443 +0,0 @@
|
|||||||
//===--- StmtDumper.cpp - Dumping 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, which dump out the
|
|
||||||
// AST in a form that exposes type details and other fields.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/AST/StmtVisitor.h"
|
|
||||||
#include "clang/AST/Decl.h"
|
|
||||||
#include "clang/AST/ExprCXX.h"
|
|
||||||
#include "clang/Lex/IdentifierTable.h"
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
#include "llvm/Support/Compiler.h"
|
|
||||||
#include <cstdio>
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// StmtDumper Visitor
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor<StmtDumper> {
|
|
||||||
SourceManager *SM;
|
|
||||||
FILE *F;
|
|
||||||
unsigned IndentLevel;
|
|
||||||
|
|
||||||
/// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
|
|
||||||
/// the first few levels of an AST. This keeps track of how many ast levels
|
|
||||||
/// are left.
|
|
||||||
unsigned MaxDepth;
|
|
||||||
|
|
||||||
/// LastLocFilename/LastLocLine - Keep track of the last location we print
|
|
||||||
/// out so that we can print out deltas from then on out.
|
|
||||||
const char *LastLocFilename;
|
|
||||||
unsigned LastLocLine;
|
|
||||||
public:
|
|
||||||
StmtDumper(SourceManager *sm, FILE *f, unsigned maxDepth)
|
|
||||||
: SM(sm), F(f), IndentLevel(0-1), MaxDepth(maxDepth) {
|
|
||||||
LastLocFilename = "";
|
|
||||||
LastLocLine = ~0U;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DumpSubTree(Stmt *S) {
|
|
||||||
// Prune the recursion if not using dump all.
|
|
||||||
if (MaxDepth == 0) return;
|
|
||||||
|
|
||||||
++IndentLevel;
|
|
||||||
if (S) {
|
|
||||||
Visit(S);
|
|
||||||
|
|
||||||
// Print out children.
|
|
||||||
Stmt::child_iterator CI = S->child_begin(), CE = S->child_end();
|
|
||||||
if (CI != CE) {
|
|
||||||
while (CI != CE) {
|
|
||||||
fprintf(F, "\n");
|
|
||||||
DumpSubTree(*CI++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf(F, ")");
|
|
||||||
} else {
|
|
||||||
Indent();
|
|
||||||
fprintf(F, "<<<NULL>>>");
|
|
||||||
}
|
|
||||||
--IndentLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DumpDeclarator(Decl *D);
|
|
||||||
|
|
||||||
void Indent() const {
|
|
||||||
for (int i = 0, e = IndentLevel; i < e; ++i)
|
|
||||||
fprintf(F, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
void DumpType(QualType T) {
|
|
||||||
fprintf(F, "'%s'", T.getAsString().c_str());
|
|
||||||
|
|
||||||
// If the type is directly a typedef, strip off typedefness to give at
|
|
||||||
// least one level of concreteness.
|
|
||||||
if (TypedefType *TDT = dyn_cast<TypedefType>(T))
|
|
||||||
fprintf(F, ":'%s'", TDT->LookThroughTypedefs().getAsString().c_str());
|
|
||||||
}
|
|
||||||
void DumpStmt(const Stmt *Node) {
|
|
||||||
Indent();
|
|
||||||
fprintf(F, "(%s %p", Node->getStmtClassName(), (void*)Node);
|
|
||||||
DumpSourceRange(Node);
|
|
||||||
}
|
|
||||||
void DumpExpr(const Expr *Node) {
|
|
||||||
DumpStmt(Node);
|
|
||||||
fprintf(F, " ");
|
|
||||||
DumpType(Node->getType());
|
|
||||||
}
|
|
||||||
void DumpSourceRange(const Stmt *Node);
|
|
||||||
void DumpLocation(SourceLocation Loc);
|
|
||||||
|
|
||||||
// Stmts.
|
|
||||||
void VisitStmt(Stmt *Node);
|
|
||||||
void VisitDeclStmt(DeclStmt *Node);
|
|
||||||
void VisitLabelStmt(LabelStmt *Node);
|
|
||||||
void VisitGotoStmt(GotoStmt *Node);
|
|
||||||
|
|
||||||
// Exprs
|
|
||||||
void VisitExpr(Expr *Node);
|
|
||||||
void VisitDeclRefExpr(DeclRefExpr *Node);
|
|
||||||
void VisitPreDefinedExpr(PreDefinedExpr *Node);
|
|
||||||
void VisitCharacterLiteral(CharacterLiteral *Node);
|
|
||||||
void VisitIntegerLiteral(IntegerLiteral *Node);
|
|
||||||
void VisitFloatingLiteral(FloatingLiteral *Node);
|
|
||||||
void VisitStringLiteral(StringLiteral *Str);
|
|
||||||
void VisitUnaryOperator(UnaryOperator *Node);
|
|
||||||
void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node);
|
|
||||||
void VisitMemberExpr(MemberExpr *Node);
|
|
||||||
void VisitOCUVectorElementExpr(OCUVectorElementExpr *Node);
|
|
||||||
void VisitBinaryOperator(BinaryOperator *Node);
|
|
||||||
void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
|
|
||||||
void VisitAddrLabelExpr(AddrLabelExpr *Node);
|
|
||||||
void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node);
|
|
||||||
|
|
||||||
// C++
|
|
||||||
void VisitCXXCastExpr(CXXCastExpr *Node);
|
|
||||||
void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node);
|
|
||||||
|
|
||||||
// ObjC
|
|
||||||
void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Utilities
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void StmtDumper::DumpLocation(SourceLocation Loc) {
|
|
||||||
SourceLocation PhysLoc = SM->getPhysicalLoc(Loc);
|
|
||||||
|
|
||||||
// The general format we print out is filename:line:col, but we drop pieces
|
|
||||||
// that haven't changed since the last loc printed.
|
|
||||||
const char *Filename = SM->getSourceName(PhysLoc);
|
|
||||||
unsigned LineNo = SM->getLineNumber(PhysLoc);
|
|
||||||
if (strcmp(Filename, LastLocFilename) != 0) {
|
|
||||||
fprintf(stderr, "%s:%u:%u", Filename, LineNo, SM->getColumnNumber(PhysLoc));
|
|
||||||
LastLocFilename = Filename;
|
|
||||||
LastLocLine = LineNo;
|
|
||||||
} else if (LineNo != LastLocLine) {
|
|
||||||
fprintf(stderr, "line:%u:%u", LineNo, SM->getColumnNumber(PhysLoc));
|
|
||||||
LastLocLine = LineNo;
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "col:%u", SM->getColumnNumber(PhysLoc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::DumpSourceRange(const Stmt *Node) {
|
|
||||||
// Can't translate locations if a SourceManager isn't available.
|
|
||||||
if (SM == 0) return;
|
|
||||||
|
|
||||||
// TODO: If the parent expression is available, we can print a delta vs its
|
|
||||||
// location.
|
|
||||||
SourceRange R = Node->getSourceRange();
|
|
||||||
|
|
||||||
fprintf(stderr, " <");
|
|
||||||
DumpLocation(R.Begin());
|
|
||||||
if (R.Begin() != R.End()) {
|
|
||||||
fprintf(stderr, ", ");
|
|
||||||
DumpLocation(R.End());
|
|
||||||
}
|
|
||||||
fprintf(stderr, ">");
|
|
||||||
|
|
||||||
// <t2.c:123:421[blah], t2.c:412:321>
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Stmt printing methods.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void StmtDumper::VisitStmt(Stmt *Node) {
|
|
||||||
DumpStmt(Node);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::DumpDeclarator(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)) {
|
|
||||||
fprintf(F, "\"typedef %s %s\"",
|
|
||||||
localType->getUnderlyingType().getAsString().c_str(),
|
|
||||||
localType->getName());
|
|
||||||
} else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
|
|
||||||
fprintf(F, "\"");
|
|
||||||
// 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: fprintf(F, "extern "); break;
|
|
||||||
case VarDecl::Static: fprintf(F, "static "); break;
|
|
||||||
case VarDecl::Auto: fprintf(F, "auto "); break;
|
|
||||||
case VarDecl::Register: fprintf(F, "register "); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Name = VD->getName();
|
|
||||||
VD->getType().getAsStringInternal(Name);
|
|
||||||
fprintf(F, "%s", Name.c_str());
|
|
||||||
|
|
||||||
// If this is a vardecl with an initializer, emit it.
|
|
||||||
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
|
|
||||||
if (V->getInit()) {
|
|
||||||
fprintf(F, " =\n");
|
|
||||||
DumpSubTree(V->getInit());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf(F, "\"");
|
|
||||||
} else {
|
|
||||||
// FIXME: "struct x;"
|
|
||||||
assert(0 && "Unexpected decl");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
|
|
||||||
DumpStmt(Node);
|
|
||||||
fprintf(F, "\n");
|
|
||||||
for (Decl *D = Node->getDecl(); D; D = D->getNextDeclarator()) {
|
|
||||||
++IndentLevel;
|
|
||||||
Indent();
|
|
||||||
fprintf(F, "%p ", (void*)D);
|
|
||||||
DumpDeclarator(D);
|
|
||||||
if (D->getNextDeclarator())
|
|
||||||
fprintf(F, "\n");
|
|
||||||
--IndentLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::VisitLabelStmt(LabelStmt *Node) {
|
|
||||||
DumpStmt(Node);
|
|
||||||
fprintf(F, " '%s'\n", Node->getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::VisitGotoStmt(GotoStmt *Node) {
|
|
||||||
DumpStmt(Node);
|
|
||||||
fprintf(F, " '%s':%p", Node->getLabel()->getName(), (void*)Node->getLabel());
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Expr printing methods.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void StmtDumper::VisitExpr(Expr *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
|
|
||||||
fprintf(F, " ");
|
|
||||||
switch (Node->getDecl()->getKind()) {
|
|
||||||
case Decl::Function: fprintf(F,"FunctionDecl"); break;
|
|
||||||
case Decl::BlockVariable: fprintf(F,"BlockVariable"); break;
|
|
||||||
case Decl::FileVariable: fprintf(F,"FileVariable"); break;
|
|
||||||
case Decl::ParmVariable: fprintf(F,"ParmVariable"); break;
|
|
||||||
case Decl::EnumConstant: fprintf(F,"EnumConstant"); break;
|
|
||||||
case Decl::Typedef: fprintf(F,"Typedef"); break;
|
|
||||||
case Decl::Struct: fprintf(F,"Struct"); break;
|
|
||||||
case Decl::Union: fprintf(F,"Union"); break;
|
|
||||||
case Decl::Class: fprintf(F,"Class"); break;
|
|
||||||
case Decl::Enum: fprintf(F,"Enum"); break;
|
|
||||||
case Decl::ObjcInterface: fprintf(F,"ObjcInterface"); break;
|
|
||||||
case Decl::ObjcClass: fprintf(F,"ObjcClass"); break;
|
|
||||||
default: fprintf(F,"Decl"); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(F, "='%s' %p", Node->getDecl()->getName(), (void*)Node->getDecl());
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::VisitPreDefinedExpr(PreDefinedExpr *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
switch (Node->getIdentType()) {
|
|
||||||
default:
|
|
||||||
assert(0 && "unknown case");
|
|
||||||
case PreDefinedExpr::Func:
|
|
||||||
fprintf(F, " __func__");
|
|
||||||
break;
|
|
||||||
case PreDefinedExpr::Function:
|
|
||||||
fprintf(F, " __FUNCTION__");
|
|
||||||
break;
|
|
||||||
case PreDefinedExpr::PrettyFunction:
|
|
||||||
fprintf(F, " __PRETTY_FUNCTION__");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
fprintf(F, " %d", Node->getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
|
|
||||||
bool isSigned = Node->getType()->isSignedIntegerType();
|
|
||||||
fprintf(F, " %s", Node->getValue().toString(10, isSigned).c_str());
|
|
||||||
}
|
|
||||||
void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
fprintf(F, " %f", Node->getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::VisitStringLiteral(StringLiteral *Str) {
|
|
||||||
DumpExpr(Str);
|
|
||||||
// FIXME: this doesn't print wstrings right.
|
|
||||||
fprintf(F, " %s\"", Str->isWide() ? "L" : "");
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) {
|
|
||||||
switch (char C = Str->getStrData()[i]) {
|
|
||||||
default:
|
|
||||||
if (isprint(C))
|
|
||||||
fputc(C, F);
|
|
||||||
else
|
|
||||||
fprintf(F, "\\%03o", C);
|
|
||||||
break;
|
|
||||||
// Handle some common ones to make dumps prettier.
|
|
||||||
case '\\': fprintf(F, "\\\\"); break;
|
|
||||||
case '"': fprintf(F, "\\\""); break;
|
|
||||||
case '\n': fprintf(F, "\\n"); break;
|
|
||||||
case '\t': fprintf(F, "\\t"); break;
|
|
||||||
case '\a': fprintf(F, "\\a"); break;
|
|
||||||
case '\b': fprintf(F, "\\b"); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf(F, "\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
fprintf(F, " %s '%s'", Node->isPostfix() ? "postfix" : "prefix",
|
|
||||||
UnaryOperator::getOpcodeStr(Node->getOpcode()));
|
|
||||||
}
|
|
||||||
void StmtDumper::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
fprintf(F, " %s ", Node->isSizeOf() ? "sizeof" : "alignof");
|
|
||||||
DumpType(Node->getArgumentType());
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".",
|
|
||||||
Node->getMemberDecl()->getName(), (void*)Node->getMemberDecl());
|
|
||||||
}
|
|
||||||
void StmtDumper::VisitOCUVectorElementExpr(OCUVectorElementExpr *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
fprintf(F, " %s", Node->getAccessor().getName());
|
|
||||||
}
|
|
||||||
void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
fprintf(F, " '%s'", BinaryOperator::getOpcodeStr(Node->getOpcode()));
|
|
||||||
}
|
|
||||||
void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
fprintf(F, " '%s' ComputeTy=",
|
|
||||||
BinaryOperator::getOpcodeStr(Node->getOpcode()));
|
|
||||||
DumpType(Node->getComputationType());
|
|
||||||
}
|
|
||||||
|
|
||||||
// GNU extensions.
|
|
||||||
|
|
||||||
void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
fprintf(F, " %s %p", Node->getLabel()->getName(), (void*)Node->getLabel());
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
fprintf(F, " ");
|
|
||||||
DumpType(Node->getArgType1());
|
|
||||||
fprintf(F, " ");
|
|
||||||
DumpType(Node->getArgType2());
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// C++ Expressions
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void StmtDumper::VisitCXXCastExpr(CXXCastExpr *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
fprintf(F, " %s", CXXCastExpr::getOpcodeStr(Node->getOpcode()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
fprintf(F, " %s", Node->getValue() ? "true" : "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Obj-C Expressions
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
|
|
||||||
DumpExpr(Node);
|
|
||||||
|
|
||||||
fprintf(F, " ");
|
|
||||||
DumpType(Node->getEncodedType());
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Stmt method implementations
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// dump - This does a local dump of the specified AST fragment. It dumps the
|
|
||||||
/// specified node and a few nodes underneath it, but not the whole subtree.
|
|
||||||
/// This is useful in a debugger.
|
|
||||||
void Stmt::dump(SourceManager &SM) const {
|
|
||||||
StmtDumper P(&SM, stderr, 4);
|
|
||||||
P.DumpSubTree(const_cast<Stmt*>(this));
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// dump - This does a local dump of the specified AST fragment. It dumps the
|
|
||||||
/// specified node and a few nodes underneath it, but not the whole subtree.
|
|
||||||
/// This is useful in a debugger.
|
|
||||||
void Stmt::dump() const {
|
|
||||||
StmtDumper P(0, stderr, 4);
|
|
||||||
P.DumpSubTree(const_cast<Stmt*>(this));
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
|
|
||||||
void Stmt::dumpAll(SourceManager &SM) const {
|
|
||||||
StmtDumper P(&SM, stderr, ~0U);
|
|
||||||
P.DumpSubTree(const_cast<Stmt*>(this));
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
|
|
||||||
void Stmt::dumpAll() const {
|
|
||||||
StmtDumper P(0, stderr, ~0U);
|
|
||||||
P.DumpSubTree(const_cast<Stmt*>(this));
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
@@ -1,620 +0,0 @@
|
|||||||
//===--- 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::dumpPretty/Stmt::printPretty methods, which
|
|
||||||
// pretty print the AST back out to C code.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/AST/StmtVisitor.h"
|
|
||||||
#include "clang/AST/Decl.h"
|
|
||||||
#include "clang/AST/ExprCXX.h"
|
|
||||||
#include "clang/AST/PrettyPrinter.h"
|
|
||||||
#include "clang/Lex/IdentifierTable.h"
|
|
||||||
#include "llvm/Support/Compiler.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// StmtPrinter Visitor
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor<StmtPrinter> {
|
|
||||||
std::ostream &OS;
|
|
||||||
unsigned IndentLevel;
|
|
||||||
clang::PrinterHelper* Helper;
|
|
||||||
public:
|
|
||||||
StmtPrinter(std::ostream &os, PrinterHelper* helper) :
|
|
||||||
OS(os), IndentLevel(0), Helper(helper) {}
|
|
||||||
|
|
||||||
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();
|
|
||||||
Visit(S);
|
|
||||||
OS << ";\n";
|
|
||||||
} else if (S) {
|
|
||||||
Visit(S);
|
|
||||||
} 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)
|
|
||||||
Visit(E);
|
|
||||||
else
|
|
||||||
OS << "<null expr>";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream &Indent(int Delta = 0) const {
|
|
||||||
for (int i = 0, e = IndentLevel+Delta; i < e; ++i)
|
|
||||||
OS << " ";
|
|
||||||
return OS;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PrintOffsetOfDesignator(Expr *E);
|
|
||||||
void VisitUnaryOffsetOf(UnaryOperator *Node);
|
|
||||||
|
|
||||||
void Visit(Stmt* S) {
|
|
||||||
if (Helper && Helper->handledStmt(S,OS))
|
|
||||||
return;
|
|
||||||
else StmtVisitor<StmtPrinter>::Visit(S);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisitStmt(Stmt *Node);
|
|
||||||
#define STMT(N, CLASS, PARENT) \
|
|
||||||
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;
|
|
||||||
|
|
||||||
// If this is a vardecl with an initializer, emit it.
|
|
||||||
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
|
|
||||||
if (V->getInit()) {
|
|
||||||
OS << " = ";
|
|
||||||
PrintExpr(V->getInit());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} 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::VisitSwitchCase(SwitchCase*) {
|
|
||||||
assert(0 && "SwitchCase is an abstract class");
|
|
||||||
}
|
|
||||||
|
|
||||||
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::VisitPreDefinedExpr(PreDefinedExpr *Node) {
|
|
||||||
switch (Node->getIdentType()) {
|
|
||||||
default:
|
|
||||||
assert(0 && "unknown case");
|
|
||||||
case PreDefinedExpr::Func:
|
|
||||||
OS << "__func__";
|
|
||||||
break;
|
|
||||||
case PreDefinedExpr::Function:
|
|
||||||
OS << "__FUNCTION__";
|
|
||||||
break;
|
|
||||||
case PreDefinedExpr::PrettyFunction:
|
|
||||||
OS << "__PRETTY_FUNCTION__";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
|
|
||||||
// FIXME should print an L for wchar_t constants
|
|
||||||
unsigned value = Node->getValue();
|
|
||||||
switch (value) {
|
|
||||||
case '\\':
|
|
||||||
OS << "'\\\\'";
|
|
||||||
break;
|
|
||||||
case '\'':
|
|
||||||
OS << "'\\''";
|
|
||||||
break;
|
|
||||||
case '\a':
|
|
||||||
// TODO: K&R: the meaning of '\\a' is different in traditional C
|
|
||||||
OS << "'\\a'";
|
|
||||||
break;
|
|
||||||
case '\b':
|
|
||||||
OS << "'\\b'";
|
|
||||||
break;
|
|
||||||
// Nonstandard escape sequence.
|
|
||||||
/*case '\e':
|
|
||||||
OS << "'\\e'";
|
|
||||||
break;*/
|
|
||||||
case '\f':
|
|
||||||
OS << "'\\f'";
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
OS << "'\\n'";
|
|
||||||
break;
|
|
||||||
case '\r':
|
|
||||||
OS << "'\\r'";
|
|
||||||
break;
|
|
||||||
case '\t':
|
|
||||||
OS << "'\\t'";
|
|
||||||
break;
|
|
||||||
case '\v':
|
|
||||||
OS << "'\\v'";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (isprint(value) && value < 256) {
|
|
||||||
OS << "'" << (char)value << "'";
|
|
||||||
} else if (value < 256) {
|
|
||||||
OS << "'\\x" << std::hex << value << std::dec << "'";
|
|
||||||
} else {
|
|
||||||
// FIXME what to really do here?
|
|
||||||
OS << value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 more precisely.
|
|
||||||
OS << Node->getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) {
|
|
||||||
PrintExpr(Node->getSubExpr());
|
|
||||||
OS << "i";
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
|
|
||||||
// Print a space if this is an "identifier operator" like sizeof or __real.
|
|
||||||
switch (Node->getOpcode()) {
|
|
||||||
default: break;
|
|
||||||
case UnaryOperator::SizeOf:
|
|
||||||
case UnaryOperator::AlignOf:
|
|
||||||
case UnaryOperator::Real:
|
|
||||||
case UnaryOperator::Imag:
|
|
||||||
case UnaryOperator::Extension:
|
|
||||||
OS << ' ';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrintExpr(Node->getSubExpr());
|
|
||||||
|
|
||||||
if (Node->isPostfix())
|
|
||||||
OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) {
|
|
||||||
if (isa<CompoundLiteralExpr>(E)) {
|
|
||||||
// Base case, print the type and comma.
|
|
||||||
OS << E->getType().getAsString() << ", ";
|
|
||||||
return true;
|
|
||||||
} else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
|
|
||||||
PrintOffsetOfDesignator(ASE->getLHS());
|
|
||||||
OS << "[";
|
|
||||||
PrintExpr(ASE->getRHS());
|
|
||||||
OS << "]";
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
MemberExpr *ME = cast<MemberExpr>(E);
|
|
||||||
bool IsFirst = PrintOffsetOfDesignator(ME->getBase());
|
|
||||||
OS << (IsFirst ? "" : ".") << ME->getMemberDecl()->getName();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) {
|
|
||||||
OS << "__builtin_offsetof(";
|
|
||||||
PrintOffsetOfDesignator(Node->getSubExpr());
|
|
||||||
OS << ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtPrinter::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) {
|
|
||||||
OS << (Node->isSizeOf() ? "sizeof(" : "__alignof(");
|
|
||||||
OS << Node->getArgumentType().getAsString() << ")";
|
|
||||||
}
|
|
||||||
void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
|
|
||||||
PrintExpr(Node->getLHS());
|
|
||||||
OS << "[";
|
|
||||||
PrintExpr(Node->getRHS());
|
|
||||||
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::VisitOCUVectorElementExpr(OCUVectorElementExpr *Node) {
|
|
||||||
PrintExpr(Node->getBase());
|
|
||||||
OS << ".";
|
|
||||||
OS << Node->getAccessor().getName();
|
|
||||||
}
|
|
||||||
void StmtPrinter::VisitCastExpr(CastExpr *Node) {
|
|
||||||
OS << "(" << Node->getType().getAsString() << ")";
|
|
||||||
PrintExpr(Node->getSubExpr());
|
|
||||||
}
|
|
||||||
void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) {
|
|
||||||
OS << "(" << Node->getType().getAsString() << ")";
|
|
||||||
PrintExpr(Node->getInitializer());
|
|
||||||
}
|
|
||||||
void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
|
|
||||||
// No need to print anything, simply forward to the sub expression.
|
|
||||||
PrintExpr(Node->getSubExpr());
|
|
||||||
}
|
|
||||||
void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) {
|
|
||||||
PrintExpr(Node->getLHS());
|
|
||||||
OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
|
|
||||||
PrintExpr(Node->getRHS());
|
|
||||||
}
|
|
||||||
void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *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::VisitAddrLabelExpr(AddrLabelExpr *Node) {
|
|
||||||
OS << "&&" << Node->getLabel()->getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtPrinter::VisitStmtExpr(StmtExpr *E) {
|
|
||||||
OS << "(";
|
|
||||||
PrintRawCompoundStmt(E->getSubStmt());
|
|
||||||
OS << ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtPrinter::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
|
|
||||||
OS << "__builtin_types_compatible_p(";
|
|
||||||
OS << Node->getArgType1().getAsString() << ",";
|
|
||||||
OS << Node->getArgType2().getAsString() << ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) {
|
|
||||||
OS << "__builtin_choose_expr(";
|
|
||||||
PrintExpr(Node->getCond());
|
|
||||||
OS << ", ";
|
|
||||||
PrintExpr(Node->getLHS());
|
|
||||||
OS << ", ";
|
|
||||||
PrintExpr(Node->getRHS());
|
|
||||||
OS << ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
|
|
||||||
OS << "{ ";
|
|
||||||
for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {
|
|
||||||
if (i) OS << ", ";
|
|
||||||
PrintExpr(Node->getInit(i));
|
|
||||||
}
|
|
||||||
OS << " }";
|
|
||||||
}
|
|
||||||
|
|
||||||
// C++
|
|
||||||
|
|
||||||
void StmtPrinter::VisitCXXCastExpr(CXXCastExpr *Node) {
|
|
||||||
OS << CXXCastExpr::getOpcodeStr(Node->getOpcode()) << '<';
|
|
||||||
OS << Node->getDestType().getAsString() << ">(";
|
|
||||||
PrintExpr(Node->getSubExpr());
|
|
||||||
OS << ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
|
|
||||||
OS << (Node->getValue() ? "true" : "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obj-C
|
|
||||||
|
|
||||||
void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
|
|
||||||
OS << "@";
|
|
||||||
VisitStringLiteral(Node->getString());
|
|
||||||
}
|
|
||||||
|
|
||||||
void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
|
|
||||||
OS << "@encode(";
|
|
||||||
OS << Node->getEncodedType().getAsString() << ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Stmt method implementations
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void Stmt::dumpPretty() const {
|
|
||||||
// FIXME: eliminate use of <iostream>
|
|
||||||
printPretty(std::cerr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stmt::printPretty(std::ostream &OS, PrinterHelper* Helper) const {
|
|
||||||
if (this == 0) {
|
|
||||||
OS << "<NULL>";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StmtPrinter P(OS, Helper);
|
|
||||||
P.Visit(const_cast<Stmt*>(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// PrinterHelper
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// Implement virtual destructor.
|
|
||||||
PrinterHelper::~PrinterHelper() {}
|
|
||||||
@@ -1,857 +0,0 @@
|
|||||||
//===--- 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"
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
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 VariableArray:
|
|
||||||
case ConstantArray:
|
|
||||||
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::isStructureType() const {
|
|
||||||
if (const RecordType *RT = dyn_cast<RecordType>(this))
|
|
||||||
if (RT->getDecl()->getKind() == Decl::Struct)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool Type::isUnionType() const {
|
|
||||||
if (const RecordType *RT = dyn_cast<RecordType>(this))
|
|
||||||
if (RT->getDecl()->getKind() == Decl::Union)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Type::isComplexType() const {
|
|
||||||
return isa<ComplexType>(CanonicalType);
|
|
||||||
}
|
|
||||||
|
|
||||||
const BuiltinType *Type::getAsBuiltinType() const {
|
|
||||||
// If this is directly a builtin type, return it.
|
|
||||||
if (const BuiltinType *BTy = dyn_cast<BuiltinType>(this))
|
|
||||||
return BTy;
|
|
||||||
|
|
||||||
// If this is a typedef for a builtin type, strip the typedef off without
|
|
||||||
// losing all typedef information.
|
|
||||||
if (isa<BuiltinType>(CanonicalType))
|
|
||||||
return cast<BuiltinType>(cast<TypedefType>(this)->LookThroughTypedefs());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FunctionType *Type::getAsFunctionType() const {
|
|
||||||
// If this is directly a function type, return it.
|
|
||||||
if (const FunctionType *FTy = dyn_cast<FunctionType>(this))
|
|
||||||
return FTy;
|
|
||||||
|
|
||||||
// If this is a typedef for a function type, strip the typedef off without
|
|
||||||
// losing all typedef information.
|
|
||||||
if (isa<FunctionType>(CanonicalType))
|
|
||||||
return cast<FunctionType>(cast<TypedefType>(this)->LookThroughTypedefs());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PointerType *Type::getAsPointerType() const {
|
|
||||||
// If this is directly a pointer type, return it.
|
|
||||||
if (const PointerType *PTy = dyn_cast<PointerType>(this))
|
|
||||||
return PTy;
|
|
||||||
|
|
||||||
// If this is a typedef for a pointer type, strip the typedef off without
|
|
||||||
// losing all typedef information.
|
|
||||||
if (isa<PointerType>(CanonicalType))
|
|
||||||
return cast<PointerType>(cast<TypedefType>(this)->LookThroughTypedefs());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ReferenceType *Type::getAsReferenceType() const {
|
|
||||||
// If this is directly a reference type, return it.
|
|
||||||
if (const ReferenceType *RTy = dyn_cast<ReferenceType>(this))
|
|
||||||
return RTy;
|
|
||||||
|
|
||||||
// If this is a typedef for a reference type, strip the typedef off without
|
|
||||||
// losing all typedef information.
|
|
||||||
if (isa<ReferenceType>(CanonicalType))
|
|
||||||
return cast<ReferenceType>(cast<TypedefType>(this)->LookThroughTypedefs());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ArrayType *Type::getAsArrayType() const {
|
|
||||||
// If this is directly an array type, return it.
|
|
||||||
if (const ArrayType *ATy = dyn_cast<ArrayType>(this))
|
|
||||||
return ATy;
|
|
||||||
|
|
||||||
// If this is a typedef for an array type, strip the typedef off without
|
|
||||||
// losing all typedef information.
|
|
||||||
if (isa<ArrayType>(CanonicalType))
|
|
||||||
return cast<ArrayType>(cast<TypedefType>(this)->LookThroughTypedefs());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ConstantArrayType *Type::getAsConstantArrayType() const {
|
|
||||||
// If this is directly a constant array type, return it.
|
|
||||||
if (const ConstantArrayType *ATy = dyn_cast<ConstantArrayType>(this))
|
|
||||||
return ATy;
|
|
||||||
|
|
||||||
// If this is a typedef for an array type, strip the typedef off without
|
|
||||||
// losing all typedef information.
|
|
||||||
if (isa<ConstantArrayType>(CanonicalType))
|
|
||||||
return cast<ConstantArrayType>(cast<TypedefType>(this)->LookThroughTypedefs());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const VariableArrayType *Type::getAsVariableArrayType() const {
|
|
||||||
// If this is directly a variable array type, return it.
|
|
||||||
if (const VariableArrayType *ATy = dyn_cast<VariableArrayType>(this))
|
|
||||||
return ATy;
|
|
||||||
|
|
||||||
// If this is a typedef for an array type, strip the typedef off without
|
|
||||||
// losing all typedef information.
|
|
||||||
if (isa<VariableArrayType>(CanonicalType))
|
|
||||||
return cast<VariableArrayType>(cast<TypedefType>(this)->LookThroughTypedefs());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// isVariablyModifiedType (C99 6.7.5.2p2) - Return true for variable array
|
|
||||||
/// types that have a non-constant expression. This does not include "[]".
|
|
||||||
bool Type::isVariablyModifiedType() const {
|
|
||||||
if (const VariableArrayType *VAT = getAsVariableArrayType()) {
|
|
||||||
if (VAT->getSizeExpr())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const VariableArrayType *Type::getAsVariablyModifiedType() const {
|
|
||||||
if (const VariableArrayType *VAT = getAsVariableArrayType()) {
|
|
||||||
if (VAT->getSizeExpr())
|
|
||||||
return VAT;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RecordType *Type::getAsRecordType() const {
|
|
||||||
// If this is directly a reference type, return it.
|
|
||||||
if (const RecordType *RTy = dyn_cast<RecordType>(this))
|
|
||||||
return RTy;
|
|
||||||
|
|
||||||
// If this is a typedef for an record type, strip the typedef off without
|
|
||||||
// losing all typedef information.
|
|
||||||
if (isa<RecordType>(CanonicalType))
|
|
||||||
return cast<RecordType>(cast<TypedefType>(this)->LookThroughTypedefs());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RecordType *Type::getAsStructureType() const {
|
|
||||||
// If this is directly a structure type, return it.
|
|
||||||
if (const RecordType *RT = dyn_cast<RecordType>(this)) {
|
|
||||||
if (RT->getDecl()->getKind() == Decl::Struct)
|
|
||||||
return RT;
|
|
||||||
}
|
|
||||||
// If this is a typedef for a structure type, strip the typedef off without
|
|
||||||
// losing all typedef information.
|
|
||||||
if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) {
|
|
||||||
if (RT->getDecl()->getKind() == Decl::Struct)
|
|
||||||
return cast<RecordType>(cast<TypedefType>(this)->LookThroughTypedefs());
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RecordType *Type::getAsUnionType() const {
|
|
||||||
// If this is directly a union type, return it.
|
|
||||||
if (const RecordType *RT = dyn_cast<RecordType>(this)) {
|
|
||||||
if (RT->getDecl()->getKind() == Decl::Union)
|
|
||||||
return RT;
|
|
||||||
}
|
|
||||||
// If this is a typedef for a union type, strip the typedef off without
|
|
||||||
// losing all typedef information.
|
|
||||||
if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) {
|
|
||||||
if (RT->getDecl()->getKind() == Decl::Union)
|
|
||||||
return cast<RecordType>(cast<TypedefType>(this)->LookThroughTypedefs());
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ComplexType *Type::getAsComplexType() const {
|
|
||||||
// Are we directly a complex type?
|
|
||||||
if (const ComplexType *CTy = dyn_cast<ComplexType>(this))
|
|
||||||
return CTy;
|
|
||||||
|
|
||||||
// If this is a typedef for a complex type, strip the typedef off without
|
|
||||||
// losing all typedef information.
|
|
||||||
if (isa<ComplexType>(CanonicalType))
|
|
||||||
return cast<ComplexType>(cast<TypedefType>(this)->LookThroughTypedefs());
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const VectorType *Type::getAsVectorType() const {
|
|
||||||
// Are we directly a vector type?
|
|
||||||
if (const VectorType *VTy = dyn_cast<VectorType>(this))
|
|
||||||
return VTy;
|
|
||||||
|
|
||||||
// If this is a typedef for a vector type, strip the typedef off without
|
|
||||||
// losing all typedef information.
|
|
||||||
if (isa<VectorType>(CanonicalType))
|
|
||||||
return cast<VectorType>(cast<TypedefType>(this)->LookThroughTypedefs());
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const OCUVectorType *Type::getAsOCUVectorType() const {
|
|
||||||
// Are we directly an OpenCU vector type?
|
|
||||||
if (const OCUVectorType *VTy = dyn_cast<OCUVectorType>(this))
|
|
||||||
return VTy;
|
|
||||||
|
|
||||||
// If this is a typedef for an OpenCU vector type, strip the typedef off
|
|
||||||
// without losing all typedef information.
|
|
||||||
if (isa<OCUVectorType>(CanonicalType))
|
|
||||||
return cast<OCUVectorType>(cast<TypedefType>(this)->LookThroughTypedefs());
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Type::builtinTypesAreCompatible(QualType lhs, QualType rhs) {
|
|
||||||
const BuiltinType *lBuiltin = lhs->getAsBuiltinType();
|
|
||||||
const BuiltinType *rBuiltin = rhs->getAsBuiltinType();
|
|
||||||
|
|
||||||
return lBuiltin->getKind() == rBuiltin->getKind();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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::ConstantArray:
|
|
||||||
case Type::VariableArray:
|
|
||||||
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 builtinTypesAreCompatible(lcanon, rcanon);
|
|
||||||
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;
|
|
||||||
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
|
|
||||||
return VT->getElementType()->isIntegerType();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Type::isEnumeralType() const {
|
|
||||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
|
|
||||||
return TT->getDecl()->getKind() == Decl::Enum;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Type::isBooleanType() const {
|
|
||||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
|
||||||
return BT->getKind() == BuiltinType::Bool;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Type::isCharType() const {
|
|
||||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
|
||||||
return BT->getKind() == BuiltinType::Char_U ||
|
|
||||||
BT->getKind() == BuiltinType::UChar ||
|
|
||||||
BT->getKind() == BuiltinType::Char_S;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// isSignedIntegerType - Return true if this is an integer type that is
|
|
||||||
/// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..],
|
|
||||||
/// an enum decl which has a signed representation, or a vector of signed
|
|
||||||
/// integer element type.
|
|
||||||
bool Type::isSignedIntegerType() const {
|
|
||||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
|
|
||||||
return BT->getKind() >= BuiltinType::Char_S &&
|
|
||||||
BT->getKind() <= BuiltinType::LongLong;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
|
|
||||||
if (const EnumDecl *ED = dyn_cast<EnumDecl>(TT->getDecl()))
|
|
||||||
return ED->getIntegerType()->isSignedIntegerType();
|
|
||||||
|
|
||||||
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
|
|
||||||
return VT->getElementType()->isSignedIntegerType();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// isUnsignedIntegerType - Return true if this is an integer type that is
|
|
||||||
/// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum
|
|
||||||
/// decl which has an unsigned representation, or a vector of unsigned integer
|
|
||||||
/// element type.
|
|
||||||
bool Type::isUnsignedIntegerType() const {
|
|
||||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
|
|
||||||
return BT->getKind() >= BuiltinType::Bool &&
|
|
||||||
BT->getKind() <= BuiltinType::ULongLong;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
|
|
||||||
if (const EnumDecl *ED = dyn_cast<EnumDecl>(TT->getDecl()))
|
|
||||||
return ED->getIntegerType()->isUnsignedIntegerType();
|
|
||||||
|
|
||||||
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
|
|
||||||
return VT->getElementType()->isUnsignedIntegerType();
|
|
||||||
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->getElementType()->isFloatingType();
|
|
||||||
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
|
|
||||||
return VT->getElementType()->isFloatingType();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Type::isRealFloatingType() const {
|
|
||||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
|
||||||
return BT->getKind() >= BuiltinType::Float &&
|
|
||||||
BT->getKind() <= BuiltinType::LongDouble;
|
|
||||||
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
|
|
||||||
return VT->getElementType()->isRealFloatingType();
|
|
||||||
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;
|
|
||||||
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
|
|
||||||
return VT->getElementType()->isRealType();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) ||
|
|
||||||
isa<VectorType>(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() == ConstantArray ||
|
|
||||||
CanonicalType->getTypeClass() == VariableArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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(ASTContext &Ctx, SourceLocation *loc) const {
|
|
||||||
if (isa<VariableArrayType>(CanonicalType))
|
|
||||||
return false;
|
|
||||||
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 VariableArray:
|
|
||||||
// An array of unknown size is an incomplete type (C99 6.2.5p22).
|
|
||||||
return cast<VariableArrayType>(CanonicalType)->getSizeExpr() == 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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
|
|
||||||
arg_type_iterator 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(), arg_type_begin(), NumArgs, isVariadic());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
|
|
||||||
/// potentially looking through *all* consequtive typedefs. This returns the
|
|
||||||
/// sum of the type qualifiers, so if you have:
|
|
||||||
/// typedef const int A;
|
|
||||||
/// typedef volatile A B;
|
|
||||||
/// looking through the typedefs for B will give you "const volatile A".
|
|
||||||
///
|
|
||||||
QualType TypedefType::LookThroughTypedefs() const {
|
|
||||||
// Usually, there is only a single level of typedefs, be fast in that case.
|
|
||||||
QualType FirstType = getDecl()->getUnderlyingType();
|
|
||||||
if (!isa<TypedefType>(FirstType))
|
|
||||||
return FirstType;
|
|
||||||
|
|
||||||
// Otherwise, do the fully general loop.
|
|
||||||
unsigned TypeQuals = 0;
|
|
||||||
const TypedefType *TDT = this;
|
|
||||||
while (1) {
|
|
||||||
QualType CurType = TDT->getDecl()->getUnderlyingType();
|
|
||||||
TypeQuals |= CurType.getQualifiers();
|
|
||||||
|
|
||||||
TDT = dyn_cast<TypedefType>(CurType);
|
|
||||||
if (TDT == 0)
|
|
||||||
return QualType(CurType.getTypePtr(), TypeQuals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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.
|
|
||||||
unsigned TQ = getQualifiers();
|
|
||||||
if (TQ) {
|
|
||||||
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 ConstantArrayType::getAsStringInternal(std::string &S) const {
|
|
||||||
S += '[';
|
|
||||||
S += llvm::utostr(getSize().getZExtValue());
|
|
||||||
S += ']';
|
|
||||||
|
|
||||||
getElementType().getAsStringInternal(S);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VariableArrayType::getAsStringInternal(std::string &S) const {
|
|
||||||
S += '[';
|
|
||||||
|
|
||||||
if (getIndexTypeQualifier()) {
|
|
||||||
AppendTypeQualList(S, getIndexTypeQualifier());
|
|
||||||
S += ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getSizeModifier() == Static)
|
|
||||||
S += "static";
|
|
||||||
else if (getSizeModifier() == Star)
|
|
||||||
S += '*';
|
|
||||||
|
|
||||||
if (getSizeExpr()) {
|
|
||||||
std::ostringstream s;
|
|
||||||
getSizeExpr()->printPretty(s);
|
|
||||||
S += s.str();
|
|
||||||
}
|
|
||||||
S += ']';
|
|
||||||
|
|
||||||
getElementType().getAsStringInternal(S);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VectorType::getAsStringInternal(std::string &S) const {
|
|
||||||
S += " __attribute__((vector_size(";
|
|
||||||
// FIXME: should multiply by element size somehow.
|
|
||||||
S += llvm::utostr_32(NumElements*4); // convert back to bytes.
|
|
||||||
S += ")))";
|
|
||||||
ElementType.getAsStringInternal(S);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OCUVectorType::getAsStringInternal(std::string &S) const {
|
|
||||||
S += " __attribute__((ocu_vector_type(";
|
|
||||||
S += llvm::utostr_32(NumElements);
|
|
||||||
S += ")))";
|
|
||||||
ElementType.getAsStringInternal(S);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TypeOfExpr::getAsStringInternal(std::string &InnerString) const {
|
|
||||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(e) X'.
|
|
||||||
InnerString = ' ' + InnerString;
|
|
||||||
std::ostringstream s;
|
|
||||||
getUnderlyingExpr()->printPretty(s);
|
|
||||||
InnerString = "typeof(" + s.str() + ")" + InnerString;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TypeOfType::getAsStringInternal(std::string &InnerString) const {
|
|
||||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(t) X'.
|
|
||||||
InnerString = ' ' + InnerString;
|
|
||||||
std::string Tmp;
|
|
||||||
getUnderlyingType().getAsStringInternal(Tmp);
|
|
||||||
InnerString = "typeof(" + Tmp + ")" + InnerString;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 ObjcInterfaceType::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;
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
//==- DeadStores.cpp - Check for stores to dead variables --------*- C++ -*-==//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Ted Kremenek and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This files defines a DeadStores, a flow-sensitive checker that looks for
|
|
||||||
// stores to variables that are no longer live.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/AST/Expr.h"
|
|
||||||
#include "clang/Analysis/LocalCheckers.h"
|
|
||||||
#include "clang/Analysis/LiveVariables.h"
|
|
||||||
#include "clang/AST/CFG.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "clang/Lex/Preprocessor.h"
|
|
||||||
#include "clang/AST/ASTContext.h"
|
|
||||||
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class DeadStoreObserver : public LiveVariablesObserver {
|
|
||||||
Preprocessor& PP;
|
|
||||||
ASTContext Ctx;
|
|
||||||
public:
|
|
||||||
DeadStoreObserver(Preprocessor& pp) :
|
|
||||||
PP(pp), Ctx(PP.getSourceManager(), PP.getTargetInfo(),
|
|
||||||
PP.getIdentifierTable()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~DeadStoreObserver() {}
|
|
||||||
|
|
||||||
virtual void ObserveStmt(Stmt* S, LiveVariables& L, llvm::BitVector& Live) {
|
|
||||||
if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
|
|
||||||
// Is this an assignment?
|
|
||||||
if (!B->isAssignmentOp())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Is this an assignment to a variable?
|
|
||||||
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
|
|
||||||
// Is the variable live?
|
|
||||||
if (!L.isLive(Live,cast<VarDecl>(DR->getDecl()))) {
|
|
||||||
SourceRange R = B->getRHS()->getSourceRange();
|
|
||||||
PP.getDiagnostics().Report(DR->getSourceRange().Begin(),
|
|
||||||
diag::warn_dead_store, 0, 0,
|
|
||||||
&R,1);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
|
|
||||||
// Iterate through the decls. Warn if any of them (which have
|
|
||||||
// initializers) are not live.
|
|
||||||
for (VarDecl* V = cast<VarDecl>(DS->getDecl()); V != NULL ;
|
|
||||||
V = cast_or_null<VarDecl>(V->getNextDeclarator()))
|
|
||||||
if (Expr* E = V->getInit())
|
|
||||||
if (!L.isLive(Live,V))
|
|
||||||
// Special case: check for initializations with constants.
|
|
||||||
//
|
|
||||||
// e.g. : int x = 0;
|
|
||||||
//
|
|
||||||
// If x is EVER assigned a new value later, don't issue
|
|
||||||
// a warning. This is because such initialization can be
|
|
||||||
// due to defensive programming.
|
|
||||||
if (!E->isConstantExpr(Ctx,NULL) ||
|
|
||||||
L.getVarInfo(V).Kills.size() == 0) {
|
|
||||||
// Flag a warning.
|
|
||||||
SourceRange R = E->getSourceRange();
|
|
||||||
PP.getDiagnostics().Report(V->getLocation(),
|
|
||||||
diag::warn_dead_store, 0, 0,
|
|
||||||
&R,1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
namespace clang {
|
|
||||||
|
|
||||||
void CheckDeadStores(CFG& cfg, LiveVariables& L, Preprocessor& PP) {
|
|
||||||
DeadStoreObserver A(PP);
|
|
||||||
|
|
||||||
for (CFG::iterator I = cfg.begin(), E = cfg.end(); I != E; ++I)
|
|
||||||
L.runOnBlock(&(*I),&A);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckDeadStores(CFG& cfg, Preprocessor& PP) {
|
|
||||||
LiveVariables L;
|
|
||||||
L.runOnCFG(cfg);
|
|
||||||
CheckDeadStores(cfg,L,PP);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace clang
|
|
||||||
@@ -1,474 +0,0 @@
|
|||||||
//==- LiveVariables.cpp - Live Variable Analysis for Source CFGs -*- C++ --*-==//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Ted Kremenek and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file implements Live Variables analysis for source-level CFGs.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Analysis/LiveVariables.h"
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
#include "clang/AST/Expr.h"
|
|
||||||
#include "clang/AST/CFG.h"
|
|
||||||
#include "clang/Analysis/DataflowStmtVisitor.h"
|
|
||||||
#include "clang/Lex/IdentifierTable.h"
|
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// RegisterDecls - Utility class to create VarInfo objects for all
|
|
||||||
// Decls referenced in a function.
|
|
||||||
//
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class RegisterDecls : public StmtVisitor<RegisterDecls,void> {
|
|
||||||
LiveVariables& L;
|
|
||||||
const CFG& cfg;
|
|
||||||
public:
|
|
||||||
RegisterDecls(LiveVariables& l, const CFG& c)
|
|
||||||
: L(l), cfg(c) {}
|
|
||||||
|
|
||||||
void VisitStmt(Stmt* S);
|
|
||||||
void VisitDeclRefExpr(DeclRefExpr* DR);
|
|
||||||
void VisitDeclStmt(DeclStmt* DS);
|
|
||||||
void Register(Decl* D);
|
|
||||||
void RegisterDeclChain(Decl* D);
|
|
||||||
void RegisterUsedDecls();
|
|
||||||
};
|
|
||||||
|
|
||||||
void RegisterDecls::VisitStmt(Stmt* S) {
|
|
||||||
for (Stmt::child_iterator I = S->child_begin(),E = S->child_end(); I != E;++I)
|
|
||||||
Visit(*I);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterDecls::VisitDeclRefExpr(DeclRefExpr* DR) {
|
|
||||||
RegisterDeclChain(DR->getDecl());
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterDecls::VisitDeclStmt(DeclStmt* DS) {
|
|
||||||
RegisterDeclChain(DS->getDecl());
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterDecls::RegisterDeclChain(Decl* D) {
|
|
||||||
for (; D != NULL ; D = D->getNextDeclarator())
|
|
||||||
Register(D);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterDecls::Register(Decl* D) {
|
|
||||||
if (VarDecl* V = dyn_cast<VarDecl>(D)) {
|
|
||||||
LiveVariables::VPair& VP = L.getVarInfoMap()[V];
|
|
||||||
|
|
||||||
VP.V.AliveBlocks.resize(cfg.getNumBlockIDs());
|
|
||||||
VP.Idx = L.getNumDecls()++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterDecls::RegisterUsedDecls() {
|
|
||||||
for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI)
|
|
||||||
for (CFGBlock::const_iterator SI=BI->begin(),SE = BI->end();SI != SE;++SI)
|
|
||||||
Visit(const_cast<Stmt*>(*SI));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// WorkList - Data structure representing the liveness algorithm worklist.
|
|
||||||
//
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class WorkListTy {
|
|
||||||
typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet;
|
|
||||||
BlockSet wlist;
|
|
||||||
public:
|
|
||||||
void enqueue(const CFGBlock* B) { wlist.insert(B); }
|
|
||||||
|
|
||||||
const CFGBlock* dequeue() {
|
|
||||||
assert (!wlist.empty());
|
|
||||||
const CFGBlock* B = *wlist.begin();
|
|
||||||
wlist.erase(B);
|
|
||||||
return B;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEmpty() const { return wlist.empty(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// TFuncs
|
|
||||||
//
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class LivenessTFuncs : public DataflowStmtVisitor<LivenessTFuncs,
|
|
||||||
dataflow::backward_analysis_tag> {
|
|
||||||
LiveVariables& L;
|
|
||||||
llvm::BitVector Live;
|
|
||||||
llvm::BitVector KilledAtLeastOnce;
|
|
||||||
Stmt* CurrentStmt;
|
|
||||||
const CFGBlock* CurrentBlock;
|
|
||||||
bool blockPreviouslyProcessed;
|
|
||||||
LiveVariablesObserver* Observer;
|
|
||||||
|
|
||||||
public:
|
|
||||||
LivenessTFuncs(LiveVariables& l, LiveVariablesObserver* A = NULL)
|
|
||||||
: L(l), CurrentStmt(NULL), CurrentBlock(NULL),
|
|
||||||
blockPreviouslyProcessed(false), Observer(A) {
|
|
||||||
Live.resize(l.getNumDecls());
|
|
||||||
KilledAtLeastOnce.resize(l.getNumDecls());
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisitDeclRefExpr(DeclRefExpr* DR);
|
|
||||||
void VisitBinaryOperator(BinaryOperator* B);
|
|
||||||
void VisitAssign(BinaryOperator* B);
|
|
||||||
void VisitDeclStmt(DeclStmt* DS);
|
|
||||||
void VisitUnaryOperator(UnaryOperator* U);
|
|
||||||
void ObserveStmt(Stmt* S);
|
|
||||||
|
|
||||||
unsigned getIdx(const VarDecl* D) {
|
|
||||||
LiveVariables::VarInfoMap& V = L.getVarInfoMap();
|
|
||||||
LiveVariables::VarInfoMap::iterator I = V.find(D);
|
|
||||||
assert (I != V.end());
|
|
||||||
return I->second.Idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProcessBlock(const CFGBlock* B);
|
|
||||||
llvm::BitVector* getBlockEntryLiveness(const CFGBlock* B);
|
|
||||||
LiveVariables::VarInfo& KillVar(VarDecl* D);
|
|
||||||
};
|
|
||||||
|
|
||||||
void LivenessTFuncs::ObserveStmt(Stmt* S) {
|
|
||||||
if (Observer) Observer->ObserveStmt(S,L,Live);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LivenessTFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
|
|
||||||
// Register a use of the variable.
|
|
||||||
if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl()))
|
|
||||||
Live.set(getIdx(V));
|
|
||||||
}
|
|
||||||
|
|
||||||
void LivenessTFuncs::VisitBinaryOperator(BinaryOperator* B) {
|
|
||||||
if (B->isAssignmentOp()) VisitAssign(B);
|
|
||||||
else VisitStmt(B);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LivenessTFuncs::VisitUnaryOperator(UnaryOperator* U) {
|
|
||||||
switch (U->getOpcode()) {
|
|
||||||
case UnaryOperator::PostInc:
|
|
||||||
case UnaryOperator::PostDec:
|
|
||||||
case UnaryOperator::PreInc:
|
|
||||||
case UnaryOperator::PreDec:
|
|
||||||
case UnaryOperator::AddrOf:
|
|
||||||
// Walk through the subexpressions, blasting through ParenExprs until
|
|
||||||
// we either find a DeclRefExpr or some non-DeclRefExpr expression.
|
|
||||||
for (Stmt* S = U->getSubExpr() ; ; ) {
|
|
||||||
if (ParenExpr* P = dyn_cast<ParenExpr>(S)) {
|
|
||||||
S = P->getSubExpr();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(S)) {
|
|
||||||
// Treat the --/++/& operator as a kill.
|
|
||||||
LiveVariables::VarInfo& V =
|
|
||||||
KillVar(cast<VarDecl>(DR->getDecl()));
|
|
||||||
|
|
||||||
if (!blockPreviouslyProcessed)
|
|
||||||
V.AddKill(CurrentStmt,DR);
|
|
||||||
|
|
||||||
VisitDeclRefExpr(DR);
|
|
||||||
}
|
|
||||||
else Visit(S);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Visit(U->getSubExpr());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LiveVariables::VarInfo& LivenessTFuncs::KillVar(VarDecl* D) {
|
|
||||||
LiveVariables::VarInfoMap::iterator I = L.getVarInfoMap().find(D);
|
|
||||||
|
|
||||||
assert (I != L.getVarInfoMap().end() &&
|
|
||||||
"Declaration not managed by variable map in LiveVariables");
|
|
||||||
|
|
||||||
// Mark the variable dead, and remove the current block from
|
|
||||||
// the set of blocks where the variable may be alive the entire time.
|
|
||||||
Live.reset(I->second.Idx);
|
|
||||||
I->second.V.AliveBlocks.reset(CurrentBlock->getBlockID());
|
|
||||||
|
|
||||||
return I->second.V;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LivenessTFuncs::VisitAssign(BinaryOperator* B) {
|
|
||||||
// Check if we are assigning to a variable.
|
|
||||||
Stmt* LHS = B->getLHS();
|
|
||||||
|
|
||||||
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS)) {
|
|
||||||
LiveVariables::VarInfo& V = KillVar(cast<VarDecl>(DR->getDecl()));
|
|
||||||
|
|
||||||
// We only need to register kills once, so we check if this block
|
|
||||||
// has been previously processed.
|
|
||||||
if (!blockPreviouslyProcessed)
|
|
||||||
V.AddKill(CurrentStmt,DR);
|
|
||||||
|
|
||||||
if (B->getOpcode() != BinaryOperator::Assign)
|
|
||||||
Visit(LHS);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Visit(LHS);
|
|
||||||
|
|
||||||
Visit(B->getRHS());
|
|
||||||
}
|
|
||||||
|
|
||||||
void LivenessTFuncs::VisitDeclStmt(DeclStmt* DS) {
|
|
||||||
// Declarations effectively "kill" a variable since they cannot possibly
|
|
||||||
// be live before they are declared. Declarations, however, are not kills
|
|
||||||
// in the sense that the value is obliterated, so we do not register
|
|
||||||
// DeclStmts as a "kill site" for a variable.
|
|
||||||
for (Decl* D = DS->getDecl(); D != NULL ; D = D->getNextDeclarator())
|
|
||||||
KillVar(cast<VarDecl>(D));
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::BitVector* LivenessTFuncs::getBlockEntryLiveness(const CFGBlock* B) {
|
|
||||||
LiveVariables::BlockLivenessMap& BMap = L.getLiveAtBlockEntryMap();
|
|
||||||
|
|
||||||
LiveVariables::BlockLivenessMap::iterator I = BMap.find(B);
|
|
||||||
return (I == BMap.end()) ? NULL : &(I->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool LivenessTFuncs::ProcessBlock(const CFGBlock* B) {
|
|
||||||
|
|
||||||
CurrentBlock = B;
|
|
||||||
Live.reset();
|
|
||||||
KilledAtLeastOnce.reset();
|
|
||||||
|
|
||||||
// Check if this block has been previously processed.
|
|
||||||
LiveVariables::BlockLivenessMap& BMap = L.getLiveAtBlockEntryMap();
|
|
||||||
LiveVariables::BlockLivenessMap::iterator BI = BMap.find(B);
|
|
||||||
|
|
||||||
blockPreviouslyProcessed = BI != BMap.end();
|
|
||||||
|
|
||||||
// Merge liveness information from all predecessors.
|
|
||||||
for (CFGBlock::const_succ_iterator I=B->succ_begin(),E=B->succ_end();I!=E;++I)
|
|
||||||
if (llvm::BitVector* V = getBlockEntryLiveness(*I))
|
|
||||||
Live |= *V;
|
|
||||||
|
|
||||||
if (Observer)
|
|
||||||
Observer->ObserveBlockExit(B,L,Live);
|
|
||||||
|
|
||||||
// Tentatively mark all variables alive at the end of the current block
|
|
||||||
// as being alive during the whole block. We then cull these out as
|
|
||||||
// we process the statements of this block.
|
|
||||||
for (LiveVariables::VarInfoMap::iterator
|
|
||||||
I=L.getVarInfoMap().begin(), E=L.getVarInfoMap().end(); I != E; ++I)
|
|
||||||
if (Live[I->second.Idx])
|
|
||||||
I->second.V.AliveBlocks.set(B->getBlockID());
|
|
||||||
|
|
||||||
// Visit the statements in reverse order;
|
|
||||||
VisitBlock(B);
|
|
||||||
|
|
||||||
// Compare the computed "Live" values with what we already have
|
|
||||||
// for the entry to this block.
|
|
||||||
bool hasChanged = false;
|
|
||||||
|
|
||||||
if (!blockPreviouslyProcessed) {
|
|
||||||
// We have not previously calculated liveness information for this block.
|
|
||||||
// Lazily instantiate a bitvector, and copy the bits from Live.
|
|
||||||
hasChanged = true;
|
|
||||||
llvm::BitVector& V = BMap[B];
|
|
||||||
V.resize(L.getNumDecls());
|
|
||||||
V = Live;
|
|
||||||
}
|
|
||||||
else if (BI->second != Live) {
|
|
||||||
hasChanged = true;
|
|
||||||
BI->second = Live;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hasChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// runOnCFG - Method to run the actual liveness computation.
|
|
||||||
//
|
|
||||||
|
|
||||||
void LiveVariables::runOnCFG(const CFG& cfg, LiveVariablesObserver* Observer) {
|
|
||||||
// Scan a CFG for DeclRefStmts. For each one, create a VarInfo object.
|
|
||||||
{
|
|
||||||
RegisterDecls R(*this,cfg);
|
|
||||||
R.RegisterUsedDecls();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the worklist and enqueue the exit block.
|
|
||||||
WorkListTy WorkList;
|
|
||||||
WorkList.enqueue(&cfg.getExit());
|
|
||||||
|
|
||||||
// Create the state for transfer functions.
|
|
||||||
LivenessTFuncs TF(*this,Observer);
|
|
||||||
|
|
||||||
// Process the worklist until it is empty.
|
|
||||||
|
|
||||||
while (!WorkList.isEmpty()) {
|
|
||||||
const CFGBlock* B = WorkList.dequeue();
|
|
||||||
if (TF.ProcessBlock(B))
|
|
||||||
for (CFGBlock::const_pred_iterator I = B->pred_begin(), E = B->pred_end();
|
|
||||||
I != E; ++I)
|
|
||||||
WorkList.enqueue(*I);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through each block and reserve a bitvector. This is needed if
|
|
||||||
// a block was never visited by the worklist algorithm.
|
|
||||||
for (CFG::const_iterator I = cfg.begin(), E = cfg.end(); I != E; ++I)
|
|
||||||
LiveAtBlockEntryMap[&(*I)].resize(NumDecls);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LiveVariables::runOnBlock(const CFGBlock* B,
|
|
||||||
LiveVariablesObserver* Observer)
|
|
||||||
{
|
|
||||||
LivenessTFuncs TF(*this,Observer);
|
|
||||||
TF.ProcessBlock(B);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// liveness queries
|
|
||||||
//
|
|
||||||
|
|
||||||
bool LiveVariables::isLive(const CFGBlock* B, const VarDecl* D) const {
|
|
||||||
BlockLivenessMap::const_iterator I = LiveAtBlockEntryMap.find(B);
|
|
||||||
assert (I != LiveAtBlockEntryMap.end());
|
|
||||||
|
|
||||||
VarInfoMap::const_iterator VI = VarInfos.find(D);
|
|
||||||
assert (VI != VarInfos.end());
|
|
||||||
|
|
||||||
return I->second[VI->second.Idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LiveVariables::isLive(llvm::BitVector& Live, const VarDecl* D) const {
|
|
||||||
VarInfoMap::const_iterator VI = VarInfos.find(D);
|
|
||||||
assert (VI != VarInfos.end());
|
|
||||||
return Live[VI->second.Idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LiveVariables::KillsVar(const Stmt* S, const VarDecl* D) const {
|
|
||||||
VarInfoMap::const_iterator VI = VarInfos.find(D);
|
|
||||||
assert (VI != VarInfos.end());
|
|
||||||
|
|
||||||
for (VarInfo::KillsSet::const_iterator
|
|
||||||
I = VI->second.V.Kills.begin(), E = VI->second.V.Kills.end(); I!=E;++I)
|
|
||||||
if (I->first == S)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LiveVariables::VarInfo& LiveVariables::getVarInfo(const VarDecl* D) {
|
|
||||||
VarInfoMap::iterator VI = VarInfos.find(D);
|
|
||||||
assert (VI != VarInfos.end());
|
|
||||||
return VI->second.V;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LiveVariables::VarInfo& LiveVariables::getVarInfo(const VarDecl* D) const{
|
|
||||||
return const_cast<LiveVariables*>(this)->getVarInfo(D);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Defaults for LiveVariablesObserver
|
|
||||||
|
|
||||||
void LiveVariablesObserver::ObserveStmt(Stmt* S, LiveVariables& L,
|
|
||||||
llvm::BitVector& V) {}
|
|
||||||
|
|
||||||
void LiveVariablesObserver::ObserveBlockExit(const CFGBlock* B,
|
|
||||||
LiveVariables& L,
|
|
||||||
llvm::BitVector& V) {}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// printing liveness state for debugging
|
|
||||||
//
|
|
||||||
|
|
||||||
void LiveVariables::dumpLiveness(const llvm::BitVector& V,
|
|
||||||
SourceManager& SM) const {
|
|
||||||
|
|
||||||
for (VarInfoMap::iterator I = VarInfos.begin(), E=VarInfos.end(); I!=E; ++I) {
|
|
||||||
if (V[I->second.Idx]) {
|
|
||||||
|
|
||||||
SourceLocation PhysLoc = SM.getPhysicalLoc(I->first->getLocation());
|
|
||||||
|
|
||||||
fprintf(stderr, " %s <%s:%u:%u>\n",
|
|
||||||
I->first->getIdentifier()->getName(),
|
|
||||||
SM.getSourceName(PhysLoc),
|
|
||||||
SM.getLineNumber(PhysLoc),
|
|
||||||
SM.getColumnNumber(PhysLoc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LiveVariables::dumpBlockLiveness(SourceManager& M) const {
|
|
||||||
for (BlockLivenessMap::iterator I = LiveAtBlockEntryMap.begin(),
|
|
||||||
E = LiveAtBlockEntryMap.end();
|
|
||||||
I != E; ++I) {
|
|
||||||
|
|
||||||
fprintf(stderr,
|
|
||||||
"\n[ B%d (live variables at block entry) ]\n",
|
|
||||||
I->first->getBlockID());
|
|
||||||
|
|
||||||
dumpLiveness(I->second,M);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr,"\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void LiveVariables::dumpVarLiveness(SourceManager& SM) const {
|
|
||||||
|
|
||||||
for (VarInfoMap::iterator I = VarInfos.begin(), E=VarInfos.end(); I!=E; ++I) {
|
|
||||||
SourceLocation PhysLoc = SM.getPhysicalLoc(I->first->getLocation());
|
|
||||||
|
|
||||||
fprintf(stderr, "[ %s <%s:%u:%u> ]\n",
|
|
||||||
I->first->getIdentifier()->getName(),
|
|
||||||
SM.getSourceName(PhysLoc),
|
|
||||||
SM.getLineNumber(PhysLoc),
|
|
||||||
SM.getColumnNumber(PhysLoc));
|
|
||||||
|
|
||||||
I->second.V.Dump(SM);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LiveVariables::VarInfo::Dump(SourceManager& SM) const {
|
|
||||||
fprintf(stderr," Blocks Alive:");
|
|
||||||
for (unsigned i = 0; i < AliveBlocks.size(); ++i) {
|
|
||||||
if (i % 5 == 0)
|
|
||||||
fprintf(stderr,"\n ");
|
|
||||||
|
|
||||||
fprintf(stderr," B%d", i);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr,"\n Kill Sites:\n");
|
|
||||||
for (KillsSet::const_iterator I = Kills.begin(), E = Kills.end(); I!=E; ++I) {
|
|
||||||
SourceLocation PhysLoc =
|
|
||||||
SM.getPhysicalLoc(I->second->getSourceRange().Begin());
|
|
||||||
|
|
||||||
fprintf(stderr, " <%s:%u:%u>\n",
|
|
||||||
SM.getSourceName(PhysLoc),
|
|
||||||
SM.getLineNumber(PhysLoc),
|
|
||||||
SM.getColumnNumber(PhysLoc));
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr,"\n");
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
##===- clang/CodeGen/Makefile ------------------------------*- Makefile -*-===##
|
|
||||||
#
|
|
||||||
# The LLVM Compiler Infrastructure
|
|
||||||
#
|
|
||||||
# This file was developed by Ted Kremenek and is distributed under
|
|
||||||
# the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
#
|
|
||||||
##===----------------------------------------------------------------------===##
|
|
||||||
#
|
|
||||||
# This implements analyses built on top of source-level CFGs.
|
|
||||||
#
|
|
||||||
##===----------------------------------------------------------------------===##
|
|
||||||
|
|
||||||
LEVEL = ../../..
|
|
||||||
LIBRARYNAME := clangAnalysis
|
|
||||||
BUILD_ARCHIVE = 1
|
|
||||||
CXXFLAGS = -fno-rtti
|
|
||||||
|
|
||||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.common
|
|
||||||
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
//===--- Diagnostic.cpp - C Language Family Diagnostic Handling -----------===//
|
|
||||||
//
|
|
||||||
// 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 Diagnostic-related interfaces.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "clang/Basic/SourceLocation.h"
|
|
||||||
#include <cassert>
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
/// Flag values for diagnostics.
|
|
||||||
enum {
|
|
||||||
// Diagnostic classes.
|
|
||||||
NOTE = 0x01,
|
|
||||||
WARNING = 0x02,
|
|
||||||
EXTENSION = 0x03,
|
|
||||||
ERROR = 0x04,
|
|
||||||
class_mask = 0x07
|
|
||||||
};
|
|
||||||
|
|
||||||
/// DiagnosticFlags - A set of flags, or'd together, that describe the
|
|
||||||
/// diagnostic.
|
|
||||||
static unsigned char DiagnosticFlags[] = {
|
|
||||||
#define DIAG(ENUM,FLAGS,DESC) FLAGS,
|
|
||||||
#include "clang/Basic/DiagnosticKinds.def"
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
/// getDiagClass - Return the class field of the diagnostic.
|
|
||||||
///
|
|
||||||
static unsigned getDiagClass(unsigned DiagID) {
|
|
||||||
assert(DiagID < diag::NUM_DIAGNOSTICS && "Diagnostic ID out of range!");
|
|
||||||
return DiagnosticFlags[DiagID] & class_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// DiagnosticText - An english message to print for the diagnostic. These
|
|
||||||
/// should be localized.
|
|
||||||
static const char * const DiagnosticText[] = {
|
|
||||||
#define DIAG(ENUM,FLAGS,DESC) DESC,
|
|
||||||
#include "clang/Basic/DiagnosticKinds.def"
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
Diagnostic::Diagnostic(DiagnosticClient &client) : Client(client) {
|
|
||||||
WarningsAsErrors = false;
|
|
||||||
WarnOnExtensions = false;
|
|
||||||
ErrorOnExtensions = false;
|
|
||||||
// Clear all mappings, setting them to MAP_DEFAULT.
|
|
||||||
memset(DiagMappings, 0, sizeof(DiagMappings));
|
|
||||||
|
|
||||||
ErrorOccurred = false;
|
|
||||||
NumDiagnostics = 0;
|
|
||||||
NumErrors = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// isNoteWarningOrExtension - Return true if the unmapped diagnostic level of
|
|
||||||
/// the specified diagnostic ID is a Note, Warning, or Extension.
|
|
||||||
bool Diagnostic::isNoteWarningOrExtension(unsigned DiagID) {
|
|
||||||
return getDiagClass(DiagID) < ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// getDescription - Given a diagnostic ID, return a description of the
|
|
||||||
/// issue.
|
|
||||||
const char *Diagnostic::getDescription(unsigned DiagID) {
|
|
||||||
assert(DiagID < diag::NUM_DIAGNOSTICS && "Diagnostic ID out of range!");
|
|
||||||
return DiagnosticText[DiagID];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
|
|
||||||
/// object, classify the specified diagnostic ID into a Level, consumable by
|
|
||||||
/// the DiagnosticClient.
|
|
||||||
Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const {
|
|
||||||
unsigned DiagClass = getDiagClass(DiagID);
|
|
||||||
|
|
||||||
// Specific non-error diagnostics may be mapped to various levels from ignored
|
|
||||||
// to error.
|
|
||||||
if (DiagClass < ERROR) {
|
|
||||||
switch (getDiagnosticMapping((diag::kind)DiagID)) {
|
|
||||||
case diag::MAP_DEFAULT: break;
|
|
||||||
case diag::MAP_IGNORE: return Ignored;
|
|
||||||
case diag::MAP_WARNING: DiagClass = WARNING; break;
|
|
||||||
case diag::MAP_ERROR: DiagClass = ERROR; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map diagnostic classes based on command line argument settings.
|
|
||||||
if (DiagClass == EXTENSION) {
|
|
||||||
if (ErrorOnExtensions)
|
|
||||||
DiagClass = ERROR;
|
|
||||||
else if (WarnOnExtensions)
|
|
||||||
DiagClass = WARNING;
|
|
||||||
else
|
|
||||||
return Ignored;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If warnings are to be treated as errors, indicate this as such.
|
|
||||||
if (DiagClass == WARNING && WarningsAsErrors)
|
|
||||||
DiagClass = ERROR;
|
|
||||||
|
|
||||||
switch (DiagClass) {
|
|
||||||
default: assert(0 && "Unknown diagnostic class!");
|
|
||||||
case NOTE: return Diagnostic::Note;
|
|
||||||
case WARNING: return Diagnostic::Warning;
|
|
||||||
case ERROR: return Diagnostic::Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Report - Issue the message to the client. If the client wants us to stop
|
|
||||||
/// compilation, return true, otherwise return false. DiagID is a member of
|
|
||||||
/// the diag::kind enum.
|
|
||||||
void Diagnostic::Report(SourceLocation Pos, unsigned DiagID,
|
|
||||||
const std::string *Strs, unsigned NumStrs,
|
|
||||||
const SourceRange *Ranges, unsigned NumRanges) {
|
|
||||||
// Figure out the diagnostic level of this message.
|
|
||||||
Diagnostic::Level DiagLevel = getDiagnosticLevel(DiagID);
|
|
||||||
|
|
||||||
// If the client doesn't care about this message, don't issue it.
|
|
||||||
if (DiagLevel == Diagnostic::Ignored)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (DiagLevel >= Diagnostic::Error) {
|
|
||||||
ErrorOccurred = true;
|
|
||||||
++NumErrors;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Are we going to ignore this diagnosic?
|
|
||||||
if (Client.IgnoreDiagnostic(DiagLevel, Pos))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Finally, report it.
|
|
||||||
Client.HandleDiagnostic(DiagLevel, Pos, (diag::kind)DiagID, Strs, NumStrs,
|
|
||||||
Ranges, NumRanges);
|
|
||||||
++NumDiagnostics;
|
|
||||||
}
|
|
||||||
|
|
||||||
DiagnosticClient::~DiagnosticClient() {}
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
//===--- FileManager.cpp - File System Probing and Caching ----------------===//
|
|
||||||
//
|
|
||||||
// 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 FileManager interface.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// TODO: This should index all interesting directories with dirent calls.
|
|
||||||
// getdirentries ?
|
|
||||||
// opendir/readdir_r/closedir ?
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Basic/FileManager.h"
|
|
||||||
#include "llvm/ADT/SmallString.h"
|
|
||||||
#include <iostream>
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
// FIXME: Enhance libsystem to support inode and other fields.
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#define S_ISDIR(s) (_S_IFDIR & s)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// NON_EXISTANT_DIR - A special value distinct from null that is used to
|
|
||||||
/// represent a dir name that doesn't exist on the disk.
|
|
||||||
#define NON_EXISTANT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
|
|
||||||
|
|
||||||
/// getDirectory - Lookup, cache, and verify the specified directory. This
|
|
||||||
/// returns null if the directory doesn't exist.
|
|
||||||
///
|
|
||||||
const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
|
|
||||||
const char *NameEnd) {
|
|
||||||
++NumDirLookups;
|
|
||||||
llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
|
|
||||||
DirEntries.GetOrCreateValue(NameStart, NameEnd);
|
|
||||||
|
|
||||||
// See if there is already an entry in the map.
|
|
||||||
if (NamedDirEnt.getValue())
|
|
||||||
return NamedDirEnt.getValue() == NON_EXISTANT_DIR
|
|
||||||
? 0 : NamedDirEnt.getValue();
|
|
||||||
|
|
||||||
++NumDirCacheMisses;
|
|
||||||
|
|
||||||
// By default, initialize it to invalid.
|
|
||||||
NamedDirEnt.setValue(NON_EXISTANT_DIR);
|
|
||||||
|
|
||||||
// Get the null-terminated directory name as stored as the key of the
|
|
||||||
// DirEntries map.
|
|
||||||
const char *InterndDirName = NamedDirEnt.getKeyData();
|
|
||||||
|
|
||||||
// Check to see if the directory exists.
|
|
||||||
struct stat StatBuf;
|
|
||||||
if (stat(InterndDirName, &StatBuf) || // Error stat'ing.
|
|
||||||
!S_ISDIR(StatBuf.st_mode)) // Not a directory?
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// It exists. See if we have already opened a directory with the same inode.
|
|
||||||
// This occurs when one dir is symlinked to another, for example.
|
|
||||||
DirectoryEntry &UDE =
|
|
||||||
UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
|
|
||||||
|
|
||||||
NamedDirEnt.setValue(&UDE);
|
|
||||||
if (UDE.getName()) // Already have an entry with this inode, return it.
|
|
||||||
return &UDE;
|
|
||||||
|
|
||||||
// Otherwise, we don't have this directory yet, add it. We use the string
|
|
||||||
// key from the DirEntries map as the string.
|
|
||||||
UDE.Name = InterndDirName;
|
|
||||||
return &UDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// NON_EXISTANT_FILE - A special value distinct from null that is used to
|
|
||||||
/// represent a filename that doesn't exist on the disk.
|
|
||||||
#define NON_EXISTANT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
|
|
||||||
|
|
||||||
/// getFile - Lookup, cache, and verify the specified file. This returns null
|
|
||||||
/// if the file doesn't exist.
|
|
||||||
///
|
|
||||||
const FileEntry *FileManager::getFile(const char *NameStart,
|
|
||||||
const char *NameEnd) {
|
|
||||||
++NumFileLookups;
|
|
||||||
|
|
||||||
// See if there is already an entry in the map.
|
|
||||||
llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
|
|
||||||
FileEntries.GetOrCreateValue(NameStart, NameEnd);
|
|
||||||
|
|
||||||
// See if there is already an entry in the map.
|
|
||||||
if (NamedFileEnt.getValue())
|
|
||||||
return NamedFileEnt.getValue() == NON_EXISTANT_FILE
|
|
||||||
? 0 : NamedFileEnt.getValue();
|
|
||||||
|
|
||||||
++NumFileCacheMisses;
|
|
||||||
|
|
||||||
// By default, initialize it to invalid.
|
|
||||||
NamedFileEnt.setValue(NON_EXISTANT_FILE);
|
|
||||||
|
|
||||||
// Figure out what directory it is in. If the string contains a / in it,
|
|
||||||
// strip off everything after it.
|
|
||||||
// FIXME: this logic should be in sys::Path.
|
|
||||||
const char *SlashPos = NameEnd-1;
|
|
||||||
while (SlashPos >= NameStart && SlashPos[0] != '/')
|
|
||||||
--SlashPos;
|
|
||||||
|
|
||||||
const DirectoryEntry *DirInfo;
|
|
||||||
if (SlashPos < NameStart) {
|
|
||||||
// Use the current directory if file has no path component.
|
|
||||||
const char *Name = ".";
|
|
||||||
DirInfo = getDirectory(Name, Name+1);
|
|
||||||
} else if (SlashPos == NameEnd-1)
|
|
||||||
return 0; // If filename ends with a /, it's a directory.
|
|
||||||
else
|
|
||||||
DirInfo = getDirectory(NameStart, SlashPos);
|
|
||||||
|
|
||||||
if (DirInfo == 0) // Directory doesn't exist, file can't exist.
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Get the null-terminated file name as stored as the key of the
|
|
||||||
// FileEntries map.
|
|
||||||
const char *InterndFileName = NamedFileEnt.getKeyData();
|
|
||||||
|
|
||||||
// FIXME: Use the directory info to prune this, before doing the stat syscall.
|
|
||||||
// FIXME: This will reduce the # syscalls.
|
|
||||||
|
|
||||||
// Nope, there isn't. Check to see if the file exists.
|
|
||||||
struct stat StatBuf;
|
|
||||||
//std::cerr << "STATING: " << Filename;
|
|
||||||
if (stat(InterndFileName, &StatBuf) || // Error stat'ing.
|
|
||||||
S_ISDIR(StatBuf.st_mode)) { // A directory?
|
|
||||||
// If this file doesn't exist, we leave a null in FileEntries for this path.
|
|
||||||
//std::cerr << ": Not existing\n";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
//std::cerr << ": exists\n";
|
|
||||||
|
|
||||||
// It exists. See if we have already opened a directory with the same inode.
|
|
||||||
// This occurs when one dir is symlinked to another, for example.
|
|
||||||
FileEntry &UFE = UniqueFiles[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
|
|
||||||
|
|
||||||
NamedFileEnt.setValue(&UFE);
|
|
||||||
if (UFE.getName()) // Already have an entry with this inode, return it.
|
|
||||||
return &UFE;
|
|
||||||
|
|
||||||
// Otherwise, we don't have this directory yet, add it.
|
|
||||||
// FIXME: Change the name to be a char* that points back to the 'FileEntries'
|
|
||||||
// key.
|
|
||||||
UFE.Name = InterndFileName;
|
|
||||||
UFE.Size = StatBuf.st_size;
|
|
||||||
UFE.ModTime = StatBuf.st_mtime;
|
|
||||||
UFE.Dir = DirInfo;
|
|
||||||
UFE.UID = NextFileUID++;
|
|
||||||
return &UFE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileManager::PrintStats() const {
|
|
||||||
std::cerr << "\n*** File Manager Stats:\n";
|
|
||||||
std::cerr << UniqueFiles.size() << " files found, "
|
|
||||||
<< UniqueDirs.size() << " dirs found.\n";
|
|
||||||
std::cerr << NumDirLookups << " dir lookups, "
|
|
||||||
<< NumDirCacheMisses << " dir cache misses.\n";
|
|
||||||
std::cerr << NumFileLookups << " file lookups, "
|
|
||||||
<< NumFileCacheMisses << " file cache misses.\n";
|
|
||||||
|
|
||||||
//std::cerr << PagesMapped << BytesOfPagesMapped << FSLookups;
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
##===- clang/Basic/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 Basic library for the C-Language front-end.
|
|
||||||
#
|
|
||||||
##===----------------------------------------------------------------------===##
|
|
||||||
|
|
||||||
LEVEL = ../../..
|
|
||||||
LIBRARYNAME := clangBasic
|
|
||||||
BUILD_ARCHIVE = 1
|
|
||||||
CXXFLAGS = -fno-rtti
|
|
||||||
|
|
||||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.common
|
|
||||||
|
|
||||||
@@ -1,409 +0,0 @@
|
|||||||
//===--- SourceManager.cpp - Track and cache source files -----------------===//
|
|
||||||
//
|
|
||||||
// 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 SourceManager interface.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
#include "clang/Basic/FileManager.h"
|
|
||||||
#include "llvm/Config/config.h"
|
|
||||||
#include "llvm/Support/Compiler.h"
|
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
|
||||||
#include "llvm/System/Path.h"
|
|
||||||
#include <algorithm>
|
|
||||||
#include <iostream>
|
|
||||||
#include <fcntl.h>
|
|
||||||
using namespace clang;
|
|
||||||
using namespace SrcMgr;
|
|
||||||
using llvm::MemoryBuffer;
|
|
||||||
|
|
||||||
SourceManager::~SourceManager() {
|
|
||||||
for (std::map<const FileEntry *, FileInfo>::iterator I = FileInfos.begin(),
|
|
||||||
E = FileInfos.end(); I != E; ++I) {
|
|
||||||
delete I->second.Buffer;
|
|
||||||
delete[] I->second.SourceLineCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::list<InfoRec>::iterator I = MemBufferInfos.begin(),
|
|
||||||
E = MemBufferInfos.end(); I != E; ++I) {
|
|
||||||
delete I->second.Buffer;
|
|
||||||
delete[] I->second.SourceLineCache;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// FIXME: REMOVE THESE
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#if !defined(_MSC_VER)
|
|
||||||
#include <sys/uio.h>
|
|
||||||
#include <sys/fcntl.h>
|
|
||||||
#else
|
|
||||||
#include <io.h>
|
|
||||||
#endif
|
|
||||||
#include <cerrno>
|
|
||||||
|
|
||||||
static const MemoryBuffer *ReadFileFast(const FileEntry *FileEnt) {
|
|
||||||
#if 0
|
|
||||||
// FIXME: Reintroduce this and zap this function once the common llvm stuff
|
|
||||||
// is fast for the small case.
|
|
||||||
return MemoryBuffer::getFile(FileEnt->getName(), strlen(FileEnt->getName()),
|
|
||||||
FileEnt->getSize());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// If the file is larger than some threshold, use 'read', otherwise use mmap.
|
|
||||||
if (FileEnt->getSize() >= 4096*4)
|
|
||||||
return MemoryBuffer::getFile(FileEnt->getName(), strlen(FileEnt->getName()),
|
|
||||||
0, FileEnt->getSize());
|
|
||||||
|
|
||||||
MemoryBuffer *SB = MemoryBuffer::getNewUninitMemBuffer(FileEnt->getSize(),
|
|
||||||
FileEnt->getName());
|
|
||||||
char *BufPtr = const_cast<char*>(SB->getBufferStart());
|
|
||||||
|
|
||||||
#if defined(LLVM_ON_WIN32)
|
|
||||||
int FD = ::open(FileEnt->getName(), O_RDONLY|O_BINARY);
|
|
||||||
#else
|
|
||||||
int FD = ::open(FileEnt->getName(), O_RDONLY);
|
|
||||||
#endif
|
|
||||||
if (FD == -1) {
|
|
||||||
delete SB;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned BytesLeft = FileEnt->getSize();
|
|
||||||
while (BytesLeft) {
|
|
||||||
ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
|
|
||||||
if (NumRead != -1) {
|
|
||||||
BytesLeft -= NumRead;
|
|
||||||
BufPtr += NumRead;
|
|
||||||
} else if (errno == EINTR) {
|
|
||||||
// try again
|
|
||||||
} else {
|
|
||||||
// error reading.
|
|
||||||
close(FD);
|
|
||||||
delete SB;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(FD);
|
|
||||||
|
|
||||||
return SB;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// getFileInfo - Create or return a cached FileInfo for the specified file.
|
|
||||||
///
|
|
||||||
const InfoRec *
|
|
||||||
SourceManager::getInfoRec(const FileEntry *FileEnt) {
|
|
||||||
assert(FileEnt && "Didn't specify a file entry to use?");
|
|
||||||
// Do we already have information about this file?
|
|
||||||
std::map<const FileEntry *, FileInfo>::iterator I =
|
|
||||||
FileInfos.lower_bound(FileEnt);
|
|
||||||
if (I != FileInfos.end() && I->first == FileEnt)
|
|
||||||
return &*I;
|
|
||||||
|
|
||||||
// Nope, get information.
|
|
||||||
const MemoryBuffer *File = ReadFileFast(FileEnt);
|
|
||||||
if (File == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
const InfoRec &Entry =
|
|
||||||
*FileInfos.insert(I, std::make_pair(FileEnt, FileInfo()));
|
|
||||||
FileInfo &Info = const_cast<FileInfo &>(Entry.second);
|
|
||||||
|
|
||||||
Info.Buffer = File;
|
|
||||||
Info.SourceLineCache = 0;
|
|
||||||
Info.NumLines = 0;
|
|
||||||
return &Entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// createMemBufferInfoRec - Create a new info record for the specified memory
|
|
||||||
/// buffer. This does no caching.
|
|
||||||
const InfoRec *
|
|
||||||
SourceManager::createMemBufferInfoRec(const MemoryBuffer *Buffer) {
|
|
||||||
// Add a new info record to the MemBufferInfos list and return it.
|
|
||||||
FileInfo FI;
|
|
||||||
FI.Buffer = Buffer;
|
|
||||||
FI.SourceLineCache = 0;
|
|
||||||
FI.NumLines = 0;
|
|
||||||
MemBufferInfos.push_back(InfoRec(0, FI));
|
|
||||||
return &MemBufferInfos.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// createFileID - Create a new fileID for the specified InfoRec and include
|
|
||||||
/// position. This works regardless of whether the InfoRec corresponds to a
|
|
||||||
/// file or some other input source.
|
|
||||||
unsigned SourceManager::createFileID(const InfoRec *File,
|
|
||||||
SourceLocation IncludePos) {
|
|
||||||
// If FileEnt is really large (e.g. it's a large .i file), we may not be able
|
|
||||||
// to fit an arbitrary position in the file in the FilePos field. To handle
|
|
||||||
// this, we create one FileID for each chunk of the file that fits in a
|
|
||||||
// FilePos field.
|
|
||||||
unsigned FileSize = File->second.Buffer->getBufferSize();
|
|
||||||
if (FileSize+1 < (1 << SourceLocation::FilePosBits)) {
|
|
||||||
FileIDs.push_back(FileIDInfo::get(IncludePos, 0, File));
|
|
||||||
assert(FileIDs.size() < (1 << SourceLocation::FileIDBits) &&
|
|
||||||
"Ran out of file ID's!");
|
|
||||||
return FileIDs.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create one FileID for each chunk of the file.
|
|
||||||
unsigned Result = FileIDs.size()+1;
|
|
||||||
|
|
||||||
unsigned ChunkNo = 0;
|
|
||||||
while (1) {
|
|
||||||
FileIDs.push_back(FileIDInfo::get(IncludePos, ChunkNo++, File));
|
|
||||||
|
|
||||||
if (FileSize+1 < (1 << SourceLocation::FilePosBits)) break;
|
|
||||||
FileSize -= (1 << SourceLocation::FilePosBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(FileIDs.size() < (1 << SourceLocation::FileIDBits) &&
|
|
||||||
"Ran out of file ID's!");
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getInstantiationLoc - Return a new SourceLocation that encodes the fact
|
|
||||||
/// that a token from physloc PhysLoc should actually be referenced from
|
|
||||||
/// InstantiationLoc.
|
|
||||||
SourceLocation SourceManager::getInstantiationLoc(SourceLocation PhysLoc,
|
|
||||||
SourceLocation InstantLoc) {
|
|
||||||
// The specified source location may be a mapped location, due to a macro
|
|
||||||
// instantiation or #line directive. Strip off this information to find out
|
|
||||||
// where the characters are actually located.
|
|
||||||
PhysLoc = getPhysicalLoc(PhysLoc);
|
|
||||||
|
|
||||||
// Resolve InstantLoc down to a real logical location.
|
|
||||||
InstantLoc = getLogicalLoc(InstantLoc);
|
|
||||||
|
|
||||||
|
|
||||||
// If the last macro id is close to the currently requested location, try to
|
|
||||||
// reuse it. This implements a small cache.
|
|
||||||
for (int i = MacroIDs.size()-1, e = MacroIDs.size()-6; i >= 0 && i != e; --i){
|
|
||||||
MacroIDInfo &LastOne = MacroIDs[i];
|
|
||||||
|
|
||||||
// The instanitation point and source physloc have to exactly match to reuse
|
|
||||||
// (for now). We could allow "nearby" instantiations in the future.
|
|
||||||
if (LastOne.getInstantiationLoc() != InstantLoc ||
|
|
||||||
LastOne.getPhysicalLoc().getFileID() != PhysLoc.getFileID())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Check to see if the physloc of the token came from near enough to reuse.
|
|
||||||
int PhysDelta = PhysLoc.getRawFilePos() -
|
|
||||||
LastOne.getPhysicalLoc().getRawFilePos();
|
|
||||||
if (SourceLocation::isValidMacroPhysOffs(PhysDelta))
|
|
||||||
return SourceLocation::getMacroLoc(i, PhysDelta, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MacroIDs.push_back(MacroIDInfo::get(InstantLoc, PhysLoc));
|
|
||||||
return SourceLocation::getMacroLoc(MacroIDs.size()-1, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// getCharacterData - Return a pointer to the start of the specified location
|
|
||||||
/// in the appropriate MemoryBuffer.
|
|
||||||
const char *SourceManager::getCharacterData(SourceLocation SL) const {
|
|
||||||
// Note that this is a hot function in the getSpelling() path, which is
|
|
||||||
// heavily used by -E mode.
|
|
||||||
SL = getPhysicalLoc(SL);
|
|
||||||
|
|
||||||
return getFileInfo(SL.getFileID())->Buffer->getBufferStart() +
|
|
||||||
getFullFilePos(SL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// getColumnNumber - Return the column # for the specified file position.
|
|
||||||
/// this is significantly cheaper to compute than the line number. This returns
|
|
||||||
/// zero if the column number isn't known.
|
|
||||||
unsigned SourceManager::getColumnNumber(SourceLocation Loc) const {
|
|
||||||
unsigned FileID = Loc.getFileID();
|
|
||||||
if (FileID == 0) return 0;
|
|
||||||
|
|
||||||
unsigned FilePos = getFullFilePos(Loc);
|
|
||||||
const MemoryBuffer *Buffer = getBuffer(FileID);
|
|
||||||
const char *Buf = Buffer->getBufferStart();
|
|
||||||
|
|
||||||
unsigned LineStart = FilePos;
|
|
||||||
while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
|
|
||||||
--LineStart;
|
|
||||||
return FilePos-LineStart+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getSourceName - This method returns the name of the file or buffer that
|
|
||||||
/// the SourceLocation specifies. This can be modified with #line directives,
|
|
||||||
/// etc.
|
|
||||||
const char *SourceManager::getSourceName(SourceLocation Loc) const {
|
|
||||||
unsigned FileID = Loc.getFileID();
|
|
||||||
if (FileID == 0) return "";
|
|
||||||
return getFileInfo(FileID)->Buffer->getBufferIdentifier();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ComputeLineNumbers(FileInfo *FI) DISABLE_INLINE;
|
|
||||||
static void ComputeLineNumbers(FileInfo *FI) {
|
|
||||||
const MemoryBuffer *Buffer = FI->Buffer;
|
|
||||||
|
|
||||||
// Find the file offsets of all of the *physical* source lines. This does
|
|
||||||
// not look at trigraphs, escaped newlines, or anything else tricky.
|
|
||||||
std::vector<unsigned> LineOffsets;
|
|
||||||
|
|
||||||
// Line #1 starts at char 0.
|
|
||||||
LineOffsets.push_back(0);
|
|
||||||
|
|
||||||
const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart();
|
|
||||||
const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd();
|
|
||||||
unsigned Offs = 0;
|
|
||||||
while (1) {
|
|
||||||
// Skip over the contents of the line.
|
|
||||||
// TODO: Vectorize this? This is very performance sensitive for programs
|
|
||||||
// with lots of diagnostics and in -E mode.
|
|
||||||
const unsigned char *NextBuf = (const unsigned char *)Buf;
|
|
||||||
while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0')
|
|
||||||
++NextBuf;
|
|
||||||
Offs += NextBuf-Buf;
|
|
||||||
Buf = NextBuf;
|
|
||||||
|
|
||||||
if (Buf[0] == '\n' || Buf[0] == '\r') {
|
|
||||||
// If this is \n\r or \r\n, skip both characters.
|
|
||||||
if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1])
|
|
||||||
++Offs, ++Buf;
|
|
||||||
++Offs, ++Buf;
|
|
||||||
LineOffsets.push_back(Offs);
|
|
||||||
} else {
|
|
||||||
// Otherwise, this is a null. If end of file, exit.
|
|
||||||
if (Buf == End) break;
|
|
||||||
// Otherwise, skip the null.
|
|
||||||
++Offs, ++Buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LineOffsets.push_back(Offs);
|
|
||||||
|
|
||||||
// Copy the offsets into the FileInfo structure.
|
|
||||||
FI->NumLines = LineOffsets.size();
|
|
||||||
FI->SourceLineCache = new unsigned[LineOffsets.size()];
|
|
||||||
std::copy(LineOffsets.begin(), LineOffsets.end(), FI->SourceLineCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getLineNumber - Given a SourceLocation, return the physical line number
|
|
||||||
/// for the position indicated. This requires building and caching a table of
|
|
||||||
/// line offsets for the MemoryBuffer, so this is not cheap: use only when
|
|
||||||
/// about to emit a diagnostic.
|
|
||||||
unsigned SourceManager::getLineNumber(SourceLocation Loc) {
|
|
||||||
unsigned FileID = Loc.getFileID();
|
|
||||||
if (FileID == 0) return 0;
|
|
||||||
FileInfo *FileInfo;
|
|
||||||
|
|
||||||
if (LastLineNoFileIDQuery == FileID)
|
|
||||||
FileInfo = LastLineNoFileInfo;
|
|
||||||
else
|
|
||||||
FileInfo = getFileInfo(FileID);
|
|
||||||
|
|
||||||
// If this is the first use of line information for this buffer, compute the
|
|
||||||
/// SourceLineCache for it on demand.
|
|
||||||
if (FileInfo->SourceLineCache == 0)
|
|
||||||
ComputeLineNumbers(FileInfo);
|
|
||||||
|
|
||||||
// Okay, we know we have a line number table. Do a binary search to find the
|
|
||||||
// line number that this character position lands on.
|
|
||||||
unsigned *SourceLineCache = FileInfo->SourceLineCache;
|
|
||||||
unsigned *SourceLineCacheStart = SourceLineCache;
|
|
||||||
unsigned *SourceLineCacheEnd = SourceLineCache + FileInfo->NumLines;
|
|
||||||
|
|
||||||
unsigned QueriedFilePos = getFullFilePos(Loc)+1;
|
|
||||||
|
|
||||||
// If the previous query was to the same file, we know both the file pos from
|
|
||||||
// that query and the line number returned. This allows us to narrow the
|
|
||||||
// search space from the entire file to something near the match.
|
|
||||||
if (LastLineNoFileIDQuery == FileID) {
|
|
||||||
if (QueriedFilePos >= LastLineNoFilePos) {
|
|
||||||
SourceLineCache = SourceLineCache+LastLineNoResult-1;
|
|
||||||
|
|
||||||
// The query is likely to be nearby the previous one. Here we check to
|
|
||||||
// see if it is within 5, 10 or 20 lines. It can be far away in cases
|
|
||||||
// where big comment blocks and vertical whitespace eat up lines but
|
|
||||||
// contribute no tokens.
|
|
||||||
if (SourceLineCache+5 < SourceLineCacheEnd) {
|
|
||||||
if (SourceLineCache[5] > QueriedFilePos)
|
|
||||||
SourceLineCacheEnd = SourceLineCache+5;
|
|
||||||
else if (SourceLineCache+10 < SourceLineCacheEnd) {
|
|
||||||
if (SourceLineCache[10] > QueriedFilePos)
|
|
||||||
SourceLineCacheEnd = SourceLineCache+10;
|
|
||||||
else if (SourceLineCache+20 < SourceLineCacheEnd) {
|
|
||||||
if (SourceLineCache[20] > QueriedFilePos)
|
|
||||||
SourceLineCacheEnd = SourceLineCache+20;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the spread is large, do a "radix" test as our initial guess, based on
|
|
||||||
// the assumption that lines average to approximately the same length.
|
|
||||||
// NOTE: This is currently disabled, as it does not appear to be profitable in
|
|
||||||
// initial measurements.
|
|
||||||
if (0 && SourceLineCacheEnd-SourceLineCache > 20) {
|
|
||||||
unsigned FileLen = FileInfo->SourceLineCache[FileInfo->NumLines-1];
|
|
||||||
|
|
||||||
// Take a stab at guessing where it is.
|
|
||||||
unsigned ApproxPos = FileInfo->NumLines*QueriedFilePos / FileLen;
|
|
||||||
|
|
||||||
// Check for -10 and +10 lines.
|
|
||||||
unsigned LowerBound = std::max(int(ApproxPos-10), 0);
|
|
||||||
unsigned UpperBound = std::min(ApproxPos+10, FileLen);
|
|
||||||
|
|
||||||
// If the computed lower bound is less than the query location, move it in.
|
|
||||||
if (SourceLineCache < SourceLineCacheStart+LowerBound &&
|
|
||||||
SourceLineCacheStart[LowerBound] < QueriedFilePos)
|
|
||||||
SourceLineCache = SourceLineCacheStart+LowerBound;
|
|
||||||
|
|
||||||
// If the computed upper bound is greater than the query location, move it.
|
|
||||||
if (SourceLineCacheEnd > SourceLineCacheStart+UpperBound &&
|
|
||||||
SourceLineCacheStart[UpperBound] >= QueriedFilePos)
|
|
||||||
SourceLineCacheEnd = SourceLineCacheStart+UpperBound;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned *Pos
|
|
||||||
= std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos);
|
|
||||||
unsigned LineNo = Pos-SourceLineCacheStart;
|
|
||||||
|
|
||||||
LastLineNoFileIDQuery = FileID;
|
|
||||||
LastLineNoFileInfo = FileInfo;
|
|
||||||
LastLineNoFilePos = QueriedFilePos;
|
|
||||||
LastLineNoResult = LineNo;
|
|
||||||
return LineNo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PrintStats - Print statistics to stderr.
|
|
||||||
///
|
|
||||||
void SourceManager::PrintStats() const {
|
|
||||||
std::cerr << "\n*** Source Manager Stats:\n";
|
|
||||||
std::cerr << FileInfos.size() << " files mapped, " << MemBufferInfos.size()
|
|
||||||
<< " mem buffers mapped, " << FileIDs.size()
|
|
||||||
<< " file ID's allocated.\n";
|
|
||||||
std::cerr << " " << FileIDs.size() << " normal buffer FileID's, "
|
|
||||||
<< MacroIDs.size() << " macro expansion FileID's.\n";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned NumLineNumsComputed = 0;
|
|
||||||
unsigned NumFileBytesMapped = 0;
|
|
||||||
for (std::map<const FileEntry *, FileInfo>::const_iterator I =
|
|
||||||
FileInfos.begin(), E = FileInfos.end(); I != E; ++I) {
|
|
||||||
NumLineNumsComputed += I->second.SourceLineCache != 0;
|
|
||||||
NumFileBytesMapped += I->second.Buffer->getBufferSize();
|
|
||||||
}
|
|
||||||
std::cerr << NumFileBytesMapped << " bytes of files mapped, "
|
|
||||||
<< NumLineNumsComputed << " files with line #'s computed.\n";
|
|
||||||
}
|
|
||||||
@@ -1,248 +0,0 @@
|
|||||||
//===--- TargetInfo.cpp - Information about Target machine ----------------===//
|
|
||||||
//
|
|
||||||
// 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 TargetInfo and TargetInfoImpl interfaces.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Basic/TargetInfo.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "clang/AST/Builtins.h"
|
|
||||||
#include "llvm/ADT/StringMap.h"
|
|
||||||
#include <set>
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
void TargetInfoImpl::ANCHOR() {} // out-of-line virtual method for class.
|
|
||||||
|
|
||||||
|
|
||||||
/// DiagnoseNonPortability - When a use of a non-portable target feature is
|
|
||||||
/// used, this method emits the diagnostic and marks the translation unit as
|
|
||||||
/// non-portable.
|
|
||||||
void TargetInfo::DiagnoseNonPortability(SourceLocation Loc, unsigned DiagKind) {
|
|
||||||
NonPortable = true;
|
|
||||||
if (Diag && Loc.isValid()) Diag->Report(Loc, DiagKind);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// GetTargetDefineMap - Get the set of target #defines in an associative
|
|
||||||
/// collection for easy lookup.
|
|
||||||
static void GetTargetDefineMap(const TargetInfoImpl *Target,
|
|
||||||
llvm::StringMap<std::string> &Map) {
|
|
||||||
std::vector<std::string> PrimaryDefines;
|
|
||||||
Target->getTargetDefines(PrimaryDefines);
|
|
||||||
|
|
||||||
while (!PrimaryDefines.empty()) {
|
|
||||||
std::string &PrimDefineStr = PrimaryDefines.back();
|
|
||||||
const char *Str = PrimDefineStr.c_str();
|
|
||||||
const char *StrEnd = Str+PrimDefineStr.size();
|
|
||||||
|
|
||||||
if (const char *Equal = strchr(Str, '=')) {
|
|
||||||
// Split at the '='.
|
|
||||||
|
|
||||||
std::string &Entry = Map.GetOrCreateValue(Str, Equal).getValue();
|
|
||||||
Entry = std::string(Equal+1, StrEnd);
|
|
||||||
} else {
|
|
||||||
// Remember "macroname=1".
|
|
||||||
std::string &Entry = Map.GetOrCreateValue(Str, StrEnd).getValue();
|
|
||||||
Entry = "1";
|
|
||||||
}
|
|
||||||
PrimaryDefines.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getTargetDefines - Appends the target-specific #define values for this
|
|
||||||
/// target set to the specified buffer.
|
|
||||||
void TargetInfo::getTargetDefines(std::vector<char> &Buffer) {
|
|
||||||
// This is tricky in the face of secondary targets. Specifically,
|
|
||||||
// target-specific #defines that are present and identical across all
|
|
||||||
// secondary targets are turned into #defines, #defines that are present in
|
|
||||||
// the primary target but are missing or different in the secondary targets
|
|
||||||
// are turned into #define_target, and #defines that are not defined in the
|
|
||||||
// primary, but are defined in a secondary are turned into
|
|
||||||
// #define_other_target. This allows the preprocessor to correctly track uses
|
|
||||||
// of target-specific macros.
|
|
||||||
|
|
||||||
// Get the set of primary #defines.
|
|
||||||
llvm::StringMap<std::string> PrimaryDefines;
|
|
||||||
GetTargetDefineMap(PrimaryTarget, PrimaryDefines);
|
|
||||||
|
|
||||||
// If we have no secondary targets, be a bit more efficient.
|
|
||||||
if (SecondaryTargets.empty()) {
|
|
||||||
for (llvm::StringMap<std::string>::iterator I =
|
|
||||||
PrimaryDefines.begin(), E = PrimaryDefines.end(); I != E; ++I) {
|
|
||||||
// If this define is non-portable, turn it into #define_target, otherwise
|
|
||||||
// just use #define.
|
|
||||||
const char *Command = "#define ";
|
|
||||||
Buffer.insert(Buffer.end(), Command, Command+strlen(Command));
|
|
||||||
|
|
||||||
// Insert "defname defvalue\n".
|
|
||||||
const char *KeyStart = I->getKeyData();
|
|
||||||
const char *KeyEnd = KeyStart + I->getKeyLength();
|
|
||||||
|
|
||||||
Buffer.insert(Buffer.end(), KeyStart, KeyEnd);
|
|
||||||
Buffer.push_back(' ');
|
|
||||||
Buffer.insert(Buffer.end(), I->getValue().begin(), I->getValue().end());
|
|
||||||
Buffer.push_back('\n');
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the sets of secondary #defines.
|
|
||||||
llvm::StringMap<std::string> *SecondaryDefines
|
|
||||||
= new llvm::StringMap<std::string>[SecondaryTargets.size()];
|
|
||||||
for (unsigned i = 0, e = SecondaryTargets.size(); i != e; ++i)
|
|
||||||
GetTargetDefineMap(SecondaryTargets[i], SecondaryDefines[i]);
|
|
||||||
|
|
||||||
// Loop over all defines in the primary target, processing them until we run
|
|
||||||
// out.
|
|
||||||
for (llvm::StringMap<std::string>::iterator PDI =
|
|
||||||
PrimaryDefines.begin(), E = PrimaryDefines.end(); PDI != E; ++PDI) {
|
|
||||||
std::string DefineName(PDI->getKeyData(),
|
|
||||||
PDI->getKeyData() + PDI->getKeyLength());
|
|
||||||
std::string DefineValue = PDI->getValue();
|
|
||||||
|
|
||||||
// Check to see whether all secondary targets have this #define and whether
|
|
||||||
// it is to the same value. Remember if not, but remove the #define from
|
|
||||||
// their collection in any case if they have it.
|
|
||||||
bool isPortable = true;
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = SecondaryTargets.size(); i != e; ++i) {
|
|
||||||
llvm::StringMap<std::string>::iterator I =
|
|
||||||
SecondaryDefines[i].find(&DefineName[0],
|
|
||||||
&DefineName[0]+DefineName.size());
|
|
||||||
if (I == SecondaryDefines[i].end()) {
|
|
||||||
// Secondary target doesn't have this #define.
|
|
||||||
isPortable = false;
|
|
||||||
} else {
|
|
||||||
// Secondary target has this define, remember if it disagrees.
|
|
||||||
if (isPortable)
|
|
||||||
isPortable = I->getValue() == DefineValue;
|
|
||||||
// Remove it from the secondary target unconditionally.
|
|
||||||
SecondaryDefines[i].erase(I);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this define is non-portable, turn it into #define_target, otherwise
|
|
||||||
// just use #define.
|
|
||||||
const char *Command = isPortable ? "#define " : "#define_target ";
|
|
||||||
Buffer.insert(Buffer.end(), Command, Command+strlen(Command));
|
|
||||||
|
|
||||||
// Insert "defname defvalue\n".
|
|
||||||
Buffer.insert(Buffer.end(), DefineName.begin(), DefineName.end());
|
|
||||||
Buffer.push_back(' ');
|
|
||||||
Buffer.insert(Buffer.end(), DefineValue.begin(), DefineValue.end());
|
|
||||||
Buffer.push_back('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that all of the primary target's defines have been handled and removed
|
|
||||||
// from the secondary target's define sets, go through the remaining secondary
|
|
||||||
// target's #defines and taint them.
|
|
||||||
for (unsigned i = 0, e = SecondaryTargets.size(); i != e; ++i) {
|
|
||||||
llvm::StringMap<std::string> &Defs = SecondaryDefines[i];
|
|
||||||
while (!Defs.empty()) {
|
|
||||||
const char *DefStart = Defs.begin()->getKeyData();
|
|
||||||
const char *DefEnd = DefStart + Defs.begin()->getKeyLength();
|
|
||||||
|
|
||||||
// Insert "#define_other_target defname".
|
|
||||||
const char *Command = "#define_other_target ";
|
|
||||||
Buffer.insert(Buffer.end(), Command, Command+strlen(Command));
|
|
||||||
Buffer.insert(Buffer.end(), DefStart, DefEnd);
|
|
||||||
Buffer.push_back('\n');
|
|
||||||
|
|
||||||
// If any other secondary targets have this same define, remove it from
|
|
||||||
// them to avoid duplicate #define_other_target directives.
|
|
||||||
for (unsigned j = i+1; j != e; ++j) {
|
|
||||||
llvm::StringMap<std::string>::iterator I =
|
|
||||||
SecondaryDefines[j].find(DefStart, DefEnd);
|
|
||||||
if (I != SecondaryDefines[j].end())
|
|
||||||
SecondaryDefines[j].erase(I);
|
|
||||||
}
|
|
||||||
Defs.erase(Defs.begin());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] SecondaryDefines;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ComputeWCharWidth - Determine the width of the wchar_t type for the primary
|
|
||||||
/// target, diagnosing whether this is non-portable across the secondary
|
|
||||||
/// targets.
|
|
||||||
void TargetInfo::ComputeWCharInfo(SourceLocation Loc) {
|
|
||||||
PrimaryTarget->getWCharInfo(WCharWidth, WCharAlign);
|
|
||||||
|
|
||||||
// Check whether this is portable across the secondary targets if the T-U is
|
|
||||||
// portable so far.
|
|
||||||
for (unsigned i = 0, e = SecondaryTargets.size(); i != e; ++i) {
|
|
||||||
unsigned Width, Align;
|
|
||||||
SecondaryTargets[i]->getWCharInfo(Width, Align);
|
|
||||||
if (Width != WCharWidth || Align != WCharAlign)
|
|
||||||
return DiagnoseNonPortability(Loc, diag::port_wchar_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// getTargetBuiltins - Return information about target-specific builtins for
|
|
||||||
/// the current primary target, and info about which builtins are non-portable
|
|
||||||
/// across the current set of primary and secondary targets.
|
|
||||||
void TargetInfo::getTargetBuiltins(const Builtin::Info *&Records,
|
|
||||||
unsigned &NumRecords,
|
|
||||||
std::vector<const char *> &NPortable) const {
|
|
||||||
// Get info about what actual builtins we will expose.
|
|
||||||
PrimaryTarget->getTargetBuiltins(Records, NumRecords);
|
|
||||||
if (SecondaryTargets.empty()) return;
|
|
||||||
|
|
||||||
// Compute the set of non-portable builtins.
|
|
||||||
|
|
||||||
// Start by computing a mapping from the primary target's builtins to their
|
|
||||||
// info records for efficient lookup.
|
|
||||||
llvm::StringMap<const Builtin::Info*> PrimaryRecs;
|
|
||||||
for (unsigned i = 0, e = NumRecords; i != e; ++i) {
|
|
||||||
const char *BIName = Records[i].Name;
|
|
||||||
PrimaryRecs.GetOrCreateValue(BIName, BIName+strlen(BIName)).getValue()
|
|
||||||
= Records+i;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = SecondaryTargets.size(); i != e; ++i) {
|
|
||||||
// Get the builtins for this secondary target.
|
|
||||||
const Builtin::Info *Records2nd;
|
|
||||||
unsigned NumRecords2nd;
|
|
||||||
SecondaryTargets[i]->getTargetBuiltins(Records2nd, NumRecords2nd);
|
|
||||||
|
|
||||||
// Remember all of the secondary builtin names.
|
|
||||||
std::set<std::string> BuiltinNames2nd;
|
|
||||||
|
|
||||||
for (unsigned j = 0, e = NumRecords2nd; j != e; ++j) {
|
|
||||||
BuiltinNames2nd.insert(Records2nd[j].Name);
|
|
||||||
|
|
||||||
// Check to see if the primary target has this builtin.
|
|
||||||
llvm::StringMap<const Builtin::Info*>::iterator I =
|
|
||||||
PrimaryRecs.find(Records2nd[j].Name,
|
|
||||||
Records2nd[j].Name+strlen(Records2nd[j].Name));
|
|
||||||
if (I != PrimaryRecs.end()) {
|
|
||||||
const Builtin::Info *PrimBI = I->getValue();
|
|
||||||
// If does. If they are not identical, mark the builtin as being
|
|
||||||
// non-portable.
|
|
||||||
if (Records2nd[j] != *PrimBI)
|
|
||||||
NPortable.push_back(PrimBI->Name);
|
|
||||||
} else {
|
|
||||||
// The primary target doesn't have this, it is non-portable.
|
|
||||||
NPortable.push_back(Records2nd[j].Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we checked all the secondary builtins, check to see if the
|
|
||||||
// primary target has any builtins that the secondary one doesn't. If so,
|
|
||||||
// then those are non-portable.
|
|
||||||
for (unsigned j = 0, e = NumRecords; j != e; ++j) {
|
|
||||||
if (!BuiltinNames2nd.count(Records[j].Name))
|
|
||||||
NPortable.push_back(Records[j].Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
//===--- TokenKinds.cpp - Token Kinds Support -----------------------------===//
|
|
||||||
//
|
|
||||||
// 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 TokenKind enum and support functions.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Basic/TokenKinds.h"
|
|
||||||
#include <cassert>
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
static const char * const TokNames[] = {
|
|
||||||
#define TOK(X) #X,
|
|
||||||
#define KEYWORD(X,Y) #X,
|
|
||||||
#include "clang/Basic/TokenKinds.def"
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *tok::getTokenName(enum TokenKind Kind) {
|
|
||||||
assert(Kind < tok::NUM_TOKENS);
|
|
||||||
return TokNames[Kind];
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Anders Carlsson and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This contains code to emit Builtin calls as LLVM code.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "CodeGenFunction.h"
|
|
||||||
#include "CodeGenModule.h"
|
|
||||||
#include "clang/AST/ASTContext.h"
|
|
||||||
#include "clang/AST/Builtins.h"
|
|
||||||
#include "clang/AST/Expr.h"
|
|
||||||
#include "llvm/Constants.h"
|
|
||||||
#include "llvm/Function.h"
|
|
||||||
using namespace clang;
|
|
||||||
using namespace CodeGen;
|
|
||||||
|
|
||||||
RValue CodeGenFunction::EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E) {
|
|
||||||
switch (BuiltinID) {
|
|
||||||
default:
|
|
||||||
if (getContext().BuiltinInfo.isLibFunction(BuiltinID))
|
|
||||||
return EmitCallExpr(CGM.getBuiltinLibFunction(BuiltinID), E);
|
|
||||||
|
|
||||||
fprintf(stderr, "Unimplemented builtin!!\n");
|
|
||||||
E->dump(getContext().SourceMgr);
|
|
||||||
|
|
||||||
// Unknown builtin, for now just dump it out and return undef.
|
|
||||||
if (hasAggregateLLVMType(E->getType()))
|
|
||||||
return RValue::getAggregate(CreateTempAlloca(ConvertType(E->getType())));
|
|
||||||
return RValue::get(llvm::UndefValue::get(ConvertType(E->getType())));
|
|
||||||
|
|
||||||
case Builtin::BI__builtin___CFStringMakeConstantString: {
|
|
||||||
const Expr *Arg = E->getArg(0);
|
|
||||||
|
|
||||||
while (const ParenExpr *PE = dyn_cast<ParenExpr>(Arg))
|
|
||||||
Arg = PE->getSubExpr();
|
|
||||||
|
|
||||||
const StringLiteral *Literal = cast<StringLiteral>(Arg);
|
|
||||||
std::string S(Literal->getStrData(), Literal->getByteLength());
|
|
||||||
|
|
||||||
return RValue::get(CGM.GetAddrOfConstantCFString(S));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return RValue::get(0);
|
|
||||||
}
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
//===--- CGDecl.cpp - Emit LLVM Code for declarations ---------------------===//
|
|
||||||
//
|
|
||||||
// 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 contains code to emit Decl nodes as LLVM code.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "CodeGenFunction.h"
|
|
||||||
#include "clang/AST/AST.h"
|
|
||||||
#include "llvm/Type.h"
|
|
||||||
using namespace clang;
|
|
||||||
using namespace CodeGen;
|
|
||||||
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitDecl(const Decl &D) {
|
|
||||||
switch (D.getKind()) {
|
|
||||||
default: assert(0 && "Unknown decl kind!");
|
|
||||||
case Decl::FileVariable:
|
|
||||||
assert(0 && "Should not see file-scope variables inside a function!");
|
|
||||||
case Decl::ParmVariable:
|
|
||||||
assert(0 && "Parmdecls should not be in declstmts!");
|
|
||||||
case Decl::Typedef: // typedef int X;
|
|
||||||
case Decl::Function: // void X();
|
|
||||||
case Decl::Struct: // struct X;
|
|
||||||
case Decl::Union: // union X;
|
|
||||||
case Decl::Class: // class X;
|
|
||||||
case Decl::Enum: // enum X;
|
|
||||||
// None of these decls require codegen support.
|
|
||||||
return;
|
|
||||||
|
|
||||||
case Decl::BlockVariable:
|
|
||||||
return EmitBlockVarDecl(cast<BlockVarDecl>(D));
|
|
||||||
case Decl::EnumConstant:
|
|
||||||
return EmitEnumConstantDecl(cast<EnumConstantDecl>(D));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitEnumConstantDecl(const EnumConstantDecl &D) {
|
|
||||||
assert(0 && "FIXME: Enum constant decls not implemented yet!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitBlockVarDecl - This method handles emission of any variable declaration
|
|
||||||
/// inside a function, including static vars etc.
|
|
||||||
void CodeGenFunction::EmitBlockVarDecl(const BlockVarDecl &D) {
|
|
||||||
switch (D.getStorageClass()) {
|
|
||||||
case VarDecl::Static:
|
|
||||||
assert(0 && "FIXME: local static vars not implemented yet");
|
|
||||||
case VarDecl::Extern:
|
|
||||||
assert(0 && "FIXME: should call up to codegenmodule");
|
|
||||||
default:
|
|
||||||
assert((D.getStorageClass() == VarDecl::None ||
|
|
||||||
D.getStorageClass() == VarDecl::Auto ||
|
|
||||||
D.getStorageClass() == VarDecl::Register) &&
|
|
||||||
"Unknown storage class");
|
|
||||||
return EmitLocalBlockVarDecl(D);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitLocalBlockVarDecl - Emit code and set up an entry in LocalDeclMap for a
|
|
||||||
/// variable declaration with auto, register, or no storage class specifier.
|
|
||||||
/// These turn into simple stack objects.
|
|
||||||
void CodeGenFunction::EmitLocalBlockVarDecl(const BlockVarDecl &D) {
|
|
||||||
QualType Ty = D.getCanonicalType();
|
|
||||||
|
|
||||||
llvm::Value *DeclPtr;
|
|
||||||
if (Ty->isConstantSizeType(getContext())) {
|
|
||||||
// A normal fixed sized variable becomes an alloca in the entry block.
|
|
||||||
const llvm::Type *LTy = ConvertType(Ty);
|
|
||||||
// TODO: Alignment
|
|
||||||
DeclPtr = CreateTempAlloca(LTy, D.getName());
|
|
||||||
} else {
|
|
||||||
// TODO: Create a dynamic alloca.
|
|
||||||
assert(0 && "FIXME: Local VLAs not implemented yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Value *&DMEntry = LocalDeclMap[&D];
|
|
||||||
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
|
|
||||||
DMEntry = DeclPtr;
|
|
||||||
|
|
||||||
// If this local has an initializer, emit it now.
|
|
||||||
if (const Expr *Init = D.getInit()) {
|
|
||||||
if (!hasAggregateLLVMType(Init->getType())) {
|
|
||||||
llvm::Value *V = EmitScalarExpr(Init);
|
|
||||||
Builder.CreateStore(V, DeclPtr, D.getType().isVolatileQualified());
|
|
||||||
} else if (Init->getType()->isComplexType()) {
|
|
||||||
EmitComplexExprIntoAddr(Init, DeclPtr, D.getType().isVolatileQualified());
|
|
||||||
} else {
|
|
||||||
EmitAggExpr(Init, DeclPtr, D.getType().isVolatileQualified());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Emit an alloca for the specified parameter and set up LocalDeclMap.
|
|
||||||
void CodeGenFunction::EmitParmDecl(const ParmVarDecl &D, llvm::Value *Arg) {
|
|
||||||
QualType Ty = D.getCanonicalType();
|
|
||||||
|
|
||||||
llvm::Value *DeclPtr;
|
|
||||||
if (!Ty->isConstantSizeType(getContext())) {
|
|
||||||
// Variable sized values always are passed by-reference.
|
|
||||||
DeclPtr = Arg;
|
|
||||||
} else {
|
|
||||||
// A fixed sized first class variable becomes an alloca in the entry block.
|
|
||||||
const llvm::Type *LTy = ConvertType(Ty);
|
|
||||||
if (LTy->isFirstClassType()) {
|
|
||||||
// TODO: Alignment
|
|
||||||
DeclPtr = new llvm::AllocaInst(LTy, 0, std::string(D.getName())+".addr",
|
|
||||||
AllocaInsertPt);
|
|
||||||
|
|
||||||
// Store the initial value into the alloca.
|
|
||||||
Builder.CreateStore(Arg, DeclPtr);
|
|
||||||
} else {
|
|
||||||
// Otherwise, if this is an aggregate, just use the input pointer.
|
|
||||||
DeclPtr = Arg;
|
|
||||||
}
|
|
||||||
Arg->setName(D.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Value *&DMEntry = LocalDeclMap[&D];
|
|
||||||
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
|
|
||||||
DMEntry = DeclPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,451 +0,0 @@
|
|||||||
//===--- CGExpr.cpp - Emit LLVM Code from Expressions ---------------------===//
|
|
||||||
//
|
|
||||||
// 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 contains code to emit Expr nodes as LLVM code.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "CodeGenFunction.h"
|
|
||||||
#include "CodeGenModule.h"
|
|
||||||
#include "clang/AST/AST.h"
|
|
||||||
#include "clang/Lex/IdentifierTable.h"
|
|
||||||
#include "llvm/Constants.h"
|
|
||||||
#include "llvm/DerivedTypes.h"
|
|
||||||
#include "llvm/Function.h"
|
|
||||||
#include "llvm/GlobalVariable.h"
|
|
||||||
#include "llvm/Support/MathExtras.h"
|
|
||||||
using namespace clang;
|
|
||||||
using namespace CodeGen;
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Miscellaneous Helper Methods
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
|
|
||||||
/// block.
|
|
||||||
llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty,
|
|
||||||
const char *Name) {
|
|
||||||
return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
|
|
||||||
/// expression and compare the result against zero, returning an Int1Ty value.
|
|
||||||
llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) {
|
|
||||||
QualType BoolTy = getContext().BoolTy;
|
|
||||||
if (!E->getType()->isComplexType())
|
|
||||||
return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy);
|
|
||||||
|
|
||||||
return EmitComplexToScalarConversion(EmitComplexExpr(E), E->getType(),BoolTy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitAnyExpr - Emit code to compute the specified expression which can have
|
|
||||||
/// any type. The result is returned as an RValue struct. If this is an
|
|
||||||
/// aggregate expression, the aggloc/agglocvolatile arguments indicate where
|
|
||||||
/// the result should be returned.
|
|
||||||
RValue CodeGenFunction::EmitAnyExpr(const Expr *E, llvm::Value *AggLoc,
|
|
||||||
bool isAggLocVolatile) {
|
|
||||||
if (!hasAggregateLLVMType(E->getType()))
|
|
||||||
return RValue::get(EmitScalarExpr(E));
|
|
||||||
else if (E->getType()->isComplexType())
|
|
||||||
return RValue::getComplex(EmitComplexExpr(E));
|
|
||||||
|
|
||||||
EmitAggExpr(E, AggLoc, isAggLocVolatile);
|
|
||||||
return RValue::getAggregate(AggLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// LValue Expression Emission
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// EmitLValue - Emit code to compute a designator that specifies the location
|
|
||||||
/// of the expression.
|
|
||||||
///
|
|
||||||
/// This can return one of two things: a simple address or a bitfield
|
|
||||||
/// reference. In either case, the LLVM Value* in the LValue structure is
|
|
||||||
/// guaranteed to be an LLVM pointer type.
|
|
||||||
///
|
|
||||||
/// If this returns a bitfield reference, nothing about the pointee type of
|
|
||||||
/// the LLVM value is known: For example, it may not be a pointer to an
|
|
||||||
/// integer.
|
|
||||||
///
|
|
||||||
/// If this returns a normal address, and if the lvalue's C type is fixed
|
|
||||||
/// size, this method guarantees that the returned pointer type will point to
|
|
||||||
/// an LLVM type of the same size of the lvalue's type. If the lvalue has a
|
|
||||||
/// variable length type, this is not possible.
|
|
||||||
///
|
|
||||||
LValue CodeGenFunction::EmitLValue(const Expr *E) {
|
|
||||||
switch (E->getStmtClass()) {
|
|
||||||
default: {
|
|
||||||
fprintf(stderr, "Unimplemented lvalue expr!\n");
|
|
||||||
E->dump(getContext().SourceMgr);
|
|
||||||
llvm::Type *Ty = llvm::PointerType::get(ConvertType(E->getType()));
|
|
||||||
return LValue::MakeAddr(llvm::UndefValue::get(Ty));
|
|
||||||
}
|
|
||||||
|
|
||||||
case Expr::DeclRefExprClass: return EmitDeclRefLValue(cast<DeclRefExpr>(E));
|
|
||||||
case Expr::ParenExprClass:return EmitLValue(cast<ParenExpr>(E)->getSubExpr());
|
|
||||||
case Expr::PreDefinedExprClass:
|
|
||||||
return EmitPreDefinedLValue(cast<PreDefinedExpr>(E));
|
|
||||||
case Expr::StringLiteralClass:
|
|
||||||
return EmitStringLiteralLValue(cast<StringLiteral>(E));
|
|
||||||
|
|
||||||
case Expr::UnaryOperatorClass:
|
|
||||||
return EmitUnaryOpLValue(cast<UnaryOperator>(E));
|
|
||||||
case Expr::ArraySubscriptExprClass:
|
|
||||||
return EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E));
|
|
||||||
case Expr::OCUVectorElementExprClass:
|
|
||||||
return EmitOCUVectorElementExpr(cast<OCUVectorElementExpr>(E));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitLoadOfLValue - Given an expression that represents a value lvalue,
|
|
||||||
/// this method emits the address of the lvalue, then loads the result as an
|
|
||||||
/// rvalue, returning the rvalue.
|
|
||||||
RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) {
|
|
||||||
if (LV.isSimple()) {
|
|
||||||
llvm::Value *Ptr = LV.getAddress();
|
|
||||||
const llvm::Type *EltTy =
|
|
||||||
cast<llvm::PointerType>(Ptr->getType())->getElementType();
|
|
||||||
|
|
||||||
// Simple scalar l-value.
|
|
||||||
if (EltTy->isFirstClassType())
|
|
||||||
return RValue::get(Builder.CreateLoad(Ptr, "tmp"));
|
|
||||||
|
|
||||||
assert(ExprType->isFunctionType() && "Unknown scalar value");
|
|
||||||
return RValue::get(Ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LV.isVectorElt()) {
|
|
||||||
llvm::Value *Vec = Builder.CreateLoad(LV.getVectorAddr(), "tmp");
|
|
||||||
return RValue::get(Builder.CreateExtractElement(Vec, LV.getVectorIdx(),
|
|
||||||
"vecext"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is a reference to a subset of the elements of a vector, either
|
|
||||||
// shuffle the input or extract/insert them as appropriate.
|
|
||||||
if (LV.isOCUVectorElt())
|
|
||||||
return EmitLoadOfOCUElementLValue(LV, ExprType);
|
|
||||||
|
|
||||||
assert(0 && "Bitfield ref not impl!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is a reference to a subset of the elements of a vector, either
|
|
||||||
// shuffle the input or extract/insert them as appropriate.
|
|
||||||
RValue CodeGenFunction::EmitLoadOfOCUElementLValue(LValue LV,
|
|
||||||
QualType ExprType) {
|
|
||||||
llvm::Value *Vec = Builder.CreateLoad(LV.getOCUVectorAddr(), "tmp");
|
|
||||||
|
|
||||||
unsigned EncFields = LV.getOCUVectorElts();
|
|
||||||
|
|
||||||
// If the result of the expression is a non-vector type, we must be
|
|
||||||
// extracting a single element. Just codegen as an extractelement.
|
|
||||||
const VectorType *ExprVT = ExprType->getAsVectorType();
|
|
||||||
if (!ExprVT) {
|
|
||||||
unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(0, EncFields);
|
|
||||||
llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx);
|
|
||||||
return RValue::get(Builder.CreateExtractElement(Vec, Elt, "tmp"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the source and destination have the same number of elements, use a
|
|
||||||
// vector shuffle instead of insert/extracts.
|
|
||||||
unsigned NumResultElts = ExprVT->getNumElements();
|
|
||||||
unsigned NumSourceElts =
|
|
||||||
cast<llvm::VectorType>(Vec->getType())->getNumElements();
|
|
||||||
|
|
||||||
if (NumResultElts == NumSourceElts) {
|
|
||||||
llvm::SmallVector<llvm::Constant*, 4> Mask;
|
|
||||||
for (unsigned i = 0; i != NumResultElts; ++i) {
|
|
||||||
unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(i, EncFields);
|
|
||||||
Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx));
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size());
|
|
||||||
Vec = Builder.CreateShuffleVector(Vec,
|
|
||||||
llvm::UndefValue::get(Vec->getType()),
|
|
||||||
MaskV, "tmp");
|
|
||||||
return RValue::get(Vec);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start out with an undef of the result type.
|
|
||||||
llvm::Value *Result = llvm::UndefValue::get(ConvertType(ExprType));
|
|
||||||
|
|
||||||
// Extract/Insert each element of the result.
|
|
||||||
for (unsigned i = 0; i != NumResultElts; ++i) {
|
|
||||||
unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(i, EncFields);
|
|
||||||
llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx);
|
|
||||||
Elt = Builder.CreateExtractElement(Vec, Elt, "tmp");
|
|
||||||
|
|
||||||
llvm::Value *OutIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
|
|
||||||
Result = Builder.CreateInsertElement(Result, Elt, OutIdx, "tmp");
|
|
||||||
}
|
|
||||||
|
|
||||||
return RValue::get(Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
|
|
||||||
/// lvalue, where both are guaranteed to the have the same type, and that type
|
|
||||||
/// is 'Ty'.
|
|
||||||
void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
|
|
||||||
QualType Ty) {
|
|
||||||
if (!Dst.isSimple()) {
|
|
||||||
if (Dst.isVectorElt()) {
|
|
||||||
// Read/modify/write the vector, inserting the new element.
|
|
||||||
// FIXME: Volatility.
|
|
||||||
llvm::Value *Vec = Builder.CreateLoad(Dst.getVectorAddr(), "tmp");
|
|
||||||
Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(),
|
|
||||||
Dst.getVectorIdx(), "vecins");
|
|
||||||
Builder.CreateStore(Vec, Dst.getVectorAddr());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is an update of elements of a vector, insert them as appropriate.
|
|
||||||
if (Dst.isOCUVectorElt())
|
|
||||||
return EmitStoreThroughOCUComponentLValue(Src, Dst, Ty);
|
|
||||||
|
|
||||||
assert(0 && "FIXME: Don't support store to bitfield yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Value *DstAddr = Dst.getAddress();
|
|
||||||
assert(Src.isScalar() && "Can't emit an agg store with this method");
|
|
||||||
// FIXME: Handle volatility etc.
|
|
||||||
const llvm::Type *SrcTy = Src.getScalarVal()->getType();
|
|
||||||
const llvm::Type *AddrTy =
|
|
||||||
cast<llvm::PointerType>(DstAddr->getType())->getElementType();
|
|
||||||
|
|
||||||
if (AddrTy != SrcTy)
|
|
||||||
DstAddr = Builder.CreateBitCast(DstAddr, llvm::PointerType::get(SrcTy),
|
|
||||||
"storetmp");
|
|
||||||
Builder.CreateStore(Src.getScalarVal(), DstAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitStoreThroughOCUComponentLValue(RValue Src, LValue Dst,
|
|
||||||
QualType Ty) {
|
|
||||||
// This access turns into a read/modify/write of the vector. Load the input
|
|
||||||
// value now.
|
|
||||||
llvm::Value *Vec = Builder.CreateLoad(Dst.getOCUVectorAddr(), "tmp");
|
|
||||||
// FIXME: Volatility.
|
|
||||||
unsigned EncFields = Dst.getOCUVectorElts();
|
|
||||||
|
|
||||||
llvm::Value *SrcVal = Src.getScalarVal();
|
|
||||||
|
|
||||||
if (const VectorType *VTy = Ty->getAsVectorType()) {
|
|
||||||
unsigned NumSrcElts = VTy->getNumElements();
|
|
||||||
|
|
||||||
// Extract/Insert each element.
|
|
||||||
for (unsigned i = 0; i != NumSrcElts; ++i) {
|
|
||||||
llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
|
|
||||||
Elt = Builder.CreateExtractElement(SrcVal, Elt, "tmp");
|
|
||||||
|
|
||||||
unsigned Idx = OCUVectorElementExpr::getAccessedFieldNo(i, EncFields);
|
|
||||||
llvm::Value *OutIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, Idx);
|
|
||||||
Vec = Builder.CreateInsertElement(Vec, Elt, OutIdx, "tmp");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If the Src is a scalar (not a vector) it must be updating one element.
|
|
||||||
unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(0, EncFields);
|
|
||||||
llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx);
|
|
||||||
Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt, "tmp");
|
|
||||||
}
|
|
||||||
|
|
||||||
Builder.CreateStore(Vec, Dst.getOCUVectorAddr());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
|
|
||||||
const Decl *D = E->getDecl();
|
|
||||||
if (isa<BlockVarDecl>(D) || isa<ParmVarDecl>(D)) {
|
|
||||||
llvm::Value *V = LocalDeclMap[D];
|
|
||||||
assert(V && "BlockVarDecl not entered in LocalDeclMap?");
|
|
||||||
return LValue::MakeAddr(V);
|
|
||||||
} else if (isa<FunctionDecl>(D) || isa<FileVarDecl>(D)) {
|
|
||||||
return LValue::MakeAddr(CGM.GetAddrOfGlobalDecl(D));
|
|
||||||
}
|
|
||||||
assert(0 && "Unimp declref");
|
|
||||||
}
|
|
||||||
|
|
||||||
LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
|
|
||||||
// __extension__ doesn't affect lvalue-ness.
|
|
||||||
if (E->getOpcode() == UnaryOperator::Extension)
|
|
||||||
return EmitLValue(E->getSubExpr());
|
|
||||||
|
|
||||||
assert(E->getOpcode() == UnaryOperator::Deref &&
|
|
||||||
"'*' is the only unary operator that produces an lvalue");
|
|
||||||
return LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()));
|
|
||||||
}
|
|
||||||
|
|
||||||
LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) {
|
|
||||||
assert(!E->isWide() && "FIXME: Wide strings not supported yet!");
|
|
||||||
const char *StrData = E->getStrData();
|
|
||||||
unsigned Len = E->getByteLength();
|
|
||||||
|
|
||||||
// FIXME: Can cache/reuse these within the module.
|
|
||||||
llvm::Constant *C=llvm::ConstantArray::get(std::string(StrData, StrData+Len));
|
|
||||||
|
|
||||||
// Create a global variable for this.
|
|
||||||
C = new llvm::GlobalVariable(C->getType(), true,
|
|
||||||
llvm::GlobalValue::InternalLinkage,
|
|
||||||
C, ".str", CurFn->getParent());
|
|
||||||
llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
|
|
||||||
llvm::Constant *Zeros[] = { Zero, Zero };
|
|
||||||
C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2);
|
|
||||||
return LValue::MakeAddr(C);
|
|
||||||
}
|
|
||||||
|
|
||||||
LValue CodeGenFunction::EmitPreDefinedLValue(const PreDefinedExpr *E) {
|
|
||||||
std::string FunctionName(CurFuncDecl->getName());
|
|
||||||
std::string GlobalVarName;
|
|
||||||
|
|
||||||
switch (E->getIdentType()) {
|
|
||||||
default:
|
|
||||||
assert(0 && "unknown pre-defined ident type");
|
|
||||||
case PreDefinedExpr::Func:
|
|
||||||
GlobalVarName = "__func__.";
|
|
||||||
break;
|
|
||||||
case PreDefinedExpr::Function:
|
|
||||||
GlobalVarName = "__FUNCTION__.";
|
|
||||||
break;
|
|
||||||
case PreDefinedExpr::PrettyFunction:
|
|
||||||
// FIXME:: Demangle C++ method names
|
|
||||||
GlobalVarName = "__PRETTY_FUNCTION__.";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
GlobalVarName += CurFuncDecl->getName();
|
|
||||||
|
|
||||||
// FIXME: Can cache/reuse these within the module.
|
|
||||||
llvm::Constant *C=llvm::ConstantArray::get(FunctionName);
|
|
||||||
|
|
||||||
// Create a global variable for this.
|
|
||||||
C = new llvm::GlobalVariable(C->getType(), true,
|
|
||||||
llvm::GlobalValue::InternalLinkage,
|
|
||||||
C, GlobalVarName, CurFn->getParent());
|
|
||||||
llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
|
|
||||||
llvm::Constant *Zeros[] = { Zero, Zero };
|
|
||||||
C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2);
|
|
||||||
return LValue::MakeAddr(C);
|
|
||||||
}
|
|
||||||
|
|
||||||
LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
|
|
||||||
// The index must always be an integer, which is not an aggregate. Emit it.
|
|
||||||
llvm::Value *Idx = EmitScalarExpr(E->getIdx());
|
|
||||||
|
|
||||||
// If the base is a vector type, then we are forming a vector element lvalue
|
|
||||||
// with this subscript.
|
|
||||||
if (E->getLHS()->getType()->isVectorType()) {
|
|
||||||
// Emit the vector as an lvalue to get its address.
|
|
||||||
LValue LHS = EmitLValue(E->getLHS());
|
|
||||||
assert(LHS.isSimple() && "Can only subscript lvalue vectors here!");
|
|
||||||
// FIXME: This should properly sign/zero/extend or truncate Idx to i32.
|
|
||||||
return LValue::MakeVectorElt(LHS.getAddress(), Idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The base must be a pointer, which is not an aggregate. Emit it.
|
|
||||||
llvm::Value *Base = EmitScalarExpr(E->getBase());
|
|
||||||
|
|
||||||
// Extend or truncate the index type to 32 or 64-bits.
|
|
||||||
QualType IdxTy = E->getIdx()->getType();
|
|
||||||
bool IdxSigned = IdxTy->isSignedIntegerType();
|
|
||||||
unsigned IdxBitwidth = cast<llvm::IntegerType>(Idx->getType())->getBitWidth();
|
|
||||||
if (IdxBitwidth != LLVMPointerWidth)
|
|
||||||
Idx = Builder.CreateIntCast(Idx, llvm::IntegerType::get(LLVMPointerWidth),
|
|
||||||
IdxSigned, "idxprom");
|
|
||||||
|
|
||||||
// We know that the pointer points to a type of the correct size, unless the
|
|
||||||
// size is a VLA.
|
|
||||||
if (!E->getType()->isConstantSizeType(getContext()))
|
|
||||||
assert(0 && "VLA idx not implemented");
|
|
||||||
return LValue::MakeAddr(Builder.CreateGEP(Base, Idx, "arrayidx"));
|
|
||||||
}
|
|
||||||
|
|
||||||
LValue CodeGenFunction::
|
|
||||||
EmitOCUVectorElementExpr(const OCUVectorElementExpr *E) {
|
|
||||||
// Emit the base vector as an l-value.
|
|
||||||
LValue Base = EmitLValue(E->getBase());
|
|
||||||
assert(Base.isSimple() && "Can only subscript lvalue vectors here!");
|
|
||||||
|
|
||||||
return LValue::MakeOCUVectorElt(Base.getAddress(),
|
|
||||||
E->getEncodedElementAccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Expression Emission
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
|
|
||||||
RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) {
|
|
||||||
if (const ImplicitCastExpr *IcExpr =
|
|
||||||
dyn_cast<const ImplicitCastExpr>(E->getCallee()))
|
|
||||||
if (const DeclRefExpr *DRExpr =
|
|
||||||
dyn_cast<const DeclRefExpr>(IcExpr->getSubExpr()))
|
|
||||||
if (const FunctionDecl *FDecl =
|
|
||||||
dyn_cast<const FunctionDecl>(DRExpr->getDecl()))
|
|
||||||
if (unsigned builtinID = FDecl->getIdentifier()->getBuiltinID())
|
|
||||||
return EmitBuiltinExpr(builtinID, E);
|
|
||||||
|
|
||||||
llvm::Value *Callee = EmitScalarExpr(E->getCallee());
|
|
||||||
return EmitCallExpr(Callee, E);
|
|
||||||
}
|
|
||||||
|
|
||||||
RValue CodeGenFunction::EmitCallExpr(llvm::Value *Callee, const CallExpr *E) {
|
|
||||||
// The callee type will always be a pointer to function type, get the function
|
|
||||||
// type.
|
|
||||||
QualType CalleeTy = E->getCallee()->getType();
|
|
||||||
CalleeTy = cast<PointerType>(CalleeTy.getCanonicalType())->getPointeeType();
|
|
||||||
|
|
||||||
// Get information about the argument types.
|
|
||||||
FunctionTypeProto::arg_type_iterator ArgTyIt = 0, ArgTyEnd = 0;
|
|
||||||
|
|
||||||
// Calling unprototyped functions provides no argument info.
|
|
||||||
if (const FunctionTypeProto *FTP = dyn_cast<FunctionTypeProto>(CalleeTy)) {
|
|
||||||
ArgTyIt = FTP->arg_type_begin();
|
|
||||||
ArgTyEnd = FTP->arg_type_end();
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::SmallVector<llvm::Value*, 16> Args;
|
|
||||||
|
|
||||||
// Handle struct-return functions by passing a pointer to the location that
|
|
||||||
// we would like to return into.
|
|
||||||
if (hasAggregateLLVMType(E->getType())) {
|
|
||||||
// Create a temporary alloca to hold the result of the call. :(
|
|
||||||
Args.push_back(CreateTempAlloca(ConvertType(E->getType())));
|
|
||||||
// FIXME: set the stret attribute on the argument.
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
|
|
||||||
QualType ArgTy = E->getArg(i)->getType();
|
|
||||||
|
|
||||||
if (!hasAggregateLLVMType(ArgTy)) {
|
|
||||||
// Scalar argument is passed by-value.
|
|
||||||
Args.push_back(EmitScalarExpr(E->getArg(i)));
|
|
||||||
} else if (ArgTy->isComplexType()) {
|
|
||||||
// Make a temporary alloca to pass the argument.
|
|
||||||
llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy));
|
|
||||||
EmitComplexExprIntoAddr(E->getArg(i), DestMem, false);
|
|
||||||
Args.push_back(DestMem);
|
|
||||||
} else {
|
|
||||||
llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy));
|
|
||||||
EmitAggExpr(E->getArg(i), DestMem, false);
|
|
||||||
Args.push_back(DestMem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Value *V = Builder.CreateCall(Callee, &Args[0], &Args[0]+Args.size());
|
|
||||||
if (V->getType() != llvm::Type::VoidTy)
|
|
||||||
V->setName("call");
|
|
||||||
else if (E->getType()->isComplexType())
|
|
||||||
return RValue::getComplex(LoadComplexFromAddr(Args[0], false));
|
|
||||||
else if (hasAggregateLLVMType(E->getType()))
|
|
||||||
// Struct return.
|
|
||||||
return RValue::getAggregate(Args[0]);
|
|
||||||
|
|
||||||
return RValue::get(V);
|
|
||||||
}
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
//===--- CGExprAgg.cpp - Emit LLVM Code from Aggregate Expressions --------===//
|
|
||||||
//
|
|
||||||
// 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 contains code to emit Aggregate Expr nodes as LLVM code.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "CodeGenFunction.h"
|
|
||||||
#include "CodeGenModule.h"
|
|
||||||
#include "clang/AST/AST.h"
|
|
||||||
#include "llvm/Constants.h"
|
|
||||||
#include "llvm/Function.h"
|
|
||||||
#include "llvm/Support/Compiler.h"
|
|
||||||
using namespace clang;
|
|
||||||
using namespace CodeGen;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Aggregate Expression Emitter
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class VISIBILITY_HIDDEN AggExprEmitter : public StmtVisitor<AggExprEmitter> {
|
|
||||||
CodeGenFunction &CGF;
|
|
||||||
llvm::LLVMBuilder &Builder;
|
|
||||||
llvm::Value *DestPtr;
|
|
||||||
bool VolatileDest;
|
|
||||||
public:
|
|
||||||
AggExprEmitter(CodeGenFunction &cgf, llvm::Value *destPtr, bool volatileDest)
|
|
||||||
: CGF(cgf), Builder(CGF.Builder),
|
|
||||||
DestPtr(destPtr), VolatileDest(volatileDest) {
|
|
||||||
}
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Utilities
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// EmitAggLoadOfLValue - Given an expression with aggregate type that
|
|
||||||
/// represents a value lvalue, this method emits the address of the lvalue,
|
|
||||||
/// then loads the result into DestPtr.
|
|
||||||
void EmitAggLoadOfLValue(const Expr *E);
|
|
||||||
|
|
||||||
void EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr,
|
|
||||||
QualType EltTy);
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Visitor Methods
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void VisitStmt(Stmt *S) {
|
|
||||||
fprintf(stderr, "Unimplemented agg expr!\n");
|
|
||||||
S->dump(CGF.getContext().SourceMgr);
|
|
||||||
}
|
|
||||||
void VisitParenExpr(ParenExpr *PE) { Visit(PE->getSubExpr()); }
|
|
||||||
|
|
||||||
// l-values.
|
|
||||||
void VisitDeclRefExpr(DeclRefExpr *DRE) { return EmitAggLoadOfLValue(DRE); }
|
|
||||||
// case Expr::ArraySubscriptExprClass:
|
|
||||||
|
|
||||||
// Operators.
|
|
||||||
// case Expr::UnaryOperatorClass:
|
|
||||||
// case Expr::ImplicitCastExprClass:
|
|
||||||
// case Expr::CastExprClass:
|
|
||||||
// case Expr::CallExprClass:
|
|
||||||
void VisitStmtExpr(const StmtExpr *E);
|
|
||||||
void VisitBinaryOperator(const BinaryOperator *BO);
|
|
||||||
void VisitBinAssign(const BinaryOperator *E);
|
|
||||||
|
|
||||||
|
|
||||||
void VisitConditionalOperator(const ConditionalOperator *CO);
|
|
||||||
// case Expr::ChooseExprClass:
|
|
||||||
};
|
|
||||||
} // end anonymous namespace.
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Utilities
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void AggExprEmitter::EmitAggregateCopy(llvm::Value *DestPtr,
|
|
||||||
llvm::Value *SrcPtr, QualType Ty) {
|
|
||||||
assert(!Ty->isComplexType() && "Shouldn't happen for complex");
|
|
||||||
|
|
||||||
// Aggregate assignment turns into llvm.memcpy.
|
|
||||||
const llvm::Type *BP = llvm::PointerType::get(llvm::Type::Int8Ty);
|
|
||||||
if (DestPtr->getType() != BP)
|
|
||||||
DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp");
|
|
||||||
if (SrcPtr->getType() != BP)
|
|
||||||
SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp");
|
|
||||||
|
|
||||||
// Get size and alignment info for this aggregate.
|
|
||||||
std::pair<uint64_t, unsigned> TypeInfo =
|
|
||||||
CGF.getContext().getTypeInfo(Ty, SourceLocation());
|
|
||||||
|
|
||||||
// FIXME: Handle variable sized types.
|
|
||||||
const llvm::Type *IntPtr = llvm::IntegerType::get(CGF.LLVMPointerWidth);
|
|
||||||
|
|
||||||
llvm::Value *MemCpyOps[4] = {
|
|
||||||
DestPtr, SrcPtr,
|
|
||||||
llvm::ConstantInt::get(IntPtr, TypeInfo.first),
|
|
||||||
llvm::ConstantInt::get(llvm::Type::Int32Ty, TypeInfo.second)
|
|
||||||
};
|
|
||||||
|
|
||||||
Builder.CreateCall(CGF.CGM.getMemCpyFn(), MemCpyOps, MemCpyOps+4);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// EmitAggLoadOfLValue - Given an expression with aggregate type that
|
|
||||||
/// represents a value lvalue, this method emits the address of the lvalue,
|
|
||||||
/// then loads the result into DestPtr.
|
|
||||||
void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) {
|
|
||||||
LValue LV = CGF.EmitLValue(E);
|
|
||||||
assert(LV.isSimple() && "Can't have aggregate bitfield, vector, etc");
|
|
||||||
llvm::Value *SrcPtr = LV.getAddress();
|
|
||||||
|
|
||||||
// If the result is ignored, don't copy from the value.
|
|
||||||
if (DestPtr == 0)
|
|
||||||
// FIXME: If the source is volatile, we must read from it.
|
|
||||||
return;
|
|
||||||
|
|
||||||
EmitAggregateCopy(DestPtr, SrcPtr, E->getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Visitor Methods
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) {
|
|
||||||
CGF.EmitCompoundStmt(*E->getSubStmt(), true, DestPtr, VolatileDest);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) {
|
|
||||||
fprintf(stderr, "Unimplemented aggregate binary expr!\n");
|
|
||||||
E->dump(CGF.getContext().SourceMgr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
|
|
||||||
assert(E->getLHS()->getType().getCanonicalType() ==
|
|
||||||
E->getRHS()->getType().getCanonicalType() && "Invalid assignment");
|
|
||||||
LValue LHS = CGF.EmitLValue(E->getLHS());
|
|
||||||
|
|
||||||
// Codegen the RHS so that it stores directly into the LHS.
|
|
||||||
CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), false /*FIXME: VOLATILE LHS*/);
|
|
||||||
|
|
||||||
// If the result of the assignment is used, copy the RHS there also.
|
|
||||||
if (DestPtr) {
|
|
||||||
assert(0 && "FIXME: Chained agg assignment not implemented yet");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) {
|
|
||||||
llvm::BasicBlock *LHSBlock = new llvm::BasicBlock("cond.?");
|
|
||||||
llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("cond.:");
|
|
||||||
llvm::BasicBlock *ContBlock = new llvm::BasicBlock("cond.cont");
|
|
||||||
|
|
||||||
llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
|
|
||||||
Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
|
|
||||||
|
|
||||||
CGF.EmitBlock(LHSBlock);
|
|
||||||
|
|
||||||
// Handle the GNU extension for missing LHS.
|
|
||||||
assert(E->getLHS() && "Must have LHS for aggregate value");
|
|
||||||
|
|
||||||
Visit(E->getLHS());
|
|
||||||
Builder.CreateBr(ContBlock);
|
|
||||||
LHSBlock = Builder.GetInsertBlock();
|
|
||||||
|
|
||||||
CGF.EmitBlock(RHSBlock);
|
|
||||||
|
|
||||||
Visit(E->getRHS());
|
|
||||||
Builder.CreateBr(ContBlock);
|
|
||||||
RHSBlock = Builder.GetInsertBlock();
|
|
||||||
|
|
||||||
CGF.EmitBlock(ContBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Entry Points into this File
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// EmitAggExpr - Emit the computation of the specified expression of
|
|
||||||
/// aggregate type. The result is computed into DestPtr. Note that if
|
|
||||||
/// DestPtr is null, the value of the aggregate expression is not needed.
|
|
||||||
void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr,
|
|
||||||
bool VolatileDest) {
|
|
||||||
assert(E && hasAggregateLLVMType(E->getType()) &&
|
|
||||||
"Invalid aggregate expression to emit");
|
|
||||||
|
|
||||||
AggExprEmitter(*this, DestPtr, VolatileDest).Visit(const_cast<Expr*>(E));
|
|
||||||
}
|
|
||||||
@@ -1,532 +0,0 @@
|
|||||||
//===--- CGExprComplex.cpp - Emit LLVM Code for Complex Exprs -------------===//
|
|
||||||
//
|
|
||||||
// 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 contains code to emit Expr nodes with complex types as LLVM code.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "CodeGenFunction.h"
|
|
||||||
#include "CodeGenModule.h"
|
|
||||||
#include "clang/AST/AST.h"
|
|
||||||
#include "llvm/Constants.h"
|
|
||||||
#include "llvm/Function.h"
|
|
||||||
#include "llvm/ADT/SmallString.h"
|
|
||||||
#include "llvm/Support/Compiler.h"
|
|
||||||
using namespace clang;
|
|
||||||
using namespace CodeGen;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Complex Expression Emitter
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
typedef CodeGenFunction::ComplexPairTy ComplexPairTy;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class VISIBILITY_HIDDEN ComplexExprEmitter
|
|
||||||
: public StmtVisitor<ComplexExprEmitter, ComplexPairTy> {
|
|
||||||
CodeGenFunction &CGF;
|
|
||||||
llvm::LLVMBuilder &Builder;
|
|
||||||
public:
|
|
||||||
ComplexExprEmitter(CodeGenFunction &cgf) : CGF(cgf), Builder(CGF.Builder) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Utilities
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// EmitLoadOfLValue - Given an expression with complex type that represents a
|
|
||||||
/// value l-value, this method emits the address of the l-value, then loads
|
|
||||||
/// and returns the result.
|
|
||||||
ComplexPairTy EmitLoadOfLValue(const Expr *E) {
|
|
||||||
LValue LV = CGF.EmitLValue(E);
|
|
||||||
// FIXME: Volatile
|
|
||||||
return EmitLoadOfComplex(LV.getAddress(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitLoadOfComplex - Given a pointer to a complex value, emit code to load
|
|
||||||
/// the real and imaginary pieces.
|
|
||||||
ComplexPairTy EmitLoadOfComplex(llvm::Value *SrcPtr, bool isVolatile);
|
|
||||||
|
|
||||||
/// EmitStoreOfComplex - Store the specified real/imag parts into the
|
|
||||||
/// specified value pointer.
|
|
||||||
void EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *ResPtr, bool isVol);
|
|
||||||
|
|
||||||
/// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType.
|
|
||||||
ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType,
|
|
||||||
QualType DestType);
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Visitor Methods
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
ComplexPairTy VisitStmt(Stmt *S) {
|
|
||||||
S->dump(CGF.getContext().SourceMgr);
|
|
||||||
assert(0 && "Stmt can't have complex result type!");
|
|
||||||
return ComplexPairTy();
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitExpr(Expr *S);
|
|
||||||
ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());}
|
|
||||||
ComplexPairTy VisitImaginaryLiteral(const ImaginaryLiteral *IL);
|
|
||||||
|
|
||||||
// l-values.
|
|
||||||
ComplexPairTy VisitDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); }
|
|
||||||
ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); }
|
|
||||||
ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); }
|
|
||||||
|
|
||||||
// FIXME: CompoundLiteralExpr
|
|
||||||
|
|
||||||
ComplexPairTy EmitCast(Expr *Op, QualType DestTy);
|
|
||||||
ComplexPairTy VisitImplicitCastExpr(ImplicitCastExpr *E) {
|
|
||||||
// Unlike for scalars, we don't have to worry about function->ptr demotion
|
|
||||||
// here.
|
|
||||||
return EmitCast(E->getSubExpr(), E->getType());
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitCastExpr(CastExpr *E) {
|
|
||||||
return EmitCast(E->getSubExpr(), E->getType());
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitCallExpr(const CallExpr *E);
|
|
||||||
ComplexPairTy VisitStmtExpr(const StmtExpr *E);
|
|
||||||
|
|
||||||
// Operators.
|
|
||||||
ComplexPairTy VisitPrePostIncDec(const UnaryOperator *E,
|
|
||||||
bool isInc, bool isPre);
|
|
||||||
ComplexPairTy VisitUnaryPostDec(const UnaryOperator *E) {
|
|
||||||
return VisitPrePostIncDec(E, false, false);
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitUnaryPostInc(const UnaryOperator *E) {
|
|
||||||
return VisitPrePostIncDec(E, true, false);
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitUnaryPreDec(const UnaryOperator *E) {
|
|
||||||
return VisitPrePostIncDec(E, false, true);
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitUnaryPreInc(const UnaryOperator *E) {
|
|
||||||
return VisitPrePostIncDec(E, true, true);
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); }
|
|
||||||
ComplexPairTy VisitUnaryPlus (const UnaryOperator *E) {
|
|
||||||
return Visit(E->getSubExpr());
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitUnaryMinus (const UnaryOperator *E);
|
|
||||||
ComplexPairTy VisitUnaryNot (const UnaryOperator *E);
|
|
||||||
// LNot,SizeOf,AlignOf,Real,Imag never return complex.
|
|
||||||
ComplexPairTy VisitUnaryExtension(const UnaryOperator *E) {
|
|
||||||
return Visit(E->getSubExpr());
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BinOpInfo {
|
|
||||||
ComplexPairTy LHS;
|
|
||||||
ComplexPairTy RHS;
|
|
||||||
QualType Ty; // Computation Type.
|
|
||||||
};
|
|
||||||
|
|
||||||
BinOpInfo EmitBinOps(const BinaryOperator *E);
|
|
||||||
ComplexPairTy EmitCompoundAssign(const CompoundAssignOperator *E,
|
|
||||||
ComplexPairTy (ComplexExprEmitter::*Func)
|
|
||||||
(const BinOpInfo &));
|
|
||||||
|
|
||||||
ComplexPairTy EmitBinAdd(const BinOpInfo &Op);
|
|
||||||
ComplexPairTy EmitBinSub(const BinOpInfo &Op);
|
|
||||||
ComplexPairTy EmitBinMul(const BinOpInfo &Op);
|
|
||||||
ComplexPairTy EmitBinDiv(const BinOpInfo &Op);
|
|
||||||
|
|
||||||
ComplexPairTy VisitBinMul(const BinaryOperator *E) {
|
|
||||||
return EmitBinMul(EmitBinOps(E));
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitBinAdd(const BinaryOperator *E) {
|
|
||||||
return EmitBinAdd(EmitBinOps(E));
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitBinSub(const BinaryOperator *E) {
|
|
||||||
return EmitBinSub(EmitBinOps(E));
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitBinDiv(const BinaryOperator *E) {
|
|
||||||
return EmitBinDiv(EmitBinOps(E));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compound assignments.
|
|
||||||
ComplexPairTy VisitBinAddAssign(const CompoundAssignOperator *E) {
|
|
||||||
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinAdd);
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitBinSubAssign(const CompoundAssignOperator *E) {
|
|
||||||
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinSub);
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitBinMulAssign(const CompoundAssignOperator *E) {
|
|
||||||
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinMul);
|
|
||||||
}
|
|
||||||
ComplexPairTy VisitBinDivAssign(const CompoundAssignOperator *E) {
|
|
||||||
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinDiv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GCC rejects rem/and/or/xor for integer complex.
|
|
||||||
// Logical and/or always return int, never complex.
|
|
||||||
|
|
||||||
// No comparisons produce a complex result.
|
|
||||||
ComplexPairTy VisitBinAssign (const BinaryOperator *E);
|
|
||||||
ComplexPairTy VisitBinComma (const BinaryOperator *E);
|
|
||||||
|
|
||||||
|
|
||||||
ComplexPairTy VisitConditionalOperator(const ConditionalOperator *CO);
|
|
||||||
ComplexPairTy VisitChooseExpr(ChooseExpr *CE);
|
|
||||||
};
|
|
||||||
} // end anonymous namespace.
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Utilities
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// EmitLoadOfComplex - Given an RValue reference for a complex, emit code to
|
|
||||||
/// load the real and imaginary pieces, returning them as Real/Imag.
|
|
||||||
ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr,
|
|
||||||
bool isVolatile) {
|
|
||||||
llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
|
|
||||||
llvm::Constant *One = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1);
|
|
||||||
|
|
||||||
llvm::SmallString<64> Name(SrcPtr->getNameStart(),
|
|
||||||
SrcPtr->getNameStart()+SrcPtr->getNameLen());
|
|
||||||
|
|
||||||
Name += ".realp";
|
|
||||||
llvm::Value *Ops[] = {Zero, Zero};
|
|
||||||
llvm::Value *RealPtr = Builder.CreateGEP(SrcPtr, Ops, Ops+2, Name.c_str());
|
|
||||||
|
|
||||||
Name.pop_back(); // .realp -> .real
|
|
||||||
llvm::Value *Real = Builder.CreateLoad(RealPtr, isVolatile, Name.c_str());
|
|
||||||
|
|
||||||
Name.resize(Name.size()-4); // .real -> .imagp
|
|
||||||
Name += "imagp";
|
|
||||||
|
|
||||||
Ops[1] = One; // { Ops = { Zero, One }
|
|
||||||
llvm::Value *ImagPtr = Builder.CreateGEP(SrcPtr, Ops, Ops+2, Name.c_str());
|
|
||||||
|
|
||||||
Name.pop_back(); // .imagp -> .imag
|
|
||||||
llvm::Value *Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.c_str());
|
|
||||||
return ComplexPairTy(Real, Imag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitStoreOfComplex - Store the specified real/imag parts into the
|
|
||||||
/// specified value pointer.
|
|
||||||
void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr,
|
|
||||||
bool isVolatile) {
|
|
||||||
llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
|
|
||||||
llvm::Constant *One = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1);
|
|
||||||
|
|
||||||
llvm::Value *Ops[] = {Zero, Zero};
|
|
||||||
llvm::Value *RealPtr = Builder.CreateGEP(Ptr, Ops, Ops+2, "real");
|
|
||||||
|
|
||||||
Ops[1] = One; // { Ops = { Zero, One }
|
|
||||||
llvm::Value *ImagPtr = Builder.CreateGEP(Ptr, Ops, Ops+2, "imag");
|
|
||||||
|
|
||||||
Builder.CreateStore(Val.first, RealPtr, isVolatile);
|
|
||||||
Builder.CreateStore(Val.second, ImagPtr, isVolatile);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Visitor Methods
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) {
|
|
||||||
fprintf(stderr, "Unimplemented complex expr!\n");
|
|
||||||
E->dump(CGF.getContext().SourceMgr);
|
|
||||||
const llvm::Type *EltTy =
|
|
||||||
CGF.ConvertType(E->getType()->getAsComplexType()->getElementType());
|
|
||||||
llvm::Value *U = llvm::UndefValue::get(EltTy);
|
|
||||||
return ComplexPairTy(U, U);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::
|
|
||||||
VisitImaginaryLiteral(const ImaginaryLiteral *IL) {
|
|
||||||
llvm::Value *Imag = CGF.EmitScalarExpr(IL->getSubExpr());
|
|
||||||
return ComplexPairTy(llvm::Constant::getNullValue(Imag->getType()), Imag);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::VisitCallExpr(const CallExpr *E) {
|
|
||||||
return CGF.EmitCallExpr(E).getComplexVal();
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::VisitStmtExpr(const StmtExpr *E) {
|
|
||||||
return CGF.EmitCompoundStmt(*E->getSubStmt(), true).getComplexVal();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType.
|
|
||||||
ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val,
|
|
||||||
QualType SrcType,
|
|
||||||
QualType DestType) {
|
|
||||||
// Get the src/dest element type.
|
|
||||||
SrcType = cast<ComplexType>(SrcType.getCanonicalType())->getElementType();
|
|
||||||
DestType = cast<ComplexType>(DestType.getCanonicalType())->getElementType();
|
|
||||||
|
|
||||||
// C99 6.3.1.6: When a value of complextype is converted to another
|
|
||||||
// complex type, both the real and imaginary parts followthe conversion
|
|
||||||
// rules for the corresponding real types.
|
|
||||||
Val.first = CGF.EmitScalarConversion(Val.first, SrcType, DestType);
|
|
||||||
Val.second = CGF.EmitScalarConversion(Val.second, SrcType, DestType);
|
|
||||||
return Val;
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::EmitCast(Expr *Op, QualType DestTy) {
|
|
||||||
// Two cases here: cast from (complex to complex) and (scalar to complex).
|
|
||||||
if (Op->getType()->isComplexType())
|
|
||||||
return EmitComplexToComplexCast(Visit(Op), Op->getType(), DestTy);
|
|
||||||
|
|
||||||
// C99 6.3.1.7: When a value of real type is converted to a complex type, the
|
|
||||||
// real part of the complex result value is determined by the rules of
|
|
||||||
// conversion to the corresponding real type and the imaginary part of the
|
|
||||||
// complex result value is a positive zero or an unsigned zero.
|
|
||||||
llvm::Value *Elt = CGF.EmitScalarExpr(Op);
|
|
||||||
|
|
||||||
// Convert the input element to the element type of the complex.
|
|
||||||
DestTy = cast<ComplexType>(DestTy.getCanonicalType())->getElementType();
|
|
||||||
Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy);
|
|
||||||
|
|
||||||
// Return (realval, 0).
|
|
||||||
return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
|
|
||||||
bool isInc, bool isPre) {
|
|
||||||
LValue LV = CGF.EmitLValue(E->getSubExpr());
|
|
||||||
// FIXME: Handle volatile!
|
|
||||||
ComplexPairTy InVal = EmitLoadOfComplex(LV.getAddress(), false);
|
|
||||||
|
|
||||||
uint64_t AmountVal = isInc ? 1 : -1;
|
|
||||||
|
|
||||||
llvm::Value *NextVal;
|
|
||||||
if (isa<llvm::IntegerType>(InVal.first->getType()))
|
|
||||||
NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal);
|
|
||||||
else
|
|
||||||
NextVal = llvm::ConstantFP::get(InVal.first->getType(),
|
|
||||||
static_cast<double>(AmountVal));
|
|
||||||
|
|
||||||
// Add the inc/dec to the real part.
|
|
||||||
NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
|
|
||||||
|
|
||||||
ComplexPairTy IncVal(NextVal, InVal.second);
|
|
||||||
|
|
||||||
// Store the updated result through the lvalue.
|
|
||||||
EmitStoreOfComplex(IncVal, LV.getAddress(), false); /* FIXME: Volatile */
|
|
||||||
|
|
||||||
// If this is a postinc, return the value read from memory, otherwise use the
|
|
||||||
// updated value.
|
|
||||||
return isPre ? IncVal : InVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
|
|
||||||
ComplexPairTy Op = Visit(E->getSubExpr());
|
|
||||||
llvm::Value *ResR = Builder.CreateNeg(Op.first, "neg.r");
|
|
||||||
llvm::Value *ResI = Builder.CreateNeg(Op.second, "neg.i");
|
|
||||||
return ComplexPairTy(ResR, ResI);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
|
|
||||||
// ~(a+ib) = a + i*-b
|
|
||||||
ComplexPairTy Op = Visit(E->getSubExpr());
|
|
||||||
llvm::Value *ResI = Builder.CreateNeg(Op.second, "conj.i");
|
|
||||||
return ComplexPairTy(Op.first, ResI);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) {
|
|
||||||
llvm::Value *ResR = Builder.CreateAdd(Op.LHS.first, Op.RHS.first, "add.r");
|
|
||||||
llvm::Value *ResI = Builder.CreateAdd(Op.LHS.second, Op.RHS.second, "add.i");
|
|
||||||
return ComplexPairTy(ResR, ResI);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) {
|
|
||||||
llvm::Value *ResR = Builder.CreateSub(Op.LHS.first, Op.RHS.first, "sub.r");
|
|
||||||
llvm::Value *ResI = Builder.CreateSub(Op.LHS.second, Op.RHS.second, "sub.i");
|
|
||||||
return ComplexPairTy(ResR, ResI);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
|
|
||||||
llvm::Value *ResRl = Builder.CreateMul(Op.LHS.first, Op.RHS.first, "mul.rl");
|
|
||||||
llvm::Value *ResRr = Builder.CreateMul(Op.LHS.second, Op.RHS.second,"mul.rr");
|
|
||||||
llvm::Value *ResR = Builder.CreateSub(ResRl, ResRr, "mul.r");
|
|
||||||
|
|
||||||
llvm::Value *ResIl = Builder.CreateMul(Op.LHS.second, Op.RHS.first, "mul.il");
|
|
||||||
llvm::Value *ResIr = Builder.CreateMul(Op.LHS.first, Op.RHS.second, "mul.ir");
|
|
||||||
llvm::Value *ResI = Builder.CreateAdd(ResIl, ResIr, "mul.i");
|
|
||||||
return ComplexPairTy(ResR, ResI);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
|
|
||||||
llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second;
|
|
||||||
llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second;
|
|
||||||
|
|
||||||
// (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
|
|
||||||
llvm::Value *Tmp1 = Builder.CreateMul(LHSr, RHSr, "tmp"); // a*c
|
|
||||||
llvm::Value *Tmp2 = Builder.CreateMul(LHSi, RHSi, "tmp"); // b*d
|
|
||||||
llvm::Value *Tmp3 = Builder.CreateAdd(Tmp1, Tmp2, "tmp"); // ac+bd
|
|
||||||
|
|
||||||
llvm::Value *Tmp4 = Builder.CreateMul(RHSr, RHSr, "tmp"); // c*c
|
|
||||||
llvm::Value *Tmp5 = Builder.CreateMul(RHSi, RHSi, "tmp"); // d*d
|
|
||||||
llvm::Value *Tmp6 = Builder.CreateAdd(Tmp4, Tmp5, "tmp"); // cc+dd
|
|
||||||
|
|
||||||
llvm::Value *Tmp7 = Builder.CreateMul(LHSi, RHSr, "tmp"); // b*c
|
|
||||||
llvm::Value *Tmp8 = Builder.CreateMul(LHSr, RHSi, "tmp"); // a*d
|
|
||||||
llvm::Value *Tmp9 = Builder.CreateSub(Tmp7, Tmp8, "tmp"); // bc-ad
|
|
||||||
|
|
||||||
llvm::Value *DSTr, *DSTi;
|
|
||||||
if (Tmp3->getType()->isFloatingPoint()) {
|
|
||||||
DSTr = Builder.CreateFDiv(Tmp3, Tmp6, "tmp");
|
|
||||||
DSTi = Builder.CreateFDiv(Tmp9, Tmp6, "tmp");
|
|
||||||
} else {
|
|
||||||
if (Op.Ty->getAsComplexType()->getElementType()->isUnsignedIntegerType()) {
|
|
||||||
DSTr = Builder.CreateUDiv(Tmp3, Tmp6, "tmp");
|
|
||||||
DSTi = Builder.CreateUDiv(Tmp9, Tmp6, "tmp");
|
|
||||||
} else {
|
|
||||||
DSTr = Builder.CreateSDiv(Tmp3, Tmp6, "tmp");
|
|
||||||
DSTi = Builder.CreateSDiv(Tmp9, Tmp6, "tmp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ComplexPairTy(DSTr, DSTi);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexExprEmitter::BinOpInfo
|
|
||||||
ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) {
|
|
||||||
BinOpInfo Ops;
|
|
||||||
Ops.LHS = Visit(E->getLHS());
|
|
||||||
Ops.RHS = Visit(E->getRHS());
|
|
||||||
Ops.Ty = E->getType();
|
|
||||||
return Ops;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Compound assignments.
|
|
||||||
ComplexPairTy ComplexExprEmitter::
|
|
||||||
EmitCompoundAssign(const CompoundAssignOperator *E,
|
|
||||||
ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&)){
|
|
||||||
QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType();
|
|
||||||
|
|
||||||
// Load the LHS and RHS operands.
|
|
||||||
LValue LHSLV = CGF.EmitLValue(E->getLHS());
|
|
||||||
|
|
||||||
BinOpInfo OpInfo;
|
|
||||||
OpInfo.Ty = E->getComputationType();
|
|
||||||
|
|
||||||
// We know the LHS is a complex lvalue.
|
|
||||||
OpInfo.LHS = EmitLoadOfComplex(LHSLV.getAddress(), false);// FIXME: Volatile.
|
|
||||||
OpInfo.LHS = EmitComplexToComplexCast(OpInfo.LHS, LHSTy, OpInfo.Ty);
|
|
||||||
|
|
||||||
// It is possible for the RHS to be complex or scalar.
|
|
||||||
OpInfo.RHS = EmitCast(E->getRHS(), OpInfo.Ty);
|
|
||||||
|
|
||||||
// Expand the binary operator.
|
|
||||||
ComplexPairTy Result = (this->*Func)(OpInfo);
|
|
||||||
|
|
||||||
// Truncate the result back to the LHS type.
|
|
||||||
Result = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy);
|
|
||||||
|
|
||||||
// Store the result value into the LHS lvalue.
|
|
||||||
EmitStoreOfComplex(Result, LHSLV.getAddress(), false); // FIXME: VOLATILE
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
|
|
||||||
assert(E->getLHS()->getType().getCanonicalType() ==
|
|
||||||
E->getRHS()->getType().getCanonicalType() && "Invalid assignment");
|
|
||||||
// Emit the RHS.
|
|
||||||
ComplexPairTy Val = Visit(E->getRHS());
|
|
||||||
|
|
||||||
// Compute the address to store into.
|
|
||||||
LValue LHS = CGF.EmitLValue(E->getLHS());
|
|
||||||
|
|
||||||
// Store into it.
|
|
||||||
// FIXME: Volatility!
|
|
||||||
EmitStoreOfComplex(Val, LHS.getAddress(), false);
|
|
||||||
return Val;
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) {
|
|
||||||
CGF.EmitStmt(E->getLHS());
|
|
||||||
return Visit(E->getRHS());
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::
|
|
||||||
VisitConditionalOperator(const ConditionalOperator *E) {
|
|
||||||
llvm::BasicBlock *LHSBlock = new llvm::BasicBlock("cond.?");
|
|
||||||
llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("cond.:");
|
|
||||||
llvm::BasicBlock *ContBlock = new llvm::BasicBlock("cond.cont");
|
|
||||||
|
|
||||||
llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
|
|
||||||
Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
|
|
||||||
|
|
||||||
CGF.EmitBlock(LHSBlock);
|
|
||||||
|
|
||||||
// Handle the GNU extension for missing LHS.
|
|
||||||
assert(E->getLHS() && "Must have LHS for complex value");
|
|
||||||
|
|
||||||
ComplexPairTy LHS = Visit(E->getLHS());
|
|
||||||
Builder.CreateBr(ContBlock);
|
|
||||||
LHSBlock = Builder.GetInsertBlock();
|
|
||||||
|
|
||||||
CGF.EmitBlock(RHSBlock);
|
|
||||||
|
|
||||||
ComplexPairTy RHS = Visit(E->getRHS());
|
|
||||||
Builder.CreateBr(ContBlock);
|
|
||||||
RHSBlock = Builder.GetInsertBlock();
|
|
||||||
|
|
||||||
CGF.EmitBlock(ContBlock);
|
|
||||||
|
|
||||||
// Create a PHI node for the real part.
|
|
||||||
llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), "cond.r");
|
|
||||||
RealPN->reserveOperandSpace(2);
|
|
||||||
RealPN->addIncoming(LHS.first, LHSBlock);
|
|
||||||
RealPN->addIncoming(RHS.first, RHSBlock);
|
|
||||||
|
|
||||||
// Create a PHI node for the imaginary part.
|
|
||||||
llvm::PHINode *ImagPN = Builder.CreatePHI(LHS.first->getType(), "cond.i");
|
|
||||||
ImagPN->reserveOperandSpace(2);
|
|
||||||
ImagPN->addIncoming(LHS.second, LHSBlock);
|
|
||||||
ImagPN->addIncoming(RHS.second, RHSBlock);
|
|
||||||
|
|
||||||
return ComplexPairTy(RealPN, ImagPN);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexPairTy ComplexExprEmitter::VisitChooseExpr(ChooseExpr *E) {
|
|
||||||
llvm::APSInt CondVal(32);
|
|
||||||
bool IsConst = E->getCond()->isIntegerConstantExpr(CondVal, CGF.getContext());
|
|
||||||
assert(IsConst && "Condition of choose expr must be i-c-e"); IsConst=IsConst;
|
|
||||||
|
|
||||||
// Emit the LHS or RHS as appropriate.
|
|
||||||
return Visit(CondVal != 0 ? E->getLHS() : E->getRHS());
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Entry Point into this File
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// EmitComplexExpr - Emit the computation of the specified expression of
|
|
||||||
/// complex type, ignoring the result.
|
|
||||||
ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E) {
|
|
||||||
assert(E && E->getType()->isComplexType() &&
|
|
||||||
"Invalid complex expression to emit");
|
|
||||||
|
|
||||||
return ComplexExprEmitter(*this).Visit(const_cast<Expr*>(E));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitComplexExprIntoAddr - Emit the computation of the specified expression
|
|
||||||
/// of complex type, storing into the specified Value*.
|
|
||||||
void CodeGenFunction::EmitComplexExprIntoAddr(const Expr *E,
|
|
||||||
llvm::Value *DestAddr,
|
|
||||||
bool DestIsVolatile) {
|
|
||||||
assert(E && E->getType()->isComplexType() &&
|
|
||||||
"Invalid complex expression to emit");
|
|
||||||
ComplexExprEmitter Emitter(*this);
|
|
||||||
ComplexPairTy Val = Emitter.Visit(const_cast<Expr*>(E));
|
|
||||||
Emitter.EmitStoreOfComplex(Val, DestAddr, DestIsVolatile);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// LoadComplexFromAddr - Load a complex number from the specified address.
|
|
||||||
ComplexPairTy CodeGenFunction::LoadComplexFromAddr(llvm::Value *SrcAddr,
|
|
||||||
bool SrcIsVolatile) {
|
|
||||||
return ComplexExprEmitter(*this).EmitLoadOfComplex(SrcAddr, SrcIsVolatile);
|
|
||||||
}
|
|
||||||
@@ -1,920 +0,0 @@
|
|||||||
//===--- CGExprScalar.cpp - Emit LLVM Code for Scalar Exprs ---------------===//
|
|
||||||
//
|
|
||||||
// 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 contains code to emit Expr nodes with scalar LLVM types as LLVM code.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "CodeGenFunction.h"
|
|
||||||
#include "CodeGenModule.h"
|
|
||||||
#include "clang/AST/AST.h"
|
|
||||||
#include "llvm/Constants.h"
|
|
||||||
#include "llvm/Function.h"
|
|
||||||
#include "llvm/Support/Compiler.h"
|
|
||||||
using namespace clang;
|
|
||||||
using namespace CodeGen;
|
|
||||||
using llvm::Value;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Scalar Expression Emitter
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
struct BinOpInfo {
|
|
||||||
Value *LHS;
|
|
||||||
Value *RHS;
|
|
||||||
QualType Ty; // Computation Type.
|
|
||||||
const BinaryOperator *E;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class VISIBILITY_HIDDEN ScalarExprEmitter
|
|
||||||
: public StmtVisitor<ScalarExprEmitter, Value*> {
|
|
||||||
CodeGenFunction &CGF;
|
|
||||||
llvm::LLVMBuilder &Builder;
|
|
||||||
public:
|
|
||||||
|
|
||||||
ScalarExprEmitter(CodeGenFunction &cgf) : CGF(cgf), Builder(CGF.Builder) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Utilities
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
const llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); }
|
|
||||||
LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); }
|
|
||||||
|
|
||||||
Value *EmitLoadOfLValue(LValue LV, QualType T) {
|
|
||||||
return CGF.EmitLoadOfLValue(LV, T).getScalarVal();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitLoadOfLValue - Given an expression with complex type that represents a
|
|
||||||
/// value l-value, this method emits the address of the l-value, then loads
|
|
||||||
/// and returns the result.
|
|
||||||
Value *EmitLoadOfLValue(const Expr *E) {
|
|
||||||
// FIXME: Volatile
|
|
||||||
return EmitLoadOfLValue(EmitLValue(E), E->getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitConversionToBool - Convert the specified expression value to a
|
|
||||||
/// boolean (i1) truth value. This is equivalent to "Val != 0".
|
|
||||||
Value *EmitConversionToBool(Value *Src, QualType DstTy);
|
|
||||||
|
|
||||||
/// EmitScalarConversion - Emit a conversion from the specified type to the
|
|
||||||
/// specified destination type, both of which are LLVM scalar types.
|
|
||||||
Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy);
|
|
||||||
|
|
||||||
/// EmitComplexToScalarConversion - Emit a conversion from the specified
|
|
||||||
/// complex type to the specified destination type, where the destination
|
|
||||||
/// type is an LLVM scalar type.
|
|
||||||
Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
|
|
||||||
QualType SrcTy, QualType DstTy);
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Visitor Methods
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
Value *VisitStmt(Stmt *S) {
|
|
||||||
S->dump(CGF.getContext().SourceMgr);
|
|
||||||
assert(0 && "Stmt can't have complex result type!");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
Value *VisitExpr(Expr *S);
|
|
||||||
Value *VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr()); }
|
|
||||||
|
|
||||||
// Leaves.
|
|
||||||
Value *VisitIntegerLiteral(const IntegerLiteral *E) {
|
|
||||||
return llvm::ConstantInt::get(E->getValue());
|
|
||||||
}
|
|
||||||
Value *VisitFloatingLiteral(const FloatingLiteral *E) {
|
|
||||||
double V = E->getValue();
|
|
||||||
// FIXME: Change this when FloatingLiteral uses an APFloat internally.
|
|
||||||
const llvm::Type *Ty = ConvertType(E->getType());
|
|
||||||
if (Ty == llvm::Type::FloatTy)
|
|
||||||
return llvm::ConstantFP::get(Ty, llvm::APFloat((float)V));
|
|
||||||
assert(Ty == llvm::Type::DoubleTy && "Unknown float type!");
|
|
||||||
return llvm::ConstantFP::get(Ty, llvm::APFloat((double)V));
|
|
||||||
}
|
|
||||||
Value *VisitCharacterLiteral(const CharacterLiteral *E) {
|
|
||||||
return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
|
|
||||||
}
|
|
||||||
Value *VisitTypesCompatibleExpr(const TypesCompatibleExpr *E) {
|
|
||||||
return llvm::ConstantInt::get(ConvertType(E->getType()),
|
|
||||||
E->typesAreCompatible());
|
|
||||||
}
|
|
||||||
Value *VisitSizeOfAlignOfTypeExpr(const SizeOfAlignOfTypeExpr *E) {
|
|
||||||
return EmitSizeAlignOf(E->getArgumentType(), E->getType(), E->isSizeOf());
|
|
||||||
}
|
|
||||||
|
|
||||||
// l-values.
|
|
||||||
Value *VisitDeclRefExpr(DeclRefExpr *E) {
|
|
||||||
if (const EnumConstantDecl *EC = dyn_cast<EnumConstantDecl>(E->getDecl()))
|
|
||||||
return llvm::ConstantInt::get(EC->getInitVal());
|
|
||||||
return EmitLoadOfLValue(E);
|
|
||||||
}
|
|
||||||
Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
|
|
||||||
Value *VisitMemberExpr(Expr *E) { return EmitLoadOfLValue(E); }
|
|
||||||
Value *VisitOCUVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); }
|
|
||||||
Value *VisitStringLiteral(Expr *E) { return EmitLValue(E).getAddress(); }
|
|
||||||
Value *VisitPreDefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); }
|
|
||||||
|
|
||||||
// FIXME: CompoundLiteralExpr
|
|
||||||
Value *VisitImplicitCastExpr(const ImplicitCastExpr *E);
|
|
||||||
Value *VisitCastExpr(const CastExpr *E) {
|
|
||||||
return EmitCastExpr(E->getSubExpr(), E->getType());
|
|
||||||
}
|
|
||||||
Value *EmitCastExpr(const Expr *E, QualType T);
|
|
||||||
|
|
||||||
Value *VisitCallExpr(const CallExpr *E) {
|
|
||||||
return CGF.EmitCallExpr(E).getScalarVal();
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *VisitStmtExpr(const StmtExpr *E);
|
|
||||||
|
|
||||||
// Unary Operators.
|
|
||||||
Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre);
|
|
||||||
Value *VisitUnaryPostDec(const UnaryOperator *E) {
|
|
||||||
return VisitPrePostIncDec(E, false, false);
|
|
||||||
}
|
|
||||||
Value *VisitUnaryPostInc(const UnaryOperator *E) {
|
|
||||||
return VisitPrePostIncDec(E, true, false);
|
|
||||||
}
|
|
||||||
Value *VisitUnaryPreDec(const UnaryOperator *E) {
|
|
||||||
return VisitPrePostIncDec(E, false, true);
|
|
||||||
}
|
|
||||||
Value *VisitUnaryPreInc(const UnaryOperator *E) {
|
|
||||||
return VisitPrePostIncDec(E, true, true);
|
|
||||||
}
|
|
||||||
Value *VisitUnaryAddrOf(const UnaryOperator *E) {
|
|
||||||
return EmitLValue(E->getSubExpr()).getAddress();
|
|
||||||
}
|
|
||||||
Value *VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); }
|
|
||||||
Value *VisitUnaryPlus(const UnaryOperator *E) {
|
|
||||||
return Visit(E->getSubExpr());
|
|
||||||
}
|
|
||||||
Value *VisitUnaryMinus (const UnaryOperator *E);
|
|
||||||
Value *VisitUnaryNot (const UnaryOperator *E);
|
|
||||||
Value *VisitUnaryLNot (const UnaryOperator *E);
|
|
||||||
Value *VisitUnarySizeOf (const UnaryOperator *E) {
|
|
||||||
return EmitSizeAlignOf(E->getSubExpr()->getType(), E->getType(), true);
|
|
||||||
}
|
|
||||||
Value *VisitUnaryAlignOf (const UnaryOperator *E) {
|
|
||||||
return EmitSizeAlignOf(E->getSubExpr()->getType(), E->getType(), false);
|
|
||||||
}
|
|
||||||
Value *EmitSizeAlignOf(QualType TypeToSize, QualType RetType,
|
|
||||||
bool isSizeOf);
|
|
||||||
Value *VisitUnaryReal (const UnaryOperator *E);
|
|
||||||
Value *VisitUnaryImag (const UnaryOperator *E);
|
|
||||||
Value *VisitUnaryExtension(const UnaryOperator *E) {
|
|
||||||
return Visit(E->getSubExpr());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Binary Operators.
|
|
||||||
Value *EmitMul(const BinOpInfo &Ops) {
|
|
||||||
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
|
|
||||||
}
|
|
||||||
Value *EmitDiv(const BinOpInfo &Ops);
|
|
||||||
Value *EmitRem(const BinOpInfo &Ops);
|
|
||||||
Value *EmitAdd(const BinOpInfo &Ops);
|
|
||||||
Value *EmitSub(const BinOpInfo &Ops);
|
|
||||||
Value *EmitShl(const BinOpInfo &Ops);
|
|
||||||
Value *EmitShr(const BinOpInfo &Ops);
|
|
||||||
Value *EmitAnd(const BinOpInfo &Ops) {
|
|
||||||
return Builder.CreateAnd(Ops.LHS, Ops.RHS, "and");
|
|
||||||
}
|
|
||||||
Value *EmitXor(const BinOpInfo &Ops) {
|
|
||||||
return Builder.CreateXor(Ops.LHS, Ops.RHS, "xor");
|
|
||||||
}
|
|
||||||
Value *EmitOr (const BinOpInfo &Ops) {
|
|
||||||
return Builder.CreateOr(Ops.LHS, Ops.RHS, "or");
|
|
||||||
}
|
|
||||||
|
|
||||||
BinOpInfo EmitBinOps(const BinaryOperator *E);
|
|
||||||
Value *EmitCompoundAssign(const CompoundAssignOperator *E,
|
|
||||||
Value *(ScalarExprEmitter::*F)(const BinOpInfo &));
|
|
||||||
|
|
||||||
// Binary operators and binary compound assignment operators.
|
|
||||||
#define HANDLEBINOP(OP) \
|
|
||||||
Value *VisitBin ## OP(const BinaryOperator *E) { \
|
|
||||||
return Emit ## OP(EmitBinOps(E)); \
|
|
||||||
} \
|
|
||||||
Value *VisitBin ## OP ## Assign(const CompoundAssignOperator *E) { \
|
|
||||||
return EmitCompoundAssign(E, &ScalarExprEmitter::Emit ## OP); \
|
|
||||||
}
|
|
||||||
HANDLEBINOP(Mul);
|
|
||||||
HANDLEBINOP(Div);
|
|
||||||
HANDLEBINOP(Rem);
|
|
||||||
HANDLEBINOP(Add);
|
|
||||||
// (Sub) - Sub is handled specially below for ptr-ptr subtract.
|
|
||||||
HANDLEBINOP(Shl);
|
|
||||||
HANDLEBINOP(Shr);
|
|
||||||
HANDLEBINOP(And);
|
|
||||||
HANDLEBINOP(Xor);
|
|
||||||
HANDLEBINOP(Or);
|
|
||||||
#undef HANDLEBINOP
|
|
||||||
Value *VisitBinSub(const BinaryOperator *E);
|
|
||||||
Value *VisitBinSubAssign(const CompoundAssignOperator *E) {
|
|
||||||
return EmitCompoundAssign(E, &ScalarExprEmitter::EmitSub);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comparisons.
|
|
||||||
Value *EmitCompare(const BinaryOperator *E, unsigned UICmpOpc,
|
|
||||||
unsigned SICmpOpc, unsigned FCmpOpc);
|
|
||||||
#define VISITCOMP(CODE, UI, SI, FP) \
|
|
||||||
Value *VisitBin##CODE(const BinaryOperator *E) { \
|
|
||||||
return EmitCompare(E, llvm::ICmpInst::UI, llvm::ICmpInst::SI, \
|
|
||||||
llvm::FCmpInst::FP); }
|
|
||||||
VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT);
|
|
||||||
VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT);
|
|
||||||
VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE);
|
|
||||||
VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE);
|
|
||||||
VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ);
|
|
||||||
VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE);
|
|
||||||
#undef VISITCOMP
|
|
||||||
|
|
||||||
Value *VisitBinAssign (const BinaryOperator *E);
|
|
||||||
|
|
||||||
Value *VisitBinLAnd (const BinaryOperator *E);
|
|
||||||
Value *VisitBinLOr (const BinaryOperator *E);
|
|
||||||
Value *VisitBinComma (const BinaryOperator *E);
|
|
||||||
|
|
||||||
// Other Operators.
|
|
||||||
Value *VisitConditionalOperator(const ConditionalOperator *CO);
|
|
||||||
Value *VisitChooseExpr(ChooseExpr *CE);
|
|
||||||
Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
|
|
||||||
return CGF.EmitObjCStringLiteral(E);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // end anonymous namespace.
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Utilities
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// EmitConversionToBool - Convert the specified expression value to a
|
|
||||||
/// boolean (i1) truth value. This is equivalent to "Val != 0".
|
|
||||||
Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) {
|
|
||||||
assert(SrcType->isCanonical() && "EmitScalarConversion strips typedefs");
|
|
||||||
|
|
||||||
if (SrcType->isRealFloatingType()) {
|
|
||||||
// Compare against 0.0 for fp scalars.
|
|
||||||
llvm::Value *Zero = llvm::Constant::getNullValue(Src->getType());
|
|
||||||
return Builder.CreateFCmpUNE(Src, Zero, "tobool");
|
|
||||||
}
|
|
||||||
|
|
||||||
assert((SrcType->isIntegerType() || SrcType->isPointerType()) &&
|
|
||||||
"Unknown scalar type to convert");
|
|
||||||
|
|
||||||
// Because of the type rules of C, we often end up computing a logical value,
|
|
||||||
// then zero extending it to int, then wanting it as a logical value again.
|
|
||||||
// Optimize this common case.
|
|
||||||
if (llvm::ZExtInst *ZI = dyn_cast<llvm::ZExtInst>(Src)) {
|
|
||||||
if (ZI->getOperand(0)->getType() == llvm::Type::Int1Ty) {
|
|
||||||
Value *Result = ZI->getOperand(0);
|
|
||||||
ZI->eraseFromParent();
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare against an integer or pointer null.
|
|
||||||
llvm::Value *Zero = llvm::Constant::getNullValue(Src->getType());
|
|
||||||
return Builder.CreateICmpNE(Src, Zero, "tobool");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitScalarConversion - Emit a conversion from the specified type to the
|
|
||||||
/// specified destination type, both of which are LLVM scalar types.
|
|
||||||
Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
|
|
||||||
QualType DstType) {
|
|
||||||
SrcType = SrcType.getCanonicalType();
|
|
||||||
DstType = DstType.getCanonicalType();
|
|
||||||
if (SrcType == DstType) return Src;
|
|
||||||
|
|
||||||
if (DstType->isVoidType()) return 0;
|
|
||||||
|
|
||||||
// Handle conversions to bool first, they are special: comparisons against 0.
|
|
||||||
if (DstType->isBooleanType())
|
|
||||||
return EmitConversionToBool(Src, SrcType);
|
|
||||||
|
|
||||||
const llvm::Type *DstTy = ConvertType(DstType);
|
|
||||||
|
|
||||||
// Ignore conversions like int -> uint.
|
|
||||||
if (Src->getType() == DstTy)
|
|
||||||
return Src;
|
|
||||||
|
|
||||||
// Handle pointer conversions next: pointers can only be converted to/from
|
|
||||||
// other pointers and integers.
|
|
||||||
if (isa<PointerType>(DstType)) {
|
|
||||||
// The source value may be an integer, or a pointer.
|
|
||||||
if (isa<llvm::PointerType>(Src->getType()))
|
|
||||||
return Builder.CreateBitCast(Src, DstTy, "conv");
|
|
||||||
assert(SrcType->isIntegerType() && "Not ptr->ptr or int->ptr conversion?");
|
|
||||||
return Builder.CreateIntToPtr(Src, DstTy, "conv");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isa<PointerType>(SrcType)) {
|
|
||||||
// Must be an ptr to int cast.
|
|
||||||
assert(isa<llvm::IntegerType>(DstTy) && "not ptr->int?");
|
|
||||||
return Builder.CreateIntToPtr(Src, DstTy, "conv");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, we have the arithmetic types: real int/float.
|
|
||||||
if (isa<llvm::IntegerType>(Src->getType())) {
|
|
||||||
bool InputSigned = SrcType->isSignedIntegerType();
|
|
||||||
if (isa<llvm::IntegerType>(DstTy))
|
|
||||||
return Builder.CreateIntCast(Src, DstTy, InputSigned, "conv");
|
|
||||||
else if (InputSigned)
|
|
||||||
return Builder.CreateSIToFP(Src, DstTy, "conv");
|
|
||||||
else
|
|
||||||
return Builder.CreateUIToFP(Src, DstTy, "conv");
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(Src->getType()->isFloatingPoint() && "Unknown real conversion");
|
|
||||||
if (isa<llvm::IntegerType>(DstTy)) {
|
|
||||||
if (DstType->isSignedIntegerType())
|
|
||||||
return Builder.CreateFPToSI(Src, DstTy, "conv");
|
|
||||||
else
|
|
||||||
return Builder.CreateFPToUI(Src, DstTy, "conv");
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(DstTy->isFloatingPoint() && "Unknown real conversion");
|
|
||||||
if (DstTy->getTypeID() < Src->getType()->getTypeID())
|
|
||||||
return Builder.CreateFPTrunc(Src, DstTy, "conv");
|
|
||||||
else
|
|
||||||
return Builder.CreateFPExt(Src, DstTy, "conv");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitComplexToScalarConversion - Emit a conversion from the specified
|
|
||||||
/// complex type to the specified destination type, where the destination
|
|
||||||
/// type is an LLVM scalar type.
|
|
||||||
Value *ScalarExprEmitter::
|
|
||||||
EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
|
|
||||||
QualType SrcTy, QualType DstTy) {
|
|
||||||
// Get the source element type.
|
|
||||||
SrcTy = cast<ComplexType>(SrcTy.getCanonicalType())->getElementType();
|
|
||||||
|
|
||||||
// Handle conversions to bool first, they are special: comparisons against 0.
|
|
||||||
if (DstTy->isBooleanType()) {
|
|
||||||
// Complex != 0 -> (Real != 0) | (Imag != 0)
|
|
||||||
Src.first = EmitScalarConversion(Src.first, SrcTy, DstTy);
|
|
||||||
Src.second = EmitScalarConversion(Src.second, SrcTy, DstTy);
|
|
||||||
return Builder.CreateOr(Src.first, Src.second, "tobool");
|
|
||||||
}
|
|
||||||
|
|
||||||
// C99 6.3.1.7p2: "When a value of complex type is converted to a real type,
|
|
||||||
// the imaginary part of the complex value is discarded and the value of the
|
|
||||||
// real part is converted according to the conversion rules for the
|
|
||||||
// corresponding real type.
|
|
||||||
return EmitScalarConversion(Src.first, SrcTy, DstTy);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Visitor Methods
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitExpr(Expr *E) {
|
|
||||||
fprintf(stderr, "Unimplemented scalar expr!\n");
|
|
||||||
E->dump(CGF.getContext().SourceMgr);
|
|
||||||
if (E->getType()->isVoidType())
|
|
||||||
return 0;
|
|
||||||
return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
|
|
||||||
// Emit subscript expressions in rvalue context's. For most cases, this just
|
|
||||||
// loads the lvalue formed by the subscript expr. However, we have to be
|
|
||||||
// careful, because the base of a vector subscript is occasionally an rvalue,
|
|
||||||
// so we can't get it as an lvalue.
|
|
||||||
if (!E->getBase()->getType()->isVectorType())
|
|
||||||
return EmitLoadOfLValue(E);
|
|
||||||
|
|
||||||
// Handle the vector case. The base must be a vector, the index must be an
|
|
||||||
// integer value.
|
|
||||||
Value *Base = Visit(E->getBase());
|
|
||||||
Value *Idx = Visit(E->getIdx());
|
|
||||||
|
|
||||||
// FIXME: Convert Idx to i32 type.
|
|
||||||
return Builder.CreateExtractElement(Base, Idx, "vecext");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// VisitImplicitCastExpr - Implicit casts are the same as normal casts, but
|
|
||||||
/// also handle things like function to pointer-to-function decay, and array to
|
|
||||||
/// pointer decay.
|
|
||||||
Value *ScalarExprEmitter::VisitImplicitCastExpr(const ImplicitCastExpr *E) {
|
|
||||||
const Expr *Op = E->getSubExpr();
|
|
||||||
|
|
||||||
// If this is due to array->pointer conversion, emit the array expression as
|
|
||||||
// an l-value.
|
|
||||||
if (Op->getType()->isArrayType()) {
|
|
||||||
// FIXME: For now we assume that all source arrays map to LLVM arrays. This
|
|
||||||
// will not true when we add support for VLAs.
|
|
||||||
Value *V = EmitLValue(Op).getAddress(); // Bitfields can't be arrays.
|
|
||||||
|
|
||||||
assert(isa<llvm::PointerType>(V->getType()) &&
|
|
||||||
isa<llvm::ArrayType>(cast<llvm::PointerType>(V->getType())
|
|
||||||
->getElementType()) &&
|
|
||||||
"Doesn't support VLAs yet!");
|
|
||||||
llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
|
|
||||||
|
|
||||||
llvm::Value *Ops[] = {Idx0, Idx0};
|
|
||||||
return Builder.CreateGEP(V, Ops, Ops+2, "arraydecay");
|
|
||||||
}
|
|
||||||
|
|
||||||
return EmitCastExpr(Op, E->getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts
|
|
||||||
// have to handle a more broad range of conversions than explicit casts, as they
|
|
||||||
// handle things like function to ptr-to-function decay etc.
|
|
||||||
Value *ScalarExprEmitter::EmitCastExpr(const Expr *E, QualType DestTy) {
|
|
||||||
// Handle cases where the source is an non-complex type.
|
|
||||||
if (!E->getType()->isComplexType()) {
|
|
||||||
Value *Src = Visit(const_cast<Expr*>(E));
|
|
||||||
|
|
||||||
// Use EmitScalarConversion to perform the conversion.
|
|
||||||
return EmitScalarConversion(Src, E->getType(), DestTy);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle cases where the source is a complex type.
|
|
||||||
return EmitComplexToScalarConversion(CGF.EmitComplexExpr(E), E->getType(),
|
|
||||||
DestTy);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) {
|
|
||||||
return CGF.EmitCompoundStmt(*E->getSubStmt(), true).getScalarVal();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Unary Operators
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
|
|
||||||
bool isInc, bool isPre) {
|
|
||||||
LValue LV = EmitLValue(E->getSubExpr());
|
|
||||||
// FIXME: Handle volatile!
|
|
||||||
Value *InVal = CGF.EmitLoadOfLValue(LV, // false
|
|
||||||
E->getSubExpr()->getType()).getScalarVal();
|
|
||||||
|
|
||||||
int AmountVal = isInc ? 1 : -1;
|
|
||||||
|
|
||||||
Value *NextVal;
|
|
||||||
if (isa<llvm::PointerType>(InVal->getType())) {
|
|
||||||
// FIXME: This isn't right for VLAs.
|
|
||||||
NextVal = llvm::ConstantInt::get(llvm::Type::Int32Ty, AmountVal);
|
|
||||||
NextVal = Builder.CreateGEP(InVal, NextVal);
|
|
||||||
} else {
|
|
||||||
// Add the inc/dec to the real part.
|
|
||||||
if (isa<llvm::IntegerType>(InVal->getType()))
|
|
||||||
NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal);
|
|
||||||
else
|
|
||||||
NextVal = llvm::ConstantFP::get(InVal->getType(),
|
|
||||||
static_cast<double>(AmountVal));
|
|
||||||
NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the updated result through the lvalue.
|
|
||||||
CGF.EmitStoreThroughLValue(RValue::get(NextVal), LV,
|
|
||||||
E->getSubExpr()->getType());
|
|
||||||
|
|
||||||
// If this is a postinc, return the value read from memory, otherwise use the
|
|
||||||
// updated value.
|
|
||||||
return isPre ? NextVal : InVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
|
|
||||||
Value *Op = Visit(E->getSubExpr());
|
|
||||||
return Builder.CreateNeg(Op, "neg");
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
|
|
||||||
Value *Op = Visit(E->getSubExpr());
|
|
||||||
return Builder.CreateNot(Op, "neg");
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
|
|
||||||
// Compare operand to zero.
|
|
||||||
Value *BoolVal = CGF.EvaluateExprAsBool(E->getSubExpr());
|
|
||||||
|
|
||||||
// Invert value.
|
|
||||||
// TODO: Could dynamically modify easy computations here. For example, if
|
|
||||||
// the operand is an icmp ne, turn into icmp eq.
|
|
||||||
BoolVal = Builder.CreateNot(BoolVal, "lnot");
|
|
||||||
|
|
||||||
// ZExt result to int.
|
|
||||||
return Builder.CreateZExt(BoolVal, CGF.LLVMIntTy, "lnot.ext");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitSizeAlignOf - Return the size or alignment of the 'TypeToSize' type as
|
|
||||||
/// an integer (RetType).
|
|
||||||
Value *ScalarExprEmitter::EmitSizeAlignOf(QualType TypeToSize,
|
|
||||||
QualType RetType,bool isSizeOf){
|
|
||||||
/// FIXME: This doesn't handle VLAs yet!
|
|
||||||
std::pair<uint64_t, unsigned> Info =
|
|
||||||
CGF.getContext().getTypeInfo(TypeToSize, SourceLocation());
|
|
||||||
|
|
||||||
uint64_t Val = isSizeOf ? Info.first : Info.second;
|
|
||||||
Val /= 8; // Return size in bytes, not bits.
|
|
||||||
|
|
||||||
assert(RetType->isIntegerType() && "Result type must be an integer!");
|
|
||||||
|
|
||||||
unsigned ResultWidth = static_cast<unsigned>(CGF.getContext().getTypeSize(RetType,SourceLocation()));
|
|
||||||
return llvm::ConstantInt::get(llvm::APInt(ResultWidth, Val));
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) {
|
|
||||||
Expr *Op = E->getSubExpr();
|
|
||||||
if (Op->getType()->isComplexType())
|
|
||||||
return CGF.EmitComplexExpr(Op).first;
|
|
||||||
return Visit(Op);
|
|
||||||
}
|
|
||||||
Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
|
|
||||||
Expr *Op = E->getSubExpr();
|
|
||||||
if (Op->getType()->isComplexType())
|
|
||||||
return CGF.EmitComplexExpr(Op).second;
|
|
||||||
|
|
||||||
// __imag on a scalar returns zero. Emit it the subexpr to ensure side
|
|
||||||
// effects are evaluated.
|
|
||||||
CGF.EmitScalarExpr(Op);
|
|
||||||
return llvm::Constant::getNullValue(ConvertType(E->getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Binary Operators
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
|
|
||||||
BinOpInfo Result;
|
|
||||||
Result.LHS = Visit(E->getLHS());
|
|
||||||
Result.RHS = Visit(E->getRHS());
|
|
||||||
Result.Ty = E->getType();
|
|
||||||
Result.E = E;
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
|
|
||||||
Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
|
|
||||||
QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType();
|
|
||||||
|
|
||||||
BinOpInfo OpInfo;
|
|
||||||
|
|
||||||
// Load the LHS and RHS operands.
|
|
||||||
LValue LHSLV = EmitLValue(E->getLHS());
|
|
||||||
OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy);
|
|
||||||
|
|
||||||
// Determine the computation type. If the RHS is complex, then this is one of
|
|
||||||
// the add/sub/mul/div operators. All of these operators can be computed in
|
|
||||||
// with just their real component even though the computation domain really is
|
|
||||||
// complex.
|
|
||||||
QualType ComputeType = E->getComputationType();
|
|
||||||
|
|
||||||
// If the computation type is complex, then the RHS is complex. Emit the RHS.
|
|
||||||
if (const ComplexType *CT = ComputeType->getAsComplexType()) {
|
|
||||||
ComputeType = CT->getElementType();
|
|
||||||
|
|
||||||
// Emit the RHS, only keeping the real component.
|
|
||||||
OpInfo.RHS = CGF.EmitComplexExpr(E->getRHS()).first;
|
|
||||||
RHSTy = RHSTy->getAsComplexType()->getElementType();
|
|
||||||
} else {
|
|
||||||
// Otherwise the RHS is a simple scalar value.
|
|
||||||
OpInfo.RHS = Visit(E->getRHS());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the LHS/RHS values to the computation type.
|
|
||||||
OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, ComputeType);
|
|
||||||
|
|
||||||
// Do not merge types for -= where the LHS is a pointer.
|
|
||||||
if (E->getOpcode() != BinaryOperator::SubAssign ||
|
|
||||||
!E->getLHS()->getType()->isPointerType()) {
|
|
||||||
OpInfo.RHS = EmitScalarConversion(OpInfo.RHS, RHSTy, ComputeType);
|
|
||||||
}
|
|
||||||
OpInfo.Ty = ComputeType;
|
|
||||||
OpInfo.E = E;
|
|
||||||
|
|
||||||
// Expand the binary operator.
|
|
||||||
Value *Result = (this->*Func)(OpInfo);
|
|
||||||
|
|
||||||
// Truncate the result back to the LHS type.
|
|
||||||
Result = EmitScalarConversion(Result, ComputeType, LHSTy);
|
|
||||||
|
|
||||||
// Store the result value into the LHS lvalue.
|
|
||||||
CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, E->getType());
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
|
|
||||||
if (Ops.LHS->getType()->isFloatingPoint())
|
|
||||||
return Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
|
|
||||||
else if (Ops.Ty->isUnsignedIntegerType())
|
|
||||||
return Builder.CreateUDiv(Ops.LHS, Ops.RHS, "div");
|
|
||||||
else
|
|
||||||
return Builder.CreateSDiv(Ops.LHS, Ops.RHS, "div");
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
|
|
||||||
// Rem in C can't be a floating point type: C99 6.5.5p2.
|
|
||||||
if (Ops.Ty->isUnsignedIntegerType())
|
|
||||||
return Builder.CreateURem(Ops.LHS, Ops.RHS, "rem");
|
|
||||||
else
|
|
||||||
return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
|
|
||||||
if (!Ops.Ty->isPointerType())
|
|
||||||
return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add");
|
|
||||||
|
|
||||||
// FIXME: What about a pointer to a VLA?
|
|
||||||
if (isa<llvm::PointerType>(Ops.LHS->getType())) // pointer + int
|
|
||||||
return Builder.CreateGEP(Ops.LHS, Ops.RHS, "add.ptr");
|
|
||||||
// int + pointer
|
|
||||||
return Builder.CreateGEP(Ops.RHS, Ops.LHS, "add.ptr");
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
|
|
||||||
if (!isa<llvm::PointerType>(Ops.LHS->getType()))
|
|
||||||
return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
|
|
||||||
|
|
||||||
// pointer - int
|
|
||||||
assert(!isa<llvm::PointerType>(Ops.RHS->getType()) &&
|
|
||||||
"ptr-ptr shouldn't get here");
|
|
||||||
// FIXME: The pointer could point to a VLA.
|
|
||||||
Value *NegatedRHS = Builder.CreateNeg(Ops.RHS, "sub.ptr.neg");
|
|
||||||
return Builder.CreateGEP(Ops.LHS, NegatedRHS, "sub.ptr");
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitBinSub(const BinaryOperator *E) {
|
|
||||||
// "X - Y" is different from "X -= Y" in one case: when Y is a pointer. In
|
|
||||||
// the compound assignment case it is invalid, so just handle it here.
|
|
||||||
if (!E->getRHS()->getType()->isPointerType())
|
|
||||||
return EmitSub(EmitBinOps(E));
|
|
||||||
|
|
||||||
// pointer - pointer
|
|
||||||
Value *LHS = Visit(E->getLHS());
|
|
||||||
Value *RHS = Visit(E->getRHS());
|
|
||||||
|
|
||||||
const PointerType *LHSPtrType = E->getLHS()->getType()->getAsPointerType();
|
|
||||||
assert(LHSPtrType == E->getRHS()->getType()->getAsPointerType() &&
|
|
||||||
"Can't subtract different pointer types");
|
|
||||||
|
|
||||||
QualType LHSElementType = LHSPtrType->getPointeeType();
|
|
||||||
uint64_t ElementSize = CGF.getContext().getTypeSize(LHSElementType,
|
|
||||||
SourceLocation()) / 8;
|
|
||||||
|
|
||||||
const llvm::Type *ResultType = ConvertType(E->getType());
|
|
||||||
LHS = Builder.CreatePtrToInt(LHS, ResultType, "sub.ptr.lhs.cast");
|
|
||||||
RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast");
|
|
||||||
Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub");
|
|
||||||
|
|
||||||
// HACK: LLVM doesn't have an divide instruction that 'knows' there is no
|
|
||||||
// remainder. As such, we handle common power-of-two cases here to generate
|
|
||||||
// better code.
|
|
||||||
if (llvm::isPowerOf2_64(ElementSize)) {
|
|
||||||
Value *ShAmt =
|
|
||||||
llvm::ConstantInt::get(ResultType, llvm::Log2_64(ElementSize));
|
|
||||||
return Builder.CreateAShr(BytesBetween, ShAmt, "sub.ptr.shr");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, do a full sdiv.
|
|
||||||
Value *BytesPerElt = llvm::ConstantInt::get(ResultType, ElementSize);
|
|
||||||
return Builder.CreateSDiv(BytesBetween, BytesPerElt, "sub.ptr.div");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
|
|
||||||
// LLVM requires the LHS and RHS to be the same type: promote or truncate the
|
|
||||||
// RHS to the same size as the LHS.
|
|
||||||
Value *RHS = Ops.RHS;
|
|
||||||
if (Ops.LHS->getType() != RHS->getType())
|
|
||||||
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
|
|
||||||
|
|
||||||
return Builder.CreateShl(Ops.LHS, RHS, "shl");
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
|
|
||||||
// LLVM requires the LHS and RHS to be the same type: promote or truncate the
|
|
||||||
// RHS to the same size as the LHS.
|
|
||||||
Value *RHS = Ops.RHS;
|
|
||||||
if (Ops.LHS->getType() != RHS->getType())
|
|
||||||
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
|
|
||||||
|
|
||||||
if (Ops.Ty->isUnsignedIntegerType())
|
|
||||||
return Builder.CreateLShr(Ops.LHS, RHS, "shr");
|
|
||||||
return Builder.CreateAShr(Ops.LHS, RHS, "shr");
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
|
|
||||||
unsigned SICmpOpc, unsigned FCmpOpc) {
|
|
||||||
Value *Result;
|
|
||||||
QualType LHSTy = E->getLHS()->getType();
|
|
||||||
if (!LHSTy->isComplexType()) {
|
|
||||||
Value *LHS = Visit(E->getLHS());
|
|
||||||
Value *RHS = Visit(E->getRHS());
|
|
||||||
|
|
||||||
if (LHS->getType()->isFloatingPoint()) {
|
|
||||||
Result = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc,
|
|
||||||
LHS, RHS, "cmp");
|
|
||||||
} else if (LHSTy->isUnsignedIntegerType()) {
|
|
||||||
Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc,
|
|
||||||
LHS, RHS, "cmp");
|
|
||||||
} else {
|
|
||||||
// Signed integers and pointers.
|
|
||||||
Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)SICmpOpc,
|
|
||||||
LHS, RHS, "cmp");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Complex Comparison: can only be an equality comparison.
|
|
||||||
CodeGenFunction::ComplexPairTy LHS = CGF.EmitComplexExpr(E->getLHS());
|
|
||||||
CodeGenFunction::ComplexPairTy RHS = CGF.EmitComplexExpr(E->getRHS());
|
|
||||||
|
|
||||||
QualType CETy =
|
|
||||||
cast<ComplexType>(LHSTy.getCanonicalType())->getElementType();
|
|
||||||
|
|
||||||
Value *ResultR, *ResultI;
|
|
||||||
if (CETy->isRealFloatingType()) {
|
|
||||||
ResultR = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc,
|
|
||||||
LHS.first, RHS.first, "cmp.r");
|
|
||||||
ResultI = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc,
|
|
||||||
LHS.second, RHS.second, "cmp.i");
|
|
||||||
} else {
|
|
||||||
// Complex comparisons can only be equality comparisons. As such, signed
|
|
||||||
// and unsigned opcodes are the same.
|
|
||||||
ResultR = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc,
|
|
||||||
LHS.first, RHS.first, "cmp.r");
|
|
||||||
ResultI = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc,
|
|
||||||
LHS.second, RHS.second, "cmp.i");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (E->getOpcode() == BinaryOperator::EQ) {
|
|
||||||
Result = Builder.CreateAnd(ResultR, ResultI, "and.ri");
|
|
||||||
} else {
|
|
||||||
assert(E->getOpcode() == BinaryOperator::NE &&
|
|
||||||
"Complex comparison other than == or != ?");
|
|
||||||
Result = Builder.CreateOr(ResultR, ResultI, "or.ri");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ZExt result to int.
|
|
||||||
return Builder.CreateZExt(Result, CGF.LLVMIntTy, "cmp.ext");
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
|
|
||||||
LValue LHS = EmitLValue(E->getLHS());
|
|
||||||
Value *RHS = Visit(E->getRHS());
|
|
||||||
|
|
||||||
// Store the value into the LHS.
|
|
||||||
// FIXME: Volatility!
|
|
||||||
CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS, E->getType());
|
|
||||||
|
|
||||||
// Return the RHS.
|
|
||||||
return RHS;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
|
|
||||||
Value *LHSCond = CGF.EvaluateExprAsBool(E->getLHS());
|
|
||||||
|
|
||||||
llvm::BasicBlock *ContBlock = new llvm::BasicBlock("land_cont");
|
|
||||||
llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("land_rhs");
|
|
||||||
|
|
||||||
llvm::BasicBlock *OrigBlock = Builder.GetInsertBlock();
|
|
||||||
Builder.CreateCondBr(LHSCond, RHSBlock, ContBlock);
|
|
||||||
|
|
||||||
CGF.EmitBlock(RHSBlock);
|
|
||||||
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
|
|
||||||
|
|
||||||
// Reaquire the RHS block, as there may be subblocks inserted.
|
|
||||||
RHSBlock = Builder.GetInsertBlock();
|
|
||||||
CGF.EmitBlock(ContBlock);
|
|
||||||
|
|
||||||
// Create a PHI node. If we just evaluted the LHS condition, the result is
|
|
||||||
// false. If we evaluated both, the result is the RHS condition.
|
|
||||||
llvm::PHINode *PN = Builder.CreatePHI(llvm::Type::Int1Ty, "land");
|
|
||||||
PN->reserveOperandSpace(2);
|
|
||||||
PN->addIncoming(llvm::ConstantInt::getFalse(), OrigBlock);
|
|
||||||
PN->addIncoming(RHSCond, RHSBlock);
|
|
||||||
|
|
||||||
// ZExt result to int.
|
|
||||||
return Builder.CreateZExt(PN, CGF.LLVMIntTy, "land.ext");
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
|
|
||||||
Value *LHSCond = CGF.EvaluateExprAsBool(E->getLHS());
|
|
||||||
|
|
||||||
llvm::BasicBlock *ContBlock = new llvm::BasicBlock("lor_cont");
|
|
||||||
llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("lor_rhs");
|
|
||||||
|
|
||||||
llvm::BasicBlock *OrigBlock = Builder.GetInsertBlock();
|
|
||||||
Builder.CreateCondBr(LHSCond, ContBlock, RHSBlock);
|
|
||||||
|
|
||||||
CGF.EmitBlock(RHSBlock);
|
|
||||||
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
|
|
||||||
|
|
||||||
// Reaquire the RHS block, as there may be subblocks inserted.
|
|
||||||
RHSBlock = Builder.GetInsertBlock();
|
|
||||||
CGF.EmitBlock(ContBlock);
|
|
||||||
|
|
||||||
// Create a PHI node. If we just evaluted the LHS condition, the result is
|
|
||||||
// true. If we evaluated both, the result is the RHS condition.
|
|
||||||
llvm::PHINode *PN = Builder.CreatePHI(llvm::Type::Int1Ty, "lor");
|
|
||||||
PN->reserveOperandSpace(2);
|
|
||||||
PN->addIncoming(llvm::ConstantInt::getTrue(), OrigBlock);
|
|
||||||
PN->addIncoming(RHSCond, RHSBlock);
|
|
||||||
|
|
||||||
// ZExt result to int.
|
|
||||||
return Builder.CreateZExt(PN, CGF.LLVMIntTy, "lor.ext");
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) {
|
|
||||||
CGF.EmitStmt(E->getLHS());
|
|
||||||
return Visit(E->getRHS());
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Other Operators
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::
|
|
||||||
VisitConditionalOperator(const ConditionalOperator *E) {
|
|
||||||
llvm::BasicBlock *LHSBlock = new llvm::BasicBlock("cond.?");
|
|
||||||
llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("cond.:");
|
|
||||||
llvm::BasicBlock *ContBlock = new llvm::BasicBlock("cond.cont");
|
|
||||||
|
|
||||||
Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
|
|
||||||
Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
|
|
||||||
|
|
||||||
CGF.EmitBlock(LHSBlock);
|
|
||||||
|
|
||||||
// Handle the GNU extension for missing LHS.
|
|
||||||
Value *LHS = E->getLHS() ? Visit(E->getLHS()) : Cond;
|
|
||||||
Builder.CreateBr(ContBlock);
|
|
||||||
LHSBlock = Builder.GetInsertBlock();
|
|
||||||
|
|
||||||
CGF.EmitBlock(RHSBlock);
|
|
||||||
|
|
||||||
Value *RHS = Visit(E->getRHS());
|
|
||||||
Builder.CreateBr(ContBlock);
|
|
||||||
RHSBlock = Builder.GetInsertBlock();
|
|
||||||
|
|
||||||
CGF.EmitBlock(ContBlock);
|
|
||||||
|
|
||||||
// Create a PHI node for the real part.
|
|
||||||
llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), "cond");
|
|
||||||
PN->reserveOperandSpace(2);
|
|
||||||
PN->addIncoming(LHS, LHSBlock);
|
|
||||||
PN->addIncoming(RHS, RHSBlock);
|
|
||||||
return PN;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) {
|
|
||||||
llvm::APSInt CondVal(32);
|
|
||||||
bool IsConst = E->getCond()->isIntegerConstantExpr(CondVal, CGF.getContext());
|
|
||||||
assert(IsConst && "Condition of choose expr must be i-c-e"); IsConst=IsConst;
|
|
||||||
|
|
||||||
// Emit the LHS or RHS as appropriate.
|
|
||||||
return Visit(CondVal != 0 ? E->getLHS() : E->getRHS());
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Entry Point into this File
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// EmitComplexExpr - Emit the computation of the specified expression of
|
|
||||||
/// complex type, ignoring the result.
|
|
||||||
Value *CodeGenFunction::EmitScalarExpr(const Expr *E) {
|
|
||||||
assert(E && !hasAggregateLLVMType(E->getType()) &&
|
|
||||||
"Invalid scalar expression to emit");
|
|
||||||
|
|
||||||
return ScalarExprEmitter(*this).Visit(const_cast<Expr*>(E));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitScalarConversion - Emit a conversion from the specified type to the
|
|
||||||
/// specified destination type, both of which are LLVM scalar types.
|
|
||||||
Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy,
|
|
||||||
QualType DstTy) {
|
|
||||||
assert(!hasAggregateLLVMType(SrcTy) && !hasAggregateLLVMType(DstTy) &&
|
|
||||||
"Invalid scalar expression to emit");
|
|
||||||
return ScalarExprEmitter(*this).EmitScalarConversion(Src, SrcTy, DstTy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitComplexToScalarConversion - Emit a conversion from the specified
|
|
||||||
/// complex type to the specified destination type, where the destination
|
|
||||||
/// type is an LLVM scalar type.
|
|
||||||
Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src,
|
|
||||||
QualType SrcTy,
|
|
||||||
QualType DstTy) {
|
|
||||||
assert(SrcTy->isComplexType() && !hasAggregateLLVMType(DstTy) &&
|
|
||||||
"Invalid complex -> scalar conversion");
|
|
||||||
return ScalarExprEmitter(*this).EmitComplexToScalarConversion(Src, SrcTy,
|
|
||||||
DstTy);
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Anders Carlsson and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This contains code to emit Objective-C code as LLVM code.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "CodeGenFunction.h"
|
|
||||||
#include "CodeGenModule.h"
|
|
||||||
#include "clang/AST/Expr.h"
|
|
||||||
#include "llvm/Constant.h"
|
|
||||||
using namespace clang;
|
|
||||||
using namespace CodeGen;
|
|
||||||
|
|
||||||
llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E){
|
|
||||||
std::string S(E->getString()->getStrData(), E->getString()->getByteLength());
|
|
||||||
return CGM.GetAddrOfConstantCFString(S);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,339 +0,0 @@
|
|||||||
//===--- CGStmt.cpp - Emit LLVM Code from Statements ----------------------===//
|
|
||||||
//
|
|
||||||
// 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 contains code to emit Stmt nodes as LLVM code.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "CodeGenFunction.h"
|
|
||||||
#include "clang/AST/AST.h"
|
|
||||||
#include "llvm/Constants.h"
|
|
||||||
#include "llvm/DerivedTypes.h"
|
|
||||||
#include "llvm/Function.h"
|
|
||||||
using namespace clang;
|
|
||||||
using namespace CodeGen;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Statement Emission
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitStmt(const Stmt *S) {
|
|
||||||
assert(S && "Null statement?");
|
|
||||||
|
|
||||||
switch (S->getStmtClass()) {
|
|
||||||
default:
|
|
||||||
// Must be an expression in a stmt context. Emit the value (to get
|
|
||||||
// side-effects) and ignore the result.
|
|
||||||
if (const Expr *E = dyn_cast<Expr>(S)) {
|
|
||||||
if (!hasAggregateLLVMType(E->getType()))
|
|
||||||
EmitScalarExpr(E);
|
|
||||||
else if (E->getType()->isComplexType())
|
|
||||||
EmitComplexExpr(E);
|
|
||||||
else
|
|
||||||
EmitAggExpr(E, 0, false);
|
|
||||||
} else {
|
|
||||||
printf("Unimplemented stmt!\n");
|
|
||||||
S->dump(getContext().SourceMgr);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Stmt::NullStmtClass: break;
|
|
||||||
case Stmt::CompoundStmtClass: EmitCompoundStmt(cast<CompoundStmt>(*S)); break;
|
|
||||||
case Stmt::LabelStmtClass: EmitLabelStmt(cast<LabelStmt>(*S)); break;
|
|
||||||
case Stmt::GotoStmtClass: EmitGotoStmt(cast<GotoStmt>(*S)); break;
|
|
||||||
|
|
||||||
case Stmt::IfStmtClass: EmitIfStmt(cast<IfStmt>(*S)); break;
|
|
||||||
case Stmt::WhileStmtClass: EmitWhileStmt(cast<WhileStmt>(*S)); break;
|
|
||||||
case Stmt::DoStmtClass: EmitDoStmt(cast<DoStmt>(*S)); break;
|
|
||||||
case Stmt::ForStmtClass: EmitForStmt(cast<ForStmt>(*S)); break;
|
|
||||||
|
|
||||||
case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break;
|
|
||||||
case Stmt::DeclStmtClass: EmitDeclStmt(cast<DeclStmt>(*S)); break;
|
|
||||||
|
|
||||||
case Stmt::BreakStmtClass: EmitBreakStmt(); break;
|
|
||||||
case Stmt::ContinueStmtClass: EmitContinueStmt(); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitCompoundStmt - Emit a compound statement {..} node. If GetLast is true,
|
|
||||||
/// this captures the expression result of the last sub-statement and returns it
|
|
||||||
/// (for use by the statement expression extension).
|
|
||||||
RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
|
|
||||||
llvm::Value *AggLoc, bool isAggVol) {
|
|
||||||
// FIXME: handle vla's etc.
|
|
||||||
if (S.body_empty() || !isa<Expr>(S.body_back())) GetLast = false;
|
|
||||||
|
|
||||||
for (CompoundStmt::const_body_iterator I = S.body_begin(),
|
|
||||||
E = S.body_end()-GetLast; I != E; ++I)
|
|
||||||
EmitStmt(*I);
|
|
||||||
|
|
||||||
|
|
||||||
if (!GetLast)
|
|
||||||
return RValue::get(0);
|
|
||||||
|
|
||||||
return EmitAnyExpr(cast<Expr>(S.body_back()), AggLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB) {
|
|
||||||
// Emit a branch from this block to the next one if this was a real block. If
|
|
||||||
// this was just a fall-through block after a terminator, don't emit it.
|
|
||||||
llvm::BasicBlock *LastBB = Builder.GetInsertBlock();
|
|
||||||
|
|
||||||
if (LastBB->getTerminator()) {
|
|
||||||
// If the previous block is already terminated, don't touch it.
|
|
||||||
} else if (LastBB->empty() && LastBB->getValueName() == 0) {
|
|
||||||
// If the last block was an empty placeholder, remove it now.
|
|
||||||
// TODO: cache and reuse these.
|
|
||||||
Builder.GetInsertBlock()->eraseFromParent();
|
|
||||||
} else {
|
|
||||||
// Otherwise, create a fall-through branch.
|
|
||||||
Builder.CreateBr(BB);
|
|
||||||
}
|
|
||||||
CurFn->getBasicBlockList().push_back(BB);
|
|
||||||
Builder.SetInsertPoint(BB);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
|
|
||||||
llvm::BasicBlock *NextBB = getBasicBlockForLabel(&S);
|
|
||||||
|
|
||||||
EmitBlock(NextBB);
|
|
||||||
EmitStmt(S.getSubStmt());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
|
|
||||||
Builder.CreateBr(getBasicBlockForLabel(S.getLabel()));
|
|
||||||
|
|
||||||
// Emit a block after the branch so that dead code after a goto has some place
|
|
||||||
// to go.
|
|
||||||
Builder.SetInsertPoint(new llvm::BasicBlock("", CurFn));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
|
|
||||||
// C99 6.8.4.1: The first substatement is executed if the expression compares
|
|
||||||
// unequal to 0. The condition must be a scalar type.
|
|
||||||
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
|
|
||||||
|
|
||||||
llvm::BasicBlock *ContBlock = new llvm::BasicBlock("ifend");
|
|
||||||
llvm::BasicBlock *ThenBlock = new llvm::BasicBlock("ifthen");
|
|
||||||
llvm::BasicBlock *ElseBlock = ContBlock;
|
|
||||||
|
|
||||||
if (S.getElse())
|
|
||||||
ElseBlock = new llvm::BasicBlock("ifelse");
|
|
||||||
|
|
||||||
// Insert the conditional branch.
|
|
||||||
Builder.CreateCondBr(BoolCondVal, ThenBlock, ElseBlock);
|
|
||||||
|
|
||||||
// Emit the 'then' code.
|
|
||||||
EmitBlock(ThenBlock);
|
|
||||||
EmitStmt(S.getThen());
|
|
||||||
Builder.CreateBr(ContBlock);
|
|
||||||
|
|
||||||
// Emit the 'else' code if present.
|
|
||||||
if (const Stmt *Else = S.getElse()) {
|
|
||||||
EmitBlock(ElseBlock);
|
|
||||||
EmitStmt(Else);
|
|
||||||
Builder.CreateBr(ContBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit the continuation block for code after the if.
|
|
||||||
EmitBlock(ContBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
|
|
||||||
// Emit the header for the loop, insert it, which will create an uncond br to
|
|
||||||
// it.
|
|
||||||
llvm::BasicBlock *LoopHeader = new llvm::BasicBlock("whilecond");
|
|
||||||
EmitBlock(LoopHeader);
|
|
||||||
|
|
||||||
// Evaluate the conditional in the while header. C99 6.8.5.1: The evaluation
|
|
||||||
// of the controlling expression takes place before each execution of the loop
|
|
||||||
// body.
|
|
||||||
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
|
|
||||||
|
|
||||||
// TODO: while(1) is common, avoid extra exit blocks, etc. Be sure
|
|
||||||
// to correctly handle break/continue though.
|
|
||||||
|
|
||||||
// Create an exit block for when the condition fails, create a block for the
|
|
||||||
// body of the loop.
|
|
||||||
llvm::BasicBlock *ExitBlock = new llvm::BasicBlock("whileexit");
|
|
||||||
llvm::BasicBlock *LoopBody = new llvm::BasicBlock("whilebody");
|
|
||||||
|
|
||||||
// As long as the condition is true, go to the loop body.
|
|
||||||
Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock);
|
|
||||||
|
|
||||||
// Store the blocks to use for break and continue.
|
|
||||||
BreakContinueStack.push_back(BreakContinue(ExitBlock, LoopHeader));
|
|
||||||
|
|
||||||
// Emit the loop body.
|
|
||||||
EmitBlock(LoopBody);
|
|
||||||
EmitStmt(S.getBody());
|
|
||||||
|
|
||||||
BreakContinueStack.pop_back();
|
|
||||||
|
|
||||||
// Cycle to the condition.
|
|
||||||
Builder.CreateBr(LoopHeader);
|
|
||||||
|
|
||||||
// Emit the exit block.
|
|
||||||
EmitBlock(ExitBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
|
|
||||||
// TODO: "do {} while (0)" is common in macros, avoid extra blocks. Be sure
|
|
||||||
// to correctly handle break/continue though.
|
|
||||||
|
|
||||||
// Emit the body for the loop, insert it, which will create an uncond br to
|
|
||||||
// it.
|
|
||||||
llvm::BasicBlock *LoopBody = new llvm::BasicBlock("dobody");
|
|
||||||
llvm::BasicBlock *AfterDo = new llvm::BasicBlock("afterdo");
|
|
||||||
EmitBlock(LoopBody);
|
|
||||||
|
|
||||||
llvm::BasicBlock *DoCond = new llvm::BasicBlock("docond");
|
|
||||||
|
|
||||||
// Store the blocks to use for break and continue.
|
|
||||||
BreakContinueStack.push_back(BreakContinue(AfterDo, DoCond));
|
|
||||||
|
|
||||||
// Emit the body of the loop into the block.
|
|
||||||
EmitStmt(S.getBody());
|
|
||||||
|
|
||||||
BreakContinueStack.pop_back();
|
|
||||||
|
|
||||||
EmitBlock(DoCond);
|
|
||||||
|
|
||||||
// C99 6.8.5.2: "The evaluation of the controlling expression takes place
|
|
||||||
// after each execution of the loop body."
|
|
||||||
|
|
||||||
// Evaluate the conditional in the while header.
|
|
||||||
// C99 6.8.5p2/p4: The first substatement is executed if the expression
|
|
||||||
// compares unequal to 0. The condition must be a scalar type.
|
|
||||||
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
|
|
||||||
|
|
||||||
// As long as the condition is true, iterate the loop.
|
|
||||||
Builder.CreateCondBr(BoolCondVal, LoopBody, AfterDo);
|
|
||||||
|
|
||||||
// Emit the exit block.
|
|
||||||
EmitBlock(AfterDo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitForStmt(const ForStmt &S) {
|
|
||||||
// FIXME: What do we do if the increment (f.e.) contains a stmt expression,
|
|
||||||
// which contains a continue/break?
|
|
||||||
// TODO: We could keep track of whether the loop body contains any
|
|
||||||
// break/continue statements and not create unnecessary blocks (like
|
|
||||||
// "afterfor" for a condless loop) if it doesn't.
|
|
||||||
|
|
||||||
// Evaluate the first part before the loop.
|
|
||||||
if (S.getInit())
|
|
||||||
EmitStmt(S.getInit());
|
|
||||||
|
|
||||||
// Start the loop with a block that tests the condition.
|
|
||||||
llvm::BasicBlock *CondBlock = new llvm::BasicBlock("forcond");
|
|
||||||
llvm::BasicBlock *AfterFor = new llvm::BasicBlock("afterfor");
|
|
||||||
|
|
||||||
EmitBlock(CondBlock);
|
|
||||||
|
|
||||||
// Evaluate the condition if present. If not, treat it as a non-zero-constant
|
|
||||||
// according to 6.8.5.3p2, aka, true.
|
|
||||||
if (S.getCond()) {
|
|
||||||
// C99 6.8.5p2/p4: The first substatement is executed if the expression
|
|
||||||
// compares unequal to 0. The condition must be a scalar type.
|
|
||||||
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
|
|
||||||
|
|
||||||
// As long as the condition is true, iterate the loop.
|
|
||||||
llvm::BasicBlock *ForBody = new llvm::BasicBlock("forbody");
|
|
||||||
Builder.CreateCondBr(BoolCondVal, ForBody, AfterFor);
|
|
||||||
EmitBlock(ForBody);
|
|
||||||
} else {
|
|
||||||
// Treat it as a non-zero constant. Don't even create a new block for the
|
|
||||||
// body, just fall into it.
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the for loop doesn't have an increment we can just use the
|
|
||||||
// condition as the continue block.
|
|
||||||
llvm::BasicBlock *ContinueBlock;
|
|
||||||
if (S.getInc())
|
|
||||||
ContinueBlock = new llvm::BasicBlock("forinc");
|
|
||||||
else
|
|
||||||
ContinueBlock = CondBlock;
|
|
||||||
|
|
||||||
// Store the blocks to use for break and continue.
|
|
||||||
BreakContinueStack.push_back(BreakContinue(AfterFor, ContinueBlock));
|
|
||||||
|
|
||||||
// If the condition is true, execute the body of the for stmt.
|
|
||||||
EmitStmt(S.getBody());
|
|
||||||
|
|
||||||
BreakContinueStack.pop_back();
|
|
||||||
|
|
||||||
if (S.getInc())
|
|
||||||
EmitBlock(ContinueBlock);
|
|
||||||
|
|
||||||
// If there is an increment, emit it next.
|
|
||||||
if (S.getInc())
|
|
||||||
EmitStmt(S.getInc());
|
|
||||||
|
|
||||||
// Finally, branch back up to the condition for the next iteration.
|
|
||||||
Builder.CreateBr(CondBlock);
|
|
||||||
|
|
||||||
// Emit the fall-through block.
|
|
||||||
EmitBlock(AfterFor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitReturnStmt - Note that due to GCC extensions, this can have an operand
|
|
||||||
/// if the function returns void, or may be missing one if the function returns
|
|
||||||
/// non-void. Fun stuff :).
|
|
||||||
void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
|
|
||||||
// Emit the result value, even if unused, to evalute the side effects.
|
|
||||||
const Expr *RV = S.getRetValue();
|
|
||||||
|
|
||||||
QualType FnRetTy = CurFuncDecl->getType().getCanonicalType();
|
|
||||||
FnRetTy = cast<FunctionType>(FnRetTy)->getResultType();
|
|
||||||
|
|
||||||
if (FnRetTy->isVoidType()) {
|
|
||||||
// If the function returns void, emit ret void.
|
|
||||||
Builder.CreateRetVoid();
|
|
||||||
} else if (RV == 0) {
|
|
||||||
// Handle "return;" in a function that returns a value.
|
|
||||||
const llvm::Type *RetTy = CurFn->getFunctionType()->getReturnType();
|
|
||||||
if (RetTy == llvm::Type::VoidTy)
|
|
||||||
Builder.CreateRetVoid(); // struct return etc.
|
|
||||||
else
|
|
||||||
Builder.CreateRet(llvm::UndefValue::get(RetTy));
|
|
||||||
} else if (!hasAggregateLLVMType(RV->getType())) {
|
|
||||||
Builder.CreateRet(EmitScalarExpr(RV));
|
|
||||||
} else if (RV->getType()->isComplexType()) {
|
|
||||||
llvm::Value *SRetPtr = CurFn->arg_begin();
|
|
||||||
EmitComplexExprIntoAddr(RV, SRetPtr, false);
|
|
||||||
} else {
|
|
||||||
llvm::Value *SRetPtr = CurFn->arg_begin();
|
|
||||||
EmitAggExpr(RV, SRetPtr, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit a block after the branch so that dead code after a return has some
|
|
||||||
// place to go.
|
|
||||||
EmitBlock(new llvm::BasicBlock());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
|
|
||||||
for (const Decl *Decl = S.getDecl(); Decl; Decl = Decl->getNextDeclarator())
|
|
||||||
EmitDecl(*Decl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitBreakStmt() {
|
|
||||||
assert(!BreakContinueStack.empty() && "break stmt not in a loop or switch!");
|
|
||||||
|
|
||||||
llvm::BasicBlock *Block = BreakContinueStack.back().BreakBlock;
|
|
||||||
Builder.CreateBr(Block);
|
|
||||||
EmitBlock(new llvm::BasicBlock());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenFunction::EmitContinueStmt() {
|
|
||||||
assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
|
|
||||||
|
|
||||||
llvm::BasicBlock *Block = BreakContinueStack.back().ContinueBlock;
|
|
||||||
Builder.CreateBr(Block);
|
|
||||||
EmitBlock(new llvm::BasicBlock());
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
//===--- CodeGenFunction.cpp - Emit LLVM Code from ASTs for a Function ----===//
|
|
||||||
//
|
|
||||||
// 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 coordinates the per-function state used while generating code.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "CodeGenFunction.h"
|
|
||||||
#include "CodeGenModule.h"
|
|
||||||
#include "clang/Basic/TargetInfo.h"
|
|
||||||
#include "clang/AST/AST.h"
|
|
||||||
#include "llvm/Constants.h"
|
|
||||||
#include "llvm/DerivedTypes.h"
|
|
||||||
#include "llvm/Function.h"
|
|
||||||
#include "llvm/Analysis/Verifier.h"
|
|
||||||
using namespace clang;
|
|
||||||
using namespace CodeGen;
|
|
||||||
|
|
||||||
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
|
|
||||||
: CGM(cgm), Target(CGM.getContext().Target) {}
|
|
||||||
|
|
||||||
ASTContext &CodeGenFunction::getContext() const {
|
|
||||||
return CGM.getContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
llvm::BasicBlock *CodeGenFunction::getBasicBlockForLabel(const LabelStmt *S) {
|
|
||||||
llvm::BasicBlock *&BB = LabelMap[S];
|
|
||||||
if (BB) return BB;
|
|
||||||
|
|
||||||
// Create, but don't insert, the new block.
|
|
||||||
return BB = new llvm::BasicBlock(S->getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const llvm::Type *CodeGenFunction::ConvertType(QualType T) {
|
|
||||||
return CGM.getTypes().ConvertType(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CodeGenFunction::hasAggregateLLVMType(QualType T) {
|
|
||||||
return !T->isRealType() && !T->isPointerType() && !T->isVoidType() &&
|
|
||||||
!T->isVectorType() && !T->isFunctionType();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CodeGenFunction::GenerateCode(const FunctionDecl *FD) {
|
|
||||||
LLVMIntTy = ConvertType(getContext().IntTy);
|
|
||||||
LLVMPointerWidth = static_cast<unsigned>(
|
|
||||||
getContext().getTypeSize(getContext().getPointerType(getContext().VoidTy),
|
|
||||||
SourceLocation()));
|
|
||||||
|
|
||||||
CurFn = cast<llvm::Function>(CGM.GetAddrOfGlobalDecl(FD));
|
|
||||||
CurFuncDecl = FD;
|
|
||||||
|
|
||||||
// TODO: Set up linkage and many other things.
|
|
||||||
assert(CurFn->isDeclaration() && "Function already has body?");
|
|
||||||
|
|
||||||
llvm::BasicBlock *EntryBB = new llvm::BasicBlock("entry", CurFn);
|
|
||||||
|
|
||||||
Builder.SetInsertPoint(EntryBB);
|
|
||||||
|
|
||||||
// Create a marker to make it easy to insert allocas into the entryblock
|
|
||||||
// later.
|
|
||||||
llvm::Value *Undef = llvm::UndefValue::get(llvm::Type::Int32Ty);
|
|
||||||
AllocaInsertPt = Builder.CreateBitCast(Undef,llvm::Type::Int32Ty, "allocapt");
|
|
||||||
|
|
||||||
// Emit allocs for param decls. Give the LLVM Argument nodes names.
|
|
||||||
llvm::Function::arg_iterator AI = CurFn->arg_begin();
|
|
||||||
|
|
||||||
// Name the struct return argument.
|
|
||||||
if (hasAggregateLLVMType(FD->getResultType())) {
|
|
||||||
AI->setName("agg.result");
|
|
||||||
++AI;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i, ++AI) {
|
|
||||||
assert(AI != CurFn->arg_end() && "Argument mismatch!");
|
|
||||||
EmitParmDecl(*FD->getParamDecl(i), AI);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit the function body.
|
|
||||||
EmitStmt(FD->getBody());
|
|
||||||
|
|
||||||
// Emit a return for code that falls off the end.
|
|
||||||
// FIXME: if this is C++ main, this should return 0.
|
|
||||||
if (CurFn->getReturnType() == llvm::Type::VoidTy)
|
|
||||||
Builder.CreateRetVoid();
|
|
||||||
else
|
|
||||||
Builder.CreateRet(llvm::UndefValue::get(CurFn->getReturnType()));
|
|
||||||
|
|
||||||
assert(BreakContinueStack.empty() &&
|
|
||||||
"mismatched push/pop in break/continue stack!");
|
|
||||||
|
|
||||||
// Verify that the function is well formed.
|
|
||||||
assert(!verifyFunction(*CurFn));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,401 +0,0 @@
|
|||||||
//===--- CodeGenFunction.h - Per-Function state for LLVM CodeGen ----------===//
|
|
||||||
//
|
|
||||||
// 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 is the internal per-function state used for llvm translation.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef CODEGEN_CODEGENFUNCTION_H
|
|
||||||
#define CODEGEN_CODEGENFUNCTION_H
|
|
||||||
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
|
||||||
#include "llvm/ADT/SmallVector.h"
|
|
||||||
#include "llvm/Support/LLVMBuilder.h"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
class Module;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace clang {
|
|
||||||
class ASTContext;
|
|
||||||
class Decl;
|
|
||||||
class FunctionDecl;
|
|
||||||
class TargetInfo;
|
|
||||||
class QualType;
|
|
||||||
class FunctionTypeProto;
|
|
||||||
|
|
||||||
class Stmt;
|
|
||||||
class CompoundStmt;
|
|
||||||
class LabelStmt;
|
|
||||||
class GotoStmt;
|
|
||||||
class IfStmt;
|
|
||||||
class WhileStmt;
|
|
||||||
class DoStmt;
|
|
||||||
class ForStmt;
|
|
||||||
class ReturnStmt;
|
|
||||||
class DeclStmt;
|
|
||||||
|
|
||||||
class Expr;
|
|
||||||
class DeclRefExpr;
|
|
||||||
class StringLiteral;
|
|
||||||
class IntegerLiteral;
|
|
||||||
class FloatingLiteral;
|
|
||||||
class CharacterLiteral;
|
|
||||||
class TypesCompatibleExpr;
|
|
||||||
|
|
||||||
class ImplicitCastExpr;
|
|
||||||
class CastExpr;
|
|
||||||
class CallExpr;
|
|
||||||
class UnaryOperator;
|
|
||||||
class BinaryOperator;
|
|
||||||
class CompoundAssignOperator;
|
|
||||||
class ArraySubscriptExpr;
|
|
||||||
class OCUVectorElementExpr;
|
|
||||||
class ConditionalOperator;
|
|
||||||
class ChooseExpr;
|
|
||||||
class PreDefinedExpr;
|
|
||||||
class ObjCStringLiteral;
|
|
||||||
|
|
||||||
class BlockVarDecl;
|
|
||||||
class EnumConstantDecl;
|
|
||||||
class ParmVarDecl;
|
|
||||||
namespace CodeGen {
|
|
||||||
class CodeGenModule;
|
|
||||||
|
|
||||||
|
|
||||||
/// RValue - This trivial value class is used to represent the result of an
|
|
||||||
/// expression that is evaluated. It can be one of three things: either a
|
|
||||||
/// simple LLVM SSA value, a pair of SSA values for complex numbers, or the
|
|
||||||
/// address of an aggregate value in memory.
|
|
||||||
class RValue {
|
|
||||||
llvm::Value *V1, *V2;
|
|
||||||
// TODO: Encode this into the low bit of pointer for more efficient
|
|
||||||
// return-by-value.
|
|
||||||
enum { Scalar, Complex, Aggregate } Flavor;
|
|
||||||
|
|
||||||
// FIXME: Aggregate rvalues need to retain information about whether they are
|
|
||||||
// volatile or not.
|
|
||||||
public:
|
|
||||||
|
|
||||||
bool isScalar() const { return Flavor == Scalar; }
|
|
||||||
bool isComplex() const { return Flavor == Complex; }
|
|
||||||
bool isAggregate() const { return Flavor == Aggregate; }
|
|
||||||
|
|
||||||
/// getScalar() - Return the Value* of this scalar value.
|
|
||||||
llvm::Value *getScalarVal() const {
|
|
||||||
assert(isScalar() && "Not a scalar!");
|
|
||||||
return V1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getComplexVal - Return the real/imag components of this complex value.
|
|
||||||
///
|
|
||||||
std::pair<llvm::Value *, llvm::Value *> getComplexVal() const {
|
|
||||||
return std::pair<llvm::Value *, llvm::Value *>(V1, V2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getAggregateAddr() - Return the Value* of the address of the aggregate.
|
|
||||||
llvm::Value *getAggregateAddr() const {
|
|
||||||
assert(isAggregate() && "Not an aggregate!");
|
|
||||||
return V1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static RValue get(llvm::Value *V) {
|
|
||||||
RValue ER;
|
|
||||||
ER.V1 = V;
|
|
||||||
ER.Flavor = Scalar;
|
|
||||||
return ER;
|
|
||||||
}
|
|
||||||
static RValue getComplex(llvm::Value *V1, llvm::Value *V2) {
|
|
||||||
RValue ER;
|
|
||||||
ER.V1 = V1;
|
|
||||||
ER.V2 = V2;
|
|
||||||
ER.Flavor = Complex;
|
|
||||||
return ER;
|
|
||||||
}
|
|
||||||
static RValue getComplex(const std::pair<llvm::Value *, llvm::Value *> &C) {
|
|
||||||
RValue ER;
|
|
||||||
ER.V1 = C.first;
|
|
||||||
ER.V2 = C.second;
|
|
||||||
ER.Flavor = Complex;
|
|
||||||
return ER;
|
|
||||||
}
|
|
||||||
static RValue getAggregate(llvm::Value *V) {
|
|
||||||
RValue ER;
|
|
||||||
ER.V1 = V;
|
|
||||||
ER.Flavor = Aggregate;
|
|
||||||
return ER;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// LValue - This represents an lvalue references. Because C/C++ allow
|
|
||||||
/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
|
|
||||||
/// bitrange.
|
|
||||||
class LValue {
|
|
||||||
// FIXME: Volatility. Restrict?
|
|
||||||
// alignment?
|
|
||||||
|
|
||||||
enum {
|
|
||||||
Simple, // This is a normal l-value, use getAddress().
|
|
||||||
VectorElt, // This is a vector element l-value (V[i]), use getVector*
|
|
||||||
BitField, // This is a bitfield l-value, use getBitfield*.
|
|
||||||
OCUVectorElt // This is an ocu vector subset, use getOCUVectorComp
|
|
||||||
} LVType;
|
|
||||||
|
|
||||||
llvm::Value *V;
|
|
||||||
|
|
||||||
union {
|
|
||||||
llvm::Value *VectorIdx; // Index into a vector subscript: V[i]
|
|
||||||
unsigned VectorElts; // Encoded OCUVector element subset: V.xyx
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
bool isSimple() const { return LVType == Simple; }
|
|
||||||
bool isVectorElt() const { return LVType == VectorElt; }
|
|
||||||
bool isBitfield() const { return LVType == BitField; }
|
|
||||||
bool isOCUVectorElt() const { return LVType == OCUVectorElt; }
|
|
||||||
|
|
||||||
// simple lvalue
|
|
||||||
llvm::Value *getAddress() const { assert(isSimple()); return V; }
|
|
||||||
// vector elt lvalue
|
|
||||||
llvm::Value *getVectorAddr() const { assert(isVectorElt()); return V; }
|
|
||||||
llvm::Value *getVectorIdx() const { assert(isVectorElt()); return VectorIdx; }
|
|
||||||
// ocu vector elements.
|
|
||||||
llvm::Value *getOCUVectorAddr() const { assert(isOCUVectorElt()); return V; }
|
|
||||||
unsigned getOCUVectorElts() const {
|
|
||||||
assert(isOCUVectorElt());
|
|
||||||
return VectorElts;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static LValue MakeAddr(llvm::Value *V) {
|
|
||||||
LValue R;
|
|
||||||
R.LVType = Simple;
|
|
||||||
R.V = V;
|
|
||||||
return R;
|
|
||||||
}
|
|
||||||
|
|
||||||
static LValue MakeVectorElt(llvm::Value *Vec, llvm::Value *Idx) {
|
|
||||||
LValue R;
|
|
||||||
R.LVType = VectorElt;
|
|
||||||
R.V = Vec;
|
|
||||||
R.VectorIdx = Idx;
|
|
||||||
return R;
|
|
||||||
}
|
|
||||||
|
|
||||||
static LValue MakeOCUVectorElt(llvm::Value *Vec, unsigned Elements) {
|
|
||||||
LValue R;
|
|
||||||
R.LVType = OCUVectorElt;
|
|
||||||
R.V = Vec;
|
|
||||||
R.VectorElts = Elements;
|
|
||||||
return R;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// CodeGenFunction - This class organizes the per-function state that is used
|
|
||||||
/// while generating LLVM code.
|
|
||||||
class CodeGenFunction {
|
|
||||||
public:
|
|
||||||
CodeGenModule &CGM; // Per-module state.
|
|
||||||
TargetInfo &Target;
|
|
||||||
|
|
||||||
typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy;
|
|
||||||
llvm::LLVMBuilder Builder;
|
|
||||||
|
|
||||||
const FunctionDecl *CurFuncDecl;
|
|
||||||
llvm::Function *CurFn;
|
|
||||||
|
|
||||||
/// AllocaInsertPoint - This is an instruction in the entry block before which
|
|
||||||
/// we prefer to insert allocas.
|
|
||||||
llvm::Instruction *AllocaInsertPt;
|
|
||||||
|
|
||||||
const llvm::Type *LLVMIntTy;
|
|
||||||
unsigned LLVMPointerWidth;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C
|
|
||||||
/// decls.
|
|
||||||
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
|
|
||||||
|
|
||||||
/// LabelMap - This keeps track of the LLVM basic block for each C label.
|
|
||||||
llvm::DenseMap<const LabelStmt*, llvm::BasicBlock*> LabelMap;
|
|
||||||
|
|
||||||
// BreakContinueStack - This keeps track of where break and continue
|
|
||||||
// statements should jump to.
|
|
||||||
struct BreakContinue {
|
|
||||||
BreakContinue(llvm::BasicBlock *bb, llvm::BasicBlock *cb)
|
|
||||||
: BreakBlock(bb), ContinueBlock(cb) {}
|
|
||||||
|
|
||||||
llvm::BasicBlock *BreakBlock;
|
|
||||||
llvm::BasicBlock *ContinueBlock;
|
|
||||||
};
|
|
||||||
llvm::SmallVector<BreakContinue, 8> BreakContinueStack;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CodeGenFunction(CodeGenModule &cgm);
|
|
||||||
|
|
||||||
ASTContext &getContext() const;
|
|
||||||
|
|
||||||
void GenerateCode(const FunctionDecl *FD);
|
|
||||||
|
|
||||||
const llvm::Type *ConvertType(QualType T);
|
|
||||||
|
|
||||||
/// hasAggregateLLVMType - Return true if the specified AST type will map into
|
|
||||||
/// an aggregate LLVM type or is void.
|
|
||||||
static bool hasAggregateLLVMType(QualType T);
|
|
||||||
|
|
||||||
/// getBasicBlockForLabel - Return the LLVM basicblock that the specified
|
|
||||||
/// label maps to.
|
|
||||||
llvm::BasicBlock *getBasicBlockForLabel(const LabelStmt *S);
|
|
||||||
|
|
||||||
|
|
||||||
void EmitBlock(llvm::BasicBlock *BB);
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Helpers
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
|
|
||||||
/// block.
|
|
||||||
llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty,
|
|
||||||
const char *Name = "tmp");
|
|
||||||
|
|
||||||
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
|
|
||||||
/// expression and compare the result against zero, returning an Int1Ty value.
|
|
||||||
llvm::Value *EvaluateExprAsBool(const Expr *E);
|
|
||||||
|
|
||||||
/// EmitAnyExpr - Emit code to compute the specified expression which can have
|
|
||||||
/// any type. The result is returned as an RValue struct. If this is an
|
|
||||||
/// aggregate expression, the aggloc/agglocvolatile arguments indicate where
|
|
||||||
/// the result should be returned.
|
|
||||||
RValue EmitAnyExpr(const Expr *E, llvm::Value *AggLoc = 0,
|
|
||||||
bool isAggLocVolatile = false);
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Declaration Emission
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void EmitDecl(const Decl &D);
|
|
||||||
void EmitEnumConstantDecl(const EnumConstantDecl &D);
|
|
||||||
void EmitBlockVarDecl(const BlockVarDecl &D);
|
|
||||||
void EmitLocalBlockVarDecl(const BlockVarDecl &D);
|
|
||||||
void EmitParmDecl(const ParmVarDecl &D, llvm::Value *Arg);
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Statement Emission
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void EmitStmt(const Stmt *S);
|
|
||||||
RValue EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false,
|
|
||||||
llvm::Value *AggLoc = 0, bool isAggVol = false);
|
|
||||||
void EmitLabelStmt(const LabelStmt &S);
|
|
||||||
void EmitGotoStmt(const GotoStmt &S);
|
|
||||||
void EmitIfStmt(const IfStmt &S);
|
|
||||||
void EmitWhileStmt(const WhileStmt &S);
|
|
||||||
void EmitDoStmt(const DoStmt &S);
|
|
||||||
void EmitForStmt(const ForStmt &S);
|
|
||||||
void EmitReturnStmt(const ReturnStmt &S);
|
|
||||||
void EmitDeclStmt(const DeclStmt &S);
|
|
||||||
void EmitBreakStmt();
|
|
||||||
void EmitContinueStmt();
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// LValue Expression Emission
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// EmitLValue - Emit code to compute a designator that specifies the location
|
|
||||||
/// of the expression.
|
|
||||||
///
|
|
||||||
/// This can return one of two things: a simple address or a bitfield
|
|
||||||
/// reference. In either case, the LLVM Value* in the LValue structure is
|
|
||||||
/// guaranteed to be an LLVM pointer type.
|
|
||||||
///
|
|
||||||
/// If this returns a bitfield reference, nothing about the pointee type of
|
|
||||||
/// the LLVM value is known: For example, it may not be a pointer to an
|
|
||||||
/// integer.
|
|
||||||
///
|
|
||||||
/// If this returns a normal address, and if the lvalue's C type is fixed
|
|
||||||
/// size, this method guarantees that the returned pointer type will point to
|
|
||||||
/// an LLVM type of the same size of the lvalue's type. If the lvalue has a
|
|
||||||
/// variable length type, this is not possible.
|
|
||||||
///
|
|
||||||
LValue EmitLValue(const Expr *E);
|
|
||||||
|
|
||||||
/// EmitLoadOfLValue - Given an expression that represents a value lvalue,
|
|
||||||
/// this method emits the address of the lvalue, then loads the result as an
|
|
||||||
/// rvalue, returning the rvalue.
|
|
||||||
RValue EmitLoadOfLValue(LValue V, QualType LVType);
|
|
||||||
RValue EmitLoadOfOCUElementLValue(LValue V, QualType LVType);
|
|
||||||
|
|
||||||
|
|
||||||
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
|
|
||||||
/// lvalue, where both are guaranteed to the have the same type, and that type
|
|
||||||
/// is 'Ty'.
|
|
||||||
void EmitStoreThroughLValue(RValue Src, LValue Dst, QualType Ty);
|
|
||||||
void EmitStoreThroughOCUComponentLValue(RValue Src, LValue Dst, QualType Ty);
|
|
||||||
|
|
||||||
LValue EmitDeclRefLValue(const DeclRefExpr *E);
|
|
||||||
LValue EmitStringLiteralLValue(const StringLiteral *E);
|
|
||||||
LValue EmitPreDefinedLValue(const PreDefinedExpr *E);
|
|
||||||
LValue EmitUnaryOpLValue(const UnaryOperator *E);
|
|
||||||
LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E);
|
|
||||||
LValue EmitOCUVectorElementExpr(const OCUVectorElementExpr *E);
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Scalar Expression Emission
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
RValue EmitCallExpr(const CallExpr *E);
|
|
||||||
RValue EmitCallExpr(llvm::Value *Callee, const CallExpr *E);
|
|
||||||
RValue EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
|
|
||||||
|
|
||||||
llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Expression Emission
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// Expressions are broken into three classes: scalar, complex, aggregate.
|
|
||||||
|
|
||||||
/// EmitScalarExpr - Emit the computation of the specified expression of
|
|
||||||
/// LLVM scalar type, returning the result.
|
|
||||||
llvm::Value *EmitScalarExpr(const Expr *E);
|
|
||||||
|
|
||||||
/// EmitScalarConversion - Emit a conversion from the specified type to the
|
|
||||||
/// specified destination type, both of which are LLVM scalar types.
|
|
||||||
llvm::Value *EmitScalarConversion(llvm::Value *Src, QualType SrcTy,
|
|
||||||
QualType DstTy);
|
|
||||||
|
|
||||||
/// EmitComplexToScalarConversion - Emit a conversion from the specified
|
|
||||||
/// complex type to the specified destination type, where the destination
|
|
||||||
/// type is an LLVM scalar type.
|
|
||||||
llvm::Value *EmitComplexToScalarConversion(ComplexPairTy Src, QualType SrcTy,
|
|
||||||
QualType DstTy);
|
|
||||||
|
|
||||||
|
|
||||||
/// EmitAggExpr - Emit the computation of the specified expression of
|
|
||||||
/// aggregate type. The result is computed into DestPtr. Note that if
|
|
||||||
/// DestPtr is null, the value of the aggregate expression is not needed.
|
|
||||||
void EmitAggExpr(const Expr *E, llvm::Value *DestPtr, bool VolatileDest);
|
|
||||||
|
|
||||||
/// EmitComplexExpr - Emit the computation of the specified expression of
|
|
||||||
/// complex type, returning the result.
|
|
||||||
ComplexPairTy EmitComplexExpr(const Expr *E);
|
|
||||||
|
|
||||||
/// EmitComplexExprIntoAddr - Emit the computation of the specified expression
|
|
||||||
/// of complex type, storing into the specified Value*.
|
|
||||||
void EmitComplexExprIntoAddr(const Expr *E, llvm::Value *DestAddr,
|
|
||||||
bool DestIsVolatile);
|
|
||||||
/// LoadComplexFromAddr - Load a complex number from the specified address.
|
|
||||||
ComplexPairTy LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile);
|
|
||||||
};
|
|
||||||
} // end namespace CodeGen
|
|
||||||
} // end namespace clang
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
//===--- CodeGenModule.cpp - Emit LLVM Code from ASTs for a Module --------===//
|
|
||||||
//
|
|
||||||
// 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 coordinates the per-module state used while generating code.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "CodeGenModule.h"
|
|
||||||
#include "CodeGenFunction.h"
|
|
||||||
#include "clang/AST/ASTContext.h"
|
|
||||||
#include "clang/AST/Decl.h"
|
|
||||||
#include "clang/Basic/TargetInfo.h"
|
|
||||||
#include "llvm/Constants.h"
|
|
||||||
#include "llvm/DerivedTypes.h"
|
|
||||||
#include "llvm/Module.h"
|
|
||||||
#include "llvm/Intrinsics.h"
|
|
||||||
using namespace clang;
|
|
||||||
using namespace CodeGen;
|
|
||||||
|
|
||||||
|
|
||||||
CodeGenModule::CodeGenModule(ASTContext &C, llvm::Module &M)
|
|
||||||
: Context(C), TheModule(M), Types(C, M), CFConstantStringClassRef(0) {}
|
|
||||||
|
|
||||||
llvm::Constant *CodeGenModule::GetAddrOfGlobalDecl(const Decl *D) {
|
|
||||||
// See if it is already in the map.
|
|
||||||
llvm::Constant *&Entry = GlobalDeclMap[D];
|
|
||||||
if (Entry) return Entry;
|
|
||||||
|
|
||||||
QualType ASTTy = cast<ValueDecl>(D)->getType();
|
|
||||||
const llvm::Type *Ty = getTypes().ConvertType(ASTTy);
|
|
||||||
if (isa<FunctionDecl>(D)) {
|
|
||||||
const llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
|
|
||||||
// FIXME: param attributes for sext/zext etc.
|
|
||||||
return Entry = new llvm::Function(FTy, llvm::Function::ExternalLinkage,
|
|
||||||
D->getName(), &getModule());
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(isa<FileVarDecl>(D) && "Unknown global decl!");
|
|
||||||
|
|
||||||
return Entry = new llvm::GlobalVariable(Ty, false,
|
|
||||||
llvm::GlobalValue::ExternalLinkage,
|
|
||||||
0, D->getName(), &getModule());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenModule::EmitFunction(const FunctionDecl *FD) {
|
|
||||||
// If this is not a prototype, emit the body.
|
|
||||||
if (FD->getBody())
|
|
||||||
CodeGenFunction(*this).GenerateCode(FD);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenModule::EmitGlobalVar(const FileVarDecl *D) {
|
|
||||||
llvm::GlobalVariable *GV = cast<llvm::GlobalVariable>(GetAddrOfGlobalDecl(D));
|
|
||||||
|
|
||||||
// If the storage class is external and there is no initializer, just leave it
|
|
||||||
// as a declaration.
|
|
||||||
if (D->getStorageClass() == VarDecl::Extern && D->getInit() == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Otherwise, convert the initializer, or use zero if appropriate.
|
|
||||||
llvm::Constant *Init = 0;
|
|
||||||
if (D->getInit() == 0) {
|
|
||||||
Init = llvm::Constant::getNullValue(GV->getType()->getElementType());
|
|
||||||
} else if (D->getType()->isIntegerType()) {
|
|
||||||
llvm::APSInt Value(static_cast<unsigned>(
|
|
||||||
getContext().getTypeSize(D->getInit()->getType(), SourceLocation())));
|
|
||||||
if (D->getInit()->isIntegerConstantExpr(Value, Context))
|
|
||||||
Init = llvm::ConstantInt::get(Value);
|
|
||||||
}
|
|
||||||
assert(Init && "FIXME: Global variable initializers unimp!");
|
|
||||||
|
|
||||||
GV->setInitializer(Init);
|
|
||||||
|
|
||||||
// Set the llvm linkage type as appropriate.
|
|
||||||
// FIXME: This isn't right. This should handle common linkage and other
|
|
||||||
// stuff.
|
|
||||||
switch (D->getStorageClass()) {
|
|
||||||
case VarDecl::Auto:
|
|
||||||
case VarDecl::Register:
|
|
||||||
assert(0 && "Can't have auto or register globals");
|
|
||||||
case VarDecl::None:
|
|
||||||
case VarDecl::Extern:
|
|
||||||
// todo: common
|
|
||||||
break;
|
|
||||||
case VarDecl::Static:
|
|
||||||
GV->setLinkage(llvm::GlobalVariable::InternalLinkage);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EmitGlobalVarDeclarator - Emit all the global vars attached to the specified
|
|
||||||
/// declarator chain.
|
|
||||||
void CodeGenModule::EmitGlobalVarDeclarator(const FileVarDecl *D) {
|
|
||||||
for (; D; D = cast_or_null<FileVarDecl>(D->getNextDeclarator()))
|
|
||||||
EmitGlobalVar(D);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getBuiltinLibFunction
|
|
||||||
llvm::Function *CodeGenModule::getBuiltinLibFunction(unsigned BuiltinID) {
|
|
||||||
if (BuiltinFunctions.size() <= BuiltinID)
|
|
||||||
BuiltinFunctions.resize(BuiltinID);
|
|
||||||
|
|
||||||
// Already available?
|
|
||||||
llvm::Function *&FunctionSlot = BuiltinFunctions[BuiltinID];
|
|
||||||
if (FunctionSlot)
|
|
||||||
return FunctionSlot;
|
|
||||||
|
|
||||||
assert(Context.BuiltinInfo.isLibFunction(BuiltinID) && "isn't a lib fn");
|
|
||||||
|
|
||||||
// Get the name, skip over the __builtin_ prefix.
|
|
||||||
const char *Name = Context.BuiltinInfo.GetName(BuiltinID)+10;
|
|
||||||
|
|
||||||
// Get the type for the builtin.
|
|
||||||
QualType Type = Context.BuiltinInfo.GetBuiltinType(BuiltinID, Context);
|
|
||||||
const llvm::FunctionType *Ty =
|
|
||||||
cast<llvm::FunctionType>(getTypes().ConvertType(Type));
|
|
||||||
|
|
||||||
// FIXME: This has a serious problem with code like this:
|
|
||||||
// void abs() {}
|
|
||||||
// ... __builtin_abs(x);
|
|
||||||
// The two versions of abs will collide. The fix is for the builtin to win,
|
|
||||||
// and for the existing one to be turned into a constantexpr cast of the
|
|
||||||
// builtin. In the case where the existing one is a static function, it
|
|
||||||
// should just be renamed.
|
|
||||||
if (llvm::Function *Existing = getModule().getFunction(Name)) {
|
|
||||||
if (Existing->getFunctionType() == Ty && Existing->hasExternalLinkage())
|
|
||||||
return FunctionSlot = Existing;
|
|
||||||
assert(Existing == 0 && "FIXME: Name collision");
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: param attributes for sext/zext etc.
|
|
||||||
return FunctionSlot = new llvm::Function(Ty, llvm::Function::ExternalLinkage,
|
|
||||||
Name, &getModule());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
llvm::Function *CodeGenModule::getMemCpyFn() {
|
|
||||||
if (MemCpyFn) return MemCpyFn;
|
|
||||||
llvm::Intrinsic::ID IID;
|
|
||||||
uint64_t Size; unsigned Align;
|
|
||||||
Context.Target.getPointerInfo(Size, Align, SourceLocation());
|
|
||||||
switch (Size) {
|
|
||||||
default: assert(0 && "Unknown ptr width");
|
|
||||||
case 32: IID = llvm::Intrinsic::memcpy_i32; break;
|
|
||||||
case 64: IID = llvm::Intrinsic::memcpy_i64; break;
|
|
||||||
}
|
|
||||||
return MemCpyFn = llvm::Intrinsic::getDeclaration(&TheModule, IID);
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Constant *CodeGenModule::
|
|
||||||
GetAddrOfConstantCFString(const std::string &str) {
|
|
||||||
llvm::StringMapEntry<llvm::Constant *> &Entry =
|
|
||||||
CFConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]);
|
|
||||||
|
|
||||||
if (Entry.getValue())
|
|
||||||
return Entry.getValue();
|
|
||||||
|
|
||||||
std::vector<llvm::Constant*> Fields;
|
|
||||||
|
|
||||||
if (!CFConstantStringClassRef) {
|
|
||||||
const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
|
|
||||||
Ty = llvm::ArrayType::get(Ty, 0);
|
|
||||||
|
|
||||||
CFConstantStringClassRef =
|
|
||||||
new llvm::GlobalVariable(Ty, false,
|
|
||||||
llvm::GlobalVariable::ExternalLinkage, 0,
|
|
||||||
"__CFConstantStringClassReference",
|
|
||||||
&getModule());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Class pointer.
|
|
||||||
llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
|
|
||||||
llvm::Constant *Zeros[] = { Zero, Zero };
|
|
||||||
llvm::Constant *C =
|
|
||||||
llvm::ConstantExpr::getGetElementPtr(CFConstantStringClassRef, Zeros, 2);
|
|
||||||
Fields.push_back(C);
|
|
||||||
|
|
||||||
// Flags.
|
|
||||||
const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
|
|
||||||
Fields.push_back(llvm::ConstantInt::get(Ty, 1992));
|
|
||||||
|
|
||||||
// String pointer.
|
|
||||||
C = llvm::ConstantArray::get(str);
|
|
||||||
C = new llvm::GlobalVariable(C->getType(), true,
|
|
||||||
llvm::GlobalValue::InternalLinkage,
|
|
||||||
C, ".str", &getModule());
|
|
||||||
|
|
||||||
C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2);
|
|
||||||
Fields.push_back(C);
|
|
||||||
|
|
||||||
// String length.
|
|
||||||
Ty = getTypes().ConvertType(getContext().LongTy);
|
|
||||||
Fields.push_back(llvm::ConstantInt::get(Ty, str.length()));
|
|
||||||
|
|
||||||
// The struct.
|
|
||||||
Ty = getTypes().ConvertType(getContext().getCFConstantStringType());
|
|
||||||
C = llvm::ConstantStruct::get(cast<llvm::StructType>(Ty), Fields);
|
|
||||||
C = new llvm::GlobalVariable(C->getType(), true,
|
|
||||||
llvm::GlobalVariable::InternalLinkage,
|
|
||||||
C, "", &getModule());
|
|
||||||
|
|
||||||
Entry.setValue(C);
|
|
||||||
return C;
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
//===--- CodeGenModule.h - Per-Module state for LLVM CodeGen --------------===//
|
|
||||||
//
|
|
||||||
// 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 is the internal per-translation-unit state used for llvm translation.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef CODEGEN_CODEGENMODULE_H
|
|
||||||
#define CODEGEN_CODEGENMODULE_H
|
|
||||||
|
|
||||||
#include "CodeGenTypes.h"
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
|
||||||
#include "llvm/ADT/StringMap.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
class Module;
|
|
||||||
class Constant;
|
|
||||||
class Function;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace clang {
|
|
||||||
class ASTContext;
|
|
||||||
class FunctionDecl;
|
|
||||||
class Decl;
|
|
||||||
class FileVarDecl;
|
|
||||||
|
|
||||||
namespace CodeGen {
|
|
||||||
|
|
||||||
/// CodeGenModule - This class organizes the cross-module state that is used
|
|
||||||
/// while generating LLVM code.
|
|
||||||
class CodeGenModule {
|
|
||||||
ASTContext &Context;
|
|
||||||
llvm::Module &TheModule;
|
|
||||||
CodeGenTypes Types;
|
|
||||||
|
|
||||||
llvm::Function *MemCpyFn;
|
|
||||||
llvm::DenseMap<const Decl*, llvm::Constant*> GlobalDeclMap;
|
|
||||||
|
|
||||||
llvm::StringMap<llvm::Constant*> CFConstantStringMap;
|
|
||||||
llvm::Constant *CFConstantStringClassRef;
|
|
||||||
|
|
||||||
std::vector<llvm::Function *> BuiltinFunctions;
|
|
||||||
public:
|
|
||||||
CodeGenModule(ASTContext &C, llvm::Module &M);
|
|
||||||
|
|
||||||
ASTContext &getContext() const { return Context; }
|
|
||||||
llvm::Module &getModule() const { return TheModule; }
|
|
||||||
CodeGenTypes &getTypes() { return Types; }
|
|
||||||
|
|
||||||
llvm::Constant *GetAddrOfGlobalDecl(const Decl *D);
|
|
||||||
|
|
||||||
/// getBuiltinLibFunction - Given a builtin id for a function like
|
|
||||||
/// "__builtin_fabsf", return a Function* for "fabsf".
|
|
||||||
///
|
|
||||||
llvm::Function *getBuiltinLibFunction(unsigned BuiltinID);
|
|
||||||
llvm::Constant *GetAddrOfConstantCFString(const std::string& str);
|
|
||||||
llvm::Function *getMemCpyFn();
|
|
||||||
|
|
||||||
|
|
||||||
void EmitFunction(const FunctionDecl *FD);
|
|
||||||
void EmitGlobalVar(const FileVarDecl *D);
|
|
||||||
void EmitGlobalVarDeclarator(const FileVarDecl *D);
|
|
||||||
|
|
||||||
void PrintStats() {}
|
|
||||||
};
|
|
||||||
} // end namespace CodeGen
|
|
||||||
} // end namespace clang
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
//===--- CodeGenTypes.cpp - Type translation for LLVM CodeGen -------------===//
|
|
||||||
//
|
|
||||||
// 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 is the code that handles AST -> LLVM type lowering.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "CodeGenTypes.h"
|
|
||||||
#include "clang/Basic/TargetInfo.h"
|
|
||||||
#include "clang/AST/AST.h"
|
|
||||||
#include "llvm/DerivedTypes.h"
|
|
||||||
#include "llvm/Module.h"
|
|
||||||
|
|
||||||
using namespace clang;
|
|
||||||
using namespace CodeGen;
|
|
||||||
|
|
||||||
CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M)
|
|
||||||
: Context(Ctx), Target(Ctx.Target), TheModule(M) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ConvertType - Convert the specified type to its LLVM form.
|
|
||||||
const llvm::Type *CodeGenTypes::ConvertType(QualType T) {
|
|
||||||
// FIXME: Cache these, move the CodeGenModule, expand, etc.
|
|
||||||
const clang::Type &Ty = *T.getCanonicalType();
|
|
||||||
|
|
||||||
switch (Ty.getTypeClass()) {
|
|
||||||
case Type::TypeName: // typedef isn't canonical.
|
|
||||||
case Type::TypeOfExp: // typeof isn't canonical.
|
|
||||||
case Type::TypeOfTyp: // typeof isn't canonical.
|
|
||||||
assert(0 && "Non-canonical type, shouldn't happen");
|
|
||||||
case Type::Builtin: {
|
|
||||||
switch (cast<BuiltinType>(Ty).getKind()) {
|
|
||||||
case BuiltinType::Void:
|
|
||||||
// LLVM void type can only be used as the result of a function call. Just
|
|
||||||
// map to the same as char.
|
|
||||||
return llvm::IntegerType::get(8);
|
|
||||||
|
|
||||||
case BuiltinType::Bool:
|
|
||||||
// FIXME: This is very strange. We want scalars to be i1, but in memory
|
|
||||||
// they can be i1 or i32. Should the codegen handle this issue?
|
|
||||||
return llvm::Type::Int1Ty;
|
|
||||||
|
|
||||||
case BuiltinType::Char_S:
|
|
||||||
case BuiltinType::Char_U:
|
|
||||||
case BuiltinType::SChar:
|
|
||||||
case BuiltinType::UChar:
|
|
||||||
case BuiltinType::Short:
|
|
||||||
case BuiltinType::UShort:
|
|
||||||
case BuiltinType::Int:
|
|
||||||
case BuiltinType::UInt:
|
|
||||||
case BuiltinType::Long:
|
|
||||||
case BuiltinType::ULong:
|
|
||||||
case BuiltinType::LongLong:
|
|
||||||
case BuiltinType::ULongLong:
|
|
||||||
return llvm::IntegerType::get(
|
|
||||||
static_cast<unsigned>(Context.getTypeSize(T, SourceLocation())));
|
|
||||||
|
|
||||||
case BuiltinType::Float: return llvm::Type::FloatTy;
|
|
||||||
case BuiltinType::Double: return llvm::Type::DoubleTy;
|
|
||||||
case BuiltinType::LongDouble:
|
|
||||||
// FIXME: mapping long double onto double.
|
|
||||||
return llvm::Type::DoubleTy;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Type::Complex: {
|
|
||||||
std::vector<const llvm::Type*> Elts;
|
|
||||||
Elts.push_back(ConvertType(cast<ComplexType>(Ty).getElementType()));
|
|
||||||
Elts.push_back(Elts[0]);
|
|
||||||
return llvm::StructType::get(Elts);
|
|
||||||
}
|
|
||||||
case Type::Pointer: {
|
|
||||||
const PointerType &P = cast<PointerType>(Ty);
|
|
||||||
return llvm::PointerType::get(ConvertType(P.getPointeeType()));
|
|
||||||
}
|
|
||||||
case Type::Reference: {
|
|
||||||
const ReferenceType &R = cast<ReferenceType>(Ty);
|
|
||||||
return llvm::PointerType::get(ConvertType(R.getReferenceeType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
case Type::VariableArray: {
|
|
||||||
const VariableArrayType &A = cast<VariableArrayType>(Ty);
|
|
||||||
assert(A.getSizeModifier() == ArrayType::Normal &&
|
|
||||||
A.getIndexTypeQualifier() == 0 &&
|
|
||||||
"FIXME: We only handle trivial array types so far!");
|
|
||||||
if (A.getSizeExpr() == 0) {
|
|
||||||
// int X[] -> [0 x int]
|
|
||||||
return llvm::ArrayType::get(ConvertType(A.getElementType()), 0);
|
|
||||||
} else {
|
|
||||||
assert(0 && "FIXME: VLAs not implemented yet!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case Type::ConstantArray: {
|
|
||||||
const ConstantArrayType &A = cast<ConstantArrayType>(Ty);
|
|
||||||
const llvm::Type *EltTy = ConvertType(A.getElementType());
|
|
||||||
return llvm::ArrayType::get(EltTy, A.getSize().getZExtValue());
|
|
||||||
}
|
|
||||||
case Type::OCUVector:
|
|
||||||
case Type::Vector: {
|
|
||||||
const VectorType &VT = cast<VectorType>(Ty);
|
|
||||||
return llvm::VectorType::get(ConvertType(VT.getElementType()),
|
|
||||||
VT.getNumElements());
|
|
||||||
}
|
|
||||||
case Type::FunctionNoProto:
|
|
||||||
case Type::FunctionProto: {
|
|
||||||
const FunctionType &FP = cast<FunctionType>(Ty);
|
|
||||||
const llvm::Type *ResultType;
|
|
||||||
|
|
||||||
if (FP.getResultType()->isVoidType())
|
|
||||||
ResultType = llvm::Type::VoidTy; // Result of function uses llvm void.
|
|
||||||
else
|
|
||||||
ResultType = ConvertType(FP.getResultType());
|
|
||||||
|
|
||||||
// FIXME: Convert argument types.
|
|
||||||
bool isVarArg;
|
|
||||||
std::vector<const llvm::Type*> ArgTys;
|
|
||||||
|
|
||||||
// Struct return passes the struct byref.
|
|
||||||
if (!ResultType->isFirstClassType() && ResultType != llvm::Type::VoidTy) {
|
|
||||||
ArgTys.push_back(llvm::PointerType::get(ResultType));
|
|
||||||
ResultType = llvm::Type::VoidTy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const FunctionTypeProto *FTP = dyn_cast<FunctionTypeProto>(&FP)) {
|
|
||||||
DecodeArgumentTypes(*FTP, ArgTys);
|
|
||||||
isVarArg = FTP->isVariadic();
|
|
||||||
} else {
|
|
||||||
isVarArg = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return llvm::FunctionType::get(ResultType, ArgTys, isVarArg, 0);
|
|
||||||
}
|
|
||||||
case Type::Tagged:
|
|
||||||
const TagType &TT = cast<TagType>(Ty);
|
|
||||||
const TagDecl *TD = TT.getDecl();
|
|
||||||
llvm::Type *&ResultType = TagDeclTypes[TD];
|
|
||||||
|
|
||||||
if (ResultType)
|
|
||||||
return ResultType;
|
|
||||||
|
|
||||||
if (!TD->isDefinition()) {
|
|
||||||
ResultType = llvm::OpaqueType::get();
|
|
||||||
} else if (TD->getKind() == Decl::Enum) {
|
|
||||||
return ConvertType(cast<EnumDecl>(TD)->getIntegerType());
|
|
||||||
} else if (TD->getKind() == Decl::Struct) {
|
|
||||||
const RecordDecl *RD = cast<const RecordDecl>(TD);
|
|
||||||
std::vector<const llvm::Type*> Fields;
|
|
||||||
for (unsigned i = 0, e = RD->getNumMembers(); i != e; ++i)
|
|
||||||
Fields.push_back(ConvertType(RD->getMember(i)->getType()));
|
|
||||||
ResultType = llvm::StructType::get(Fields);
|
|
||||||
} else if (TD->getKind() == Decl::Union) {
|
|
||||||
const RecordDecl *RD = cast<const RecordDecl>(TD);
|
|
||||||
// Just use the largest element of the union, breaking ties with the
|
|
||||||
// highest aligned member.
|
|
||||||
std::vector<const llvm::Type*> Fields;
|
|
||||||
if (RD->getNumMembers() != 0) {
|
|
||||||
std::pair<uint64_t, unsigned> MaxElt =
|
|
||||||
Context.getTypeInfo(RD->getMember(0)->getType(), SourceLocation());
|
|
||||||
unsigned MaxEltNo = 0;
|
|
||||||
|
|
||||||
for (unsigned i = 1, e = RD->getNumMembers(); i != e; ++i) {
|
|
||||||
std::pair<uint64_t, unsigned> EltInfo =
|
|
||||||
Context.getTypeInfo(RD->getMember(i)->getType(), SourceLocation());
|
|
||||||
if (EltInfo.first > MaxElt.first ||
|
|
||||||
(EltInfo.first == MaxElt.first &&
|
|
||||||
EltInfo.second > MaxElt.second)) {
|
|
||||||
MaxElt = EltInfo;
|
|
||||||
MaxEltNo = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Fields.push_back(ConvertType(RD->getMember(MaxEltNo)->getType()));
|
|
||||||
}
|
|
||||||
ResultType = llvm::StructType::get(Fields);
|
|
||||||
} else {
|
|
||||||
assert(0 && "FIXME: Implement tag decl kind!");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string TypeName(TD->getKindName());
|
|
||||||
TypeName += '.';
|
|
||||||
TypeName += TD->getName();
|
|
||||||
|
|
||||||
TheModule.addTypeName(TypeName, ResultType);
|
|
||||||
return ResultType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: implement.
|
|
||||||
return llvm::OpaqueType::get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenTypes::DecodeArgumentTypes(const FunctionTypeProto &FTP,
|
|
||||||
std::vector<const llvm::Type*> &ArgTys) {
|
|
||||||
for (unsigned i = 0, e = FTP.getNumArgs(); i != e; ++i) {
|
|
||||||
const llvm::Type *Ty = ConvertType(FTP.getArgType(i));
|
|
||||||
if (Ty->isFirstClassType())
|
|
||||||
ArgTys.push_back(Ty);
|
|
||||||
else
|
|
||||||
ArgTys.push_back(llvm::PointerType::get(Ty));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
//===--- CodeGenTypes.h - Type translation for LLVM CodeGen -----*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// 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 is the code that handles AST -> LLVM type lowering.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef CODEGEN_CODEGENTYPES_H
|
|
||||||
#define CODEGEN_CODEGENTYPES_H
|
|
||||||
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
class Module;
|
|
||||||
class Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace clang {
|
|
||||||
class ASTContext;
|
|
||||||
class TagDecl;
|
|
||||||
class TargetInfo;
|
|
||||||
class QualType;
|
|
||||||
class FunctionTypeProto;
|
|
||||||
|
|
||||||
namespace CodeGen {
|
|
||||||
|
|
||||||
/// CodeGenTypes - This class organizes the cross-module state that is used
|
|
||||||
/// while lowering AST types to LLVM types.
|
|
||||||
class CodeGenTypes {
|
|
||||||
ASTContext &Context;
|
|
||||||
TargetInfo &Target;
|
|
||||||
llvm::Module& TheModule;
|
|
||||||
|
|
||||||
llvm::DenseMap<const TagDecl*, llvm::Type*> TagDeclTypes;
|
|
||||||
public:
|
|
||||||
CodeGenTypes(ASTContext &Ctx, llvm::Module &M);
|
|
||||||
|
|
||||||
TargetInfo &getTarget() const { return Target; }
|
|
||||||
|
|
||||||
const llvm::Type *ConvertType(QualType T);
|
|
||||||
void DecodeArgumentTypes(const FunctionTypeProto &FTP,
|
|
||||||
std::vector<const llvm::Type*> &ArgTys);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end namespace CodeGen
|
|
||||||
} // end namespace clang
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
##===- clang/CodeGen/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 -> LLVM code generation library for the
|
|
||||||
# C-Language front-end.
|
|
||||||
#
|
|
||||||
##===----------------------------------------------------------------------===##
|
|
||||||
|
|
||||||
LEVEL = ../../..
|
|
||||||
LIBRARYNAME := clangCodeGen
|
|
||||||
BUILD_ARCHIVE = 1
|
|
||||||
CXXFLAGS = -fno-rtti
|
|
||||||
|
|
||||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.common
|
|
||||||
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
//===--- ModuleBuilder.cpp - Emit LLVM Code from 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 builds an AST and converts it to LLVM Code.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/CodeGen/ModuleBuilder.h"
|
|
||||||
#include "CodeGenModule.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
|
|
||||||
/// Init - Create an ModuleBuilder with the specified ASTContext.
|
|
||||||
clang::CodeGen::BuilderTy *
|
|
||||||
clang::CodeGen::Init(ASTContext &Context, llvm::Module &M) {
|
|
||||||
return new CodeGenModule(Context, M);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clang::CodeGen::Terminate(BuilderTy *B) {
|
|
||||||
delete static_cast<CodeGenModule*>(B);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// CodeGenFunction - Convert the AST node for a FunctionDecl into LLVM.
|
|
||||||
///
|
|
||||||
void clang::CodeGen::CodeGenFunction(BuilderTy *B, FunctionDecl *D) {
|
|
||||||
static_cast<CodeGenModule*>(B)->EmitFunction(D);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// CodeGenGlobalVar - Emit the specified global variable to LLVM.
|
|
||||||
void clang::CodeGen::CodeGenGlobalVar(BuilderTy *Builder, FileVarDecl *D) {
|
|
||||||
static_cast<CodeGenModule*>(Builder)->EmitGlobalVarDeclarator(D);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// PrintStats - Emit statistic information to stderr.
|
|
||||||
///
|
|
||||||
void clang::CodeGen::PrintStats(BuilderTy *B) {
|
|
||||||
static_cast<CodeGenModule*>(B)->PrintStats();
|
|
||||||
}
|
|
||||||
@@ -1,282 +0,0 @@
|
|||||||
//===--- ASTStreamers.cpp - ASTStreamer Drivers ---------------------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Bill Wendling and is distributed under the
|
|
||||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// ASTStreamer drivers.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "ASTStreamers.h"
|
|
||||||
#include "clang/AST/AST.h"
|
|
||||||
#include "clang/AST/CFG.h"
|
|
||||||
#include "clang/Analysis/LiveVariables.h"
|
|
||||||
#include "clang/Analysis/LocalCheckers.h"
|
|
||||||
#include "clang/Lex/Preprocessor.h"
|
|
||||||
#include "clang/Sema/ASTStreamer.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
void clang::BuildASTs(Preprocessor &PP, unsigned MainFileID, bool Stats) {
|
|
||||||
// collect global stats on Decls/Stmts (until we have a module streamer)
|
|
||||||
if (Stats) {
|
|
||||||
Decl::CollectingStats(true);
|
|
||||||
Stmt::CollectingStats(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASTContext Context(PP.getSourceManager(), PP.getTargetInfo(),
|
|
||||||
PP.getIdentifierTable());
|
|
||||||
ASTStreamerTy *Streamer = ASTStreamer_Init(PP, Context, MainFileID);
|
|
||||||
|
|
||||||
while (ASTStreamer_ReadTopLevelDecl(Streamer))
|
|
||||||
/* keep reading */;
|
|
||||||
|
|
||||||
if (Stats) {
|
|
||||||
fprintf(stderr, "\nSTATISTICS:\n");
|
|
||||||
ASTStreamer_PrintStats(Streamer);
|
|
||||||
Context.PrintStats();
|
|
||||||
Decl::PrintStats();
|
|
||||||
Stmt::PrintStats();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASTStreamer_Terminate(Streamer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void PrintFunctionDeclStart(FunctionDecl *FD) {
|
|
||||||
bool HasBody = FD->getBody();
|
|
||||||
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
|
|
||||||
switch (FD->getStorageClass()) {
|
|
||||||
default: assert(0 && "Unknown storage class");
|
|
||||||
case FunctionDecl::None: break;
|
|
||||||
case FunctionDecl::Extern: fprintf(stderr, "extern "); break;
|
|
||||||
case FunctionDecl::Static: fprintf(stderr, "static "); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FD->isInline())
|
|
||||||
fprintf(stderr, "inline ");
|
|
||||||
|
|
||||||
std::string Proto = FD->getName();
|
|
||||||
FunctionType *AFT = cast<FunctionType>(FD->getType());
|
|
||||||
|
|
||||||
if (FunctionTypeProto *FT = dyn_cast<FunctionTypeProto>(AFT)) {
|
|
||||||
Proto += "(";
|
|
||||||
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
|
|
||||||
if (i) Proto += ", ";
|
|
||||||
std::string ParamStr;
|
|
||||||
if (HasBody) ParamStr = FD->getParamDecl(i)->getName();
|
|
||||||
|
|
||||||
FT->getArgType(i).getAsStringInternal(ParamStr);
|
|
||||||
Proto += ParamStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FT->isVariadic()) {
|
|
||||||
if (FD->getNumParams()) Proto += ", ";
|
|
||||||
Proto += "...";
|
|
||||||
}
|
|
||||||
Proto += ")";
|
|
||||||
} else {
|
|
||||||
assert(isa<FunctionTypeNoProto>(AFT));
|
|
||||||
Proto += "()";
|
|
||||||
}
|
|
||||||
|
|
||||||
AFT->getResultType().getAsStringInternal(Proto);
|
|
||||||
fprintf(stderr, "%s", Proto.c_str());
|
|
||||||
|
|
||||||
if (!FD->getBody())
|
|
||||||
fprintf(stderr, ";\n");
|
|
||||||
// Doesn't print the body.
|
|
||||||
}
|
|
||||||
|
|
||||||
static void PrintTypeDefDecl(TypedefDecl *TD) {
|
|
||||||
std::string S = TD->getName();
|
|
||||||
TD->getUnderlyingType().getAsStringInternal(S);
|
|
||||||
fprintf(stderr, "typedef %s;\n", S.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void PrintObjcInterfaceDecl(ObjcInterfaceDecl *OID) {
|
|
||||||
std::string S = OID->getName();
|
|
||||||
fprintf(stderr, "@interface %s;\n", S.c_str());
|
|
||||||
// FIXME: implement the rest...
|
|
||||||
}
|
|
||||||
|
|
||||||
void clang::PrintASTs(Preprocessor &PP, unsigned MainFileID, bool Stats) {
|
|
||||||
ASTContext Context(PP.getSourceManager(), PP.getTargetInfo(),
|
|
||||||
PP.getIdentifierTable());
|
|
||||||
ASTStreamerTy *Streamer = ASTStreamer_Init(PP, Context, MainFileID);
|
|
||||||
|
|
||||||
while (Decl *D = ASTStreamer_ReadTopLevelDecl(Streamer)) {
|
|
||||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
|
||||||
PrintFunctionDeclStart(FD);
|
|
||||||
|
|
||||||
if (FD->getBody()) {
|
|
||||||
fprintf(stderr, " ");
|
|
||||||
FD->getBody()->dumpPretty();
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
} else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
|
|
||||||
PrintTypeDefDecl(TD);
|
|
||||||
} else if (ObjcInterfaceDecl *OID = dyn_cast<ObjcInterfaceDecl>(D)) {
|
|
||||||
PrintObjcInterfaceDecl(OID);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Read top-level variable decl: '%s'\n", D->getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Stats) {
|
|
||||||
fprintf(stderr, "\nSTATISTICS:\n");
|
|
||||||
ASTStreamer_PrintStats(Streamer);
|
|
||||||
Context.PrintStats();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASTStreamer_Terminate(Streamer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clang::DumpASTs(Preprocessor &PP, unsigned MainFileID, bool Stats) {
|
|
||||||
ASTContext Context(PP.getSourceManager(), PP.getTargetInfo(),
|
|
||||||
PP.getIdentifierTable());
|
|
||||||
ASTStreamerTy *Streamer = ASTStreamer_Init(PP, Context, MainFileID);
|
|
||||||
|
|
||||||
while (Decl *D = ASTStreamer_ReadTopLevelDecl(Streamer)) {
|
|
||||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
|
||||||
PrintFunctionDeclStart(FD);
|
|
||||||
|
|
||||||
if (FD->getBody()) {
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
FD->getBody()->dumpAll(PP.getSourceManager());
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
} else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
|
|
||||||
PrintTypeDefDecl(TD);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Read top-level variable decl: '%s'\n", D->getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Stats) {
|
|
||||||
fprintf(stderr, "\nSTATISTICS:\n");
|
|
||||||
ASTStreamer_PrintStats(Streamer);
|
|
||||||
Context.PrintStats();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASTStreamer_Terminate(Streamer);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// CFGVisitor & VisitCFGs - Boilerplate interface and logic to visit
|
|
||||||
// the CFGs for all function definitions.
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class CFGVisitor {
|
|
||||||
public:
|
|
||||||
virtual ~CFGVisitor() {}
|
|
||||||
virtual void VisitCFG(CFG& C) = 0;
|
|
||||||
virtual bool printFuncDeclStart() { return true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
static void VisitCFGs(CFGVisitor& Visitor, Preprocessor& PP,
|
|
||||||
unsigned MainFileID, bool Stats) {
|
|
||||||
|
|
||||||
bool printFDecl = Visitor.printFuncDeclStart();
|
|
||||||
ASTContext Context(PP.getSourceManager(), PP.getTargetInfo(),
|
|
||||||
PP.getIdentifierTable());
|
|
||||||
ASTStreamerTy *Streamer = ASTStreamer_Init(PP, Context, MainFileID);
|
|
||||||
|
|
||||||
while (Decl *D = ASTStreamer_ReadTopLevelDecl(Streamer)) {
|
|
||||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
|
|
||||||
if (FD->getBody()) {
|
|
||||||
|
|
||||||
if (printFDecl) {
|
|
||||||
PrintFunctionDeclStart(FD);
|
|
||||||
fprintf(stderr,"\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CFG* C = CFG::buildCFG(FD->getBody())) {
|
|
||||||
Visitor.VisitCFG(*C);
|
|
||||||
delete C;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
fprintf(stderr," Error processing CFG.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Stats) {
|
|
||||||
fprintf(stderr, "\nSTATISTICS:\n");
|
|
||||||
ASTStreamer_PrintStats(Streamer);
|
|
||||||
Context.PrintStats();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASTStreamer_Terminate(Streamer);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// DumpCFGs - Dump CFGs to stderr or visualize with Graphviz
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class CFGDumper : public CFGVisitor {
|
|
||||||
const bool UseGraphviz;
|
|
||||||
public:
|
|
||||||
CFGDumper(bool use_graphviz) : UseGraphviz(use_graphviz) {}
|
|
||||||
|
|
||||||
virtual void VisitCFG(CFG& C) {
|
|
||||||
if (UseGraphviz) C.viewCFG();
|
|
||||||
else C.dump();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
void clang::DumpCFGs(Preprocessor &PP, unsigned MainFileID,
|
|
||||||
bool Stats, bool use_graphviz) {
|
|
||||||
CFGDumper Visitor(use_graphviz);
|
|
||||||
VisitCFGs(Visitor,PP,MainFileID,Stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// AnalyzeLiveVariables - perform live variable analysis and dump results
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class LivenessVisitor : public CFGVisitor {
|
|
||||||
Preprocessor& PP;
|
|
||||||
public:
|
|
||||||
LivenessVisitor(Preprocessor& pp) : PP(pp) {}
|
|
||||||
|
|
||||||
virtual void VisitCFG(CFG& C) {
|
|
||||||
LiveVariables L;
|
|
||||||
L.runOnCFG(C);
|
|
||||||
L.dumpBlockLiveness(PP.getSourceManager());
|
|
||||||
L.dumpVarLiveness(PP.getSourceManager());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
void clang::AnalyzeLiveVariables(Preprocessor &PP, unsigned MainFileID) {
|
|
||||||
LivenessVisitor Visitor(PP);
|
|
||||||
VisitCFGs(Visitor,PP,MainFileID,false);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// RunDeadStores - run checker to locate dead stores in a function
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class DeadStoreVisitor : public CFGVisitor {
|
|
||||||
Preprocessor& PP;
|
|
||||||
public:
|
|
||||||
DeadStoreVisitor(Preprocessor& pp) : PP(pp) {}
|
|
||||||
virtual void VisitCFG(CFG& C) { CheckDeadStores(C,PP); }
|
|
||||||
virtual bool printFuncDeclStart() { return false; }
|
|
||||||
};
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
void clang::RunDeadStoresCheck(Preprocessor &PP,unsigned MainFileID,bool Stats){
|
|
||||||
DeadStoreVisitor Visitor(PP);
|
|
||||||
VisitCFGs(Visitor,PP,MainFileID,Stats);
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
//===--- ASTStreamers.h - ASTStreamer Drivers -------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Bill Wendling and is distributed under the
|
|
||||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// AST Streamers.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef DRIVER_ASTSTREAMERS_H_
|
|
||||||
#define DRIVER_ASTSTREAMERS_H_
|
|
||||||
|
|
||||||
namespace clang {
|
|
||||||
|
|
||||||
class Preprocessor;
|
|
||||||
class FunctionDecl;
|
|
||||||
class TypedefDecl;
|
|
||||||
|
|
||||||
void BuildASTs(Preprocessor &PP, unsigned MainFileID, bool Stats);
|
|
||||||
void PrintASTs(Preprocessor &PP, unsigned MainFileID, bool Stats);
|
|
||||||
void DumpASTs(Preprocessor &PP, unsigned MainFileID, bool Stats);
|
|
||||||
|
|
||||||
void DumpCFGs(Preprocessor &PP, unsigned MainFileID,
|
|
||||||
bool Stats, bool use_graphviz = false);
|
|
||||||
|
|
||||||
void AnalyzeLiveVariables(Preprocessor &PP, unsigned MainFileID);
|
|
||||||
|
|
||||||
void RunDeadStoresCheck(Preprocessor &PP, unsigned MainFileID, bool Stats);
|
|
||||||
|
|
||||||
} // end clang namespace
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
//===--- DiagChecker.cpp - Diagnostic Checking Functions ------------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Bill Wendling and is distributed under the
|
|
||||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Process the input files and check that the diagnostic messages are expected.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang.h"
|
|
||||||
#include "ASTStreamers.h"
|
|
||||||
#include "TextDiagnosticBuffer.h"
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
#include "clang/Lex/Preprocessor.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
typedef TextDiagnosticBuffer::DiagList DiagList;
|
|
||||||
typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
|
|
||||||
|
|
||||||
// USING THE DIAGNOSTIC CHECKER:
|
|
||||||
//
|
|
||||||
// Indicating that a line expects an error or a warning is simple. Put a comment
|
|
||||||
// on the line that has the diagnostic, use "expected-{error,warning}" to tag
|
|
||||||
// if it's an expected error or warning, and place the expected text between {{
|
|
||||||
// and }} markers. The full text doesn't have to be included, only enough to
|
|
||||||
// ensure that the correct diagnostic was emitted.
|
|
||||||
//
|
|
||||||
// Here's an example:
|
|
||||||
//
|
|
||||||
// int A = B; // expected-error {{use of undeclared identifier 'B'}}
|
|
||||||
//
|
|
||||||
// You can place as many diagnostics on one line as you wish. To make the code
|
|
||||||
// more readable, you can use slash-newline to separate out the diagnostics.
|
|
||||||
|
|
||||||
static const char * const ExpectedErrStr = "expected-error";
|
|
||||||
static const char * const ExpectedWarnStr = "expected-warning";
|
|
||||||
|
|
||||||
/// FindDiagnostics - Go through the comment and see if it indicates expected
|
|
||||||
/// diagnostics. If so, then put them in a diagnostic list.
|
|
||||||
///
|
|
||||||
static void FindDiagnostics(const std::string &Comment,
|
|
||||||
DiagList &ExpectedDiags,
|
|
||||||
SourceManager &SourceMgr,
|
|
||||||
SourceLocation Pos,
|
|
||||||
const char * const ExpectedStr) {
|
|
||||||
// Find all expected diagnostics
|
|
||||||
typedef std::string::size_type size_type;
|
|
||||||
size_type ColNo = std::string::npos;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
ColNo = Comment.find(ExpectedStr, ColNo);
|
|
||||||
if (ColNo == std::string::npos) break;
|
|
||||||
|
|
||||||
size_type OpenDiag = Comment.find_first_of("{{", ColNo);
|
|
||||||
|
|
||||||
if (OpenDiag == std::string::npos) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"oops:%d: Cannot find beginning of expected error string\n",
|
|
||||||
SourceMgr.getLogicalLineNumber(Pos));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenDiag += 2;
|
|
||||||
size_type CloseDiag = Comment.find_first_of("}}", OpenDiag);
|
|
||||||
|
|
||||||
if (CloseDiag == std::string::npos) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"oops:%d: Cannot find end of expected error string\n",
|
|
||||||
SourceMgr.getLogicalLineNumber(Pos));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Msg(Comment.substr(OpenDiag, CloseDiag - OpenDiag));
|
|
||||||
ExpectedDiags.push_back(std::make_pair(Pos, Msg));
|
|
||||||
ColNo = CloseDiag + 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// FindExpectedDiags - Lex the file to finds all of the expected errors and
|
|
||||||
/// warnings.
|
|
||||||
static void FindExpectedDiags(Preprocessor &PP, unsigned MainFileID,
|
|
||||||
DiagList &ExpectedErrors,
|
|
||||||
DiagList &ExpectedWarnings) {
|
|
||||||
// Return comments as tokens, this is how we find expected diagnostics.
|
|
||||||
PP.SetCommentRetentionState(true, true);
|
|
||||||
|
|
||||||
// Enter the cave.
|
|
||||||
PP.EnterSourceFile(MainFileID, 0, true);
|
|
||||||
|
|
||||||
// Turn off all warnings from relexing or preprocessing.
|
|
||||||
PP.getDiagnostics().setWarnOnExtensions(false);
|
|
||||||
PP.getDiagnostics().setErrorOnExtensions(false);
|
|
||||||
for (unsigned i = 0; i != diag::NUM_DIAGNOSTICS; ++i)
|
|
||||||
if (PP.getDiagnostics().isNoteWarningOrExtension((diag::kind)i))
|
|
||||||
PP.getDiagnostics().setDiagnosticMapping((diag::kind)i, diag::MAP_IGNORE);
|
|
||||||
|
|
||||||
Token Tok;
|
|
||||||
do {
|
|
||||||
PP.Lex(Tok);
|
|
||||||
|
|
||||||
if (Tok.getKind() == tok::comment) {
|
|
||||||
std::string Comment = PP.getSpelling(Tok);
|
|
||||||
|
|
||||||
// Find all expected errors
|
|
||||||
FindDiagnostics(Comment, ExpectedErrors,PP.getSourceManager(),
|
|
||||||
Tok.getLocation(), ExpectedErrStr);
|
|
||||||
|
|
||||||
// Find all expected warnings
|
|
||||||
FindDiagnostics(Comment, ExpectedWarnings, PP.getSourceManager(),
|
|
||||||
Tok.getLocation(), ExpectedWarnStr);
|
|
||||||
}
|
|
||||||
} while (Tok.getKind() != tok::eof);
|
|
||||||
|
|
||||||
PP.SetCommentRetentionState(false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PrintProblem - This takes a diagnostic map of the delta between expected and
|
|
||||||
/// seen diagnostics. If there's anything in it, then something unexpected
|
|
||||||
/// happened. Print the map out in a nice format and return "true". If the map
|
|
||||||
/// is empty and we're not going to print things, then return "false".
|
|
||||||
///
|
|
||||||
static bool PrintProblem(SourceManager &SourceMgr,
|
|
||||||
const_diag_iterator diag_begin,
|
|
||||||
const_diag_iterator diag_end,
|
|
||||||
const char *Msg) {
|
|
||||||
if (diag_begin == diag_end) return false;
|
|
||||||
|
|
||||||
fprintf(stderr, "%s\n", Msg);
|
|
||||||
|
|
||||||
for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I)
|
|
||||||
fprintf(stderr, " Line %d: %s\n",
|
|
||||||
SourceMgr.getLogicalLineNumber(I->first),
|
|
||||||
I->second.c_str());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// CompareDiagLists - Compare two diangnostic lists and return the difference
|
|
||||||
/// between them.
|
|
||||||
///
|
|
||||||
static bool CompareDiagLists(SourceManager &SourceMgr,
|
|
||||||
const_diag_iterator d1_begin,
|
|
||||||
const_diag_iterator d1_end,
|
|
||||||
const_diag_iterator d2_begin,
|
|
||||||
const_diag_iterator d2_end,
|
|
||||||
const char *Msg) {
|
|
||||||
DiagList DiffList;
|
|
||||||
|
|
||||||
for (const_diag_iterator I = d1_begin, E = d1_end; I != E; ++I) {
|
|
||||||
unsigned LineNo1 = SourceMgr.getLogicalLineNumber(I->first);
|
|
||||||
const std::string &Diag1 = I->second;
|
|
||||||
bool Found = false;
|
|
||||||
|
|
||||||
for (const_diag_iterator II = d2_begin, IE = d2_end; II != IE; ++II) {
|
|
||||||
unsigned LineNo2 = SourceMgr.getLogicalLineNumber(II->first);
|
|
||||||
if (LineNo1 != LineNo2) continue;
|
|
||||||
|
|
||||||
const std::string &Diag2 = II->second;
|
|
||||||
if (Diag2.find(Diag1) != std::string::npos ||
|
|
||||||
Diag1.find(Diag2) != std::string::npos) {
|
|
||||||
Found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Found)
|
|
||||||
DiffList.push_back(std::make_pair(I->first, Diag1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return PrintProblem(SourceMgr, DiffList.begin(), DiffList.end(), Msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// CheckResults - This compares the expected results to those that
|
|
||||||
/// were actually reported. It emits any discrepencies. Return "true" if there
|
|
||||||
/// were problems. Return "false" otherwise.
|
|
||||||
///
|
|
||||||
static bool CheckResults(Preprocessor &PP,
|
|
||||||
const DiagList &ExpectedErrors,
|
|
||||||
const DiagList &ExpectedWarnings) {
|
|
||||||
const TextDiagnosticBuffer &Diags =
|
|
||||||
static_cast<const TextDiagnosticBuffer&>(PP.getDiagnostics().getClient());
|
|
||||||
SourceManager &SourceMgr = PP.getSourceManager();
|
|
||||||
|
|
||||||
// We want to capture the delta between what was expected and what was
|
|
||||||
// seen.
|
|
||||||
//
|
|
||||||
// Expected \ Seen - set expected but not seen
|
|
||||||
// Seen \ Expected - set seen but not expected
|
|
||||||
bool HadProblem = false;
|
|
||||||
|
|
||||||
// See if there were errors that were expected but not seen.
|
|
||||||
HadProblem |= CompareDiagLists(SourceMgr,
|
|
||||||
ExpectedErrors.begin(), ExpectedErrors.end(),
|
|
||||||
Diags.err_begin(), Diags.err_end(),
|
|
||||||
"Errors expected but not seen:");
|
|
||||||
|
|
||||||
// See if there were errors that were seen but not expected.
|
|
||||||
HadProblem |= CompareDiagLists(SourceMgr,
|
|
||||||
Diags.err_begin(), Diags.err_end(),
|
|
||||||
ExpectedErrors.begin(), ExpectedErrors.end(),
|
|
||||||
"Errors seen but not expected:");
|
|
||||||
|
|
||||||
// See if there were warnings that were expected but not seen.
|
|
||||||
HadProblem |= CompareDiagLists(SourceMgr,
|
|
||||||
ExpectedWarnings.begin(),
|
|
||||||
ExpectedWarnings.end(),
|
|
||||||
Diags.warn_begin(), Diags.warn_end(),
|
|
||||||
"Warnings expected but not seen:");
|
|
||||||
|
|
||||||
// See if there were warnings that were seen but not expected.
|
|
||||||
HadProblem |= CompareDiagLists(SourceMgr,
|
|
||||||
Diags.warn_begin(), Diags.warn_end(),
|
|
||||||
ExpectedWarnings.begin(),
|
|
||||||
ExpectedWarnings.end(),
|
|
||||||
"Warnings seen but not expected:");
|
|
||||||
|
|
||||||
return HadProblem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// CheckDiagnostics - Implement the -parse-ast-check diagnostic verifier.
|
|
||||||
bool clang::CheckDiagnostics(Preprocessor &PP, unsigned MainFileID) {
|
|
||||||
// Parse the specified input file.
|
|
||||||
BuildASTs(PP, MainFileID, false);
|
|
||||||
|
|
||||||
// Gather the set of expected diagnostics.
|
|
||||||
DiagList ExpectedErrors, ExpectedWarnings;
|
|
||||||
FindExpectedDiags(PP, MainFileID, ExpectedErrors, ExpectedWarnings);
|
|
||||||
|
|
||||||
// Check that the expected diagnostics occurred.
|
|
||||||
return CheckResults(PP, ExpectedErrors, ExpectedWarnings);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
//===--- LLVMCodegen.cpp - Emit LLVM Code from 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 builds an AST and converts it to LLVM Code.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang.h"
|
|
||||||
#include "clang/CodeGen/ModuleBuilder.h"
|
|
||||||
#include "clang/Sema/ASTStreamer.h"
|
|
||||||
#include "clang/AST/AST.h"
|
|
||||||
#include "clang/Lex/Preprocessor.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "llvm/Module.h"
|
|
||||||
#include <iostream>
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// LLVM Emission
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
void clang::EmitLLVMFromASTs(Preprocessor &PP, unsigned MainFileID,
|
|
||||||
bool PrintStats) {
|
|
||||||
Diagnostic &Diags = PP.getDiagnostics();
|
|
||||||
// Create the streamer to read the file.
|
|
||||||
ASTContext Context(PP.getSourceManager(), PP.getTargetInfo(),
|
|
||||||
PP.getIdentifierTable());
|
|
||||||
ASTStreamerTy *Streamer = ASTStreamer_Init(PP, Context, MainFileID);
|
|
||||||
|
|
||||||
// Create the module to codegen into.
|
|
||||||
llvm::Module M("foo");
|
|
||||||
|
|
||||||
CodeGen::BuilderTy *Builder = CodeGen::Init(Context, M);
|
|
||||||
|
|
||||||
while (Decl *D = ASTStreamer_ReadTopLevelDecl(Streamer)) {
|
|
||||||
// If an error occurred, stop code generation, but continue parsing and
|
|
||||||
// semantic analysis (to ensure all warnings and errors are emitted).
|
|
||||||
if (Diags.hasErrorOccurred())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
|
||||||
CodeGen::CodeGenFunction(Builder, FD);
|
|
||||||
} else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
|
|
||||||
CodeGen::CodeGenGlobalVar(Builder, FVD);
|
|
||||||
} else {
|
|
||||||
assert(isa<TypedefDecl>(D) && "Only expected typedefs here");
|
|
||||||
// don't codegen for now, eventually pass down for debug info.
|
|
||||||
//std::cerr << "Read top-level typedef decl: '" << D->getName() << "'\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PrintStats) {
|
|
||||||
std::cerr << "\nSTATISTICS:\n";
|
|
||||||
CodeGen::PrintStats(Builder);
|
|
||||||
ASTStreamer_PrintStats(Streamer);
|
|
||||||
Context.PrintStats();
|
|
||||||
}
|
|
||||||
|
|
||||||
CodeGen::Terminate(Builder);
|
|
||||||
ASTStreamer_Terminate(Streamer);
|
|
||||||
|
|
||||||
// Print the generated code.
|
|
||||||
M.print(std::cout);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
LEVEL = ../../..
|
|
||||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
|
||||||
CXXFLAGS = -fno-rtti
|
|
||||||
|
|
||||||
TOOLNAME = clang
|
|
||||||
USEDLIBS = clangCodeGen.a clangAnalysis.a clangSEMA.a clangAST.a clangParse.a clangLex.a clangBasic.a LLVMCore.a LLVMSupport.a LLVMSystem.a
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.common
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
//===--- PPCBuiltins.def - PowerPC Builtin function database ----*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// 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 defines the PowerPC-specific builtin function database. Users of
|
|
||||||
// this file must define the BUILTIN macro to make use of this information.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// FIXME: this needs to be the full list supported by GCC. Right now, I'm just
|
|
||||||
// adding stuff on demand.
|
|
||||||
|
|
||||||
// The format of this database matches clang/AST/Builtins.def.
|
|
||||||
|
|
||||||
// This is just a placeholder, the types and attributes are wrong.
|
|
||||||
BUILTIN(__builtin_altivec_abs_v4sf , "ii" , "nc")
|
|
||||||
// FIXME: Obviously incomplete.
|
|
||||||
|
|
||||||
#undef BUILTIN
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
//===--- PrintParserActions.cpp - Implement -parse-print-callbacks mode ---===//
|
|
||||||
//
|
|
||||||
// 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 code simply runs the preprocessor on the input file and prints out the
|
|
||||||
// result. This is the traditional behavior of the -E option.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang.h"
|
|
||||||
#include "clang/Lex/IdentifierTable.h"
|
|
||||||
#include "clang/Parse/Action.h"
|
|
||||||
#include "clang/Parse/DeclSpec.h"
|
|
||||||
#include <iostream>
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class ParserPrintActions : public MinimalAction {
|
|
||||||
|
|
||||||
/// ParseDeclarator - This callback is invoked when a declarator is parsed
|
|
||||||
/// and 'Init' specifies the initializer if any. This is for things like:
|
|
||||||
/// "int X = 4" or "typedef int foo".
|
|
||||||
virtual DeclTy *ParseDeclarator(Scope *S, Declarator &D,
|
|
||||||
DeclTy *LastInGroup) {
|
|
||||||
std::cout << "ParseDeclarator ";
|
|
||||||
if (IdentifierInfo *II = D.getIdentifier()) {
|
|
||||||
std::cout << "'" << II->getName() << "'";
|
|
||||||
} else {
|
|
||||||
std::cout << "<anon>";
|
|
||||||
}
|
|
||||||
std::cout << "\n";
|
|
||||||
|
|
||||||
// Pass up to EmptyActions so that the symbol table is maintained right.
|
|
||||||
return MinimalAction::ParseDeclarator(S, D, LastInGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PopScope - This callback is called immediately before the specified scope
|
|
||||||
/// is popped and deleted.
|
|
||||||
virtual void PopScope(SourceLocation Loc, Scope *S) {
|
|
||||||
std::cout << "PopScope\n";
|
|
||||||
|
|
||||||
// Pass up to EmptyActions so that the symbol table is maintained right.
|
|
||||||
MinimalAction::PopScope(Loc, S);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
MinimalAction *clang::CreatePrintParserActionsAction() {
|
|
||||||
return new ParserPrintActions();
|
|
||||||
}
|
|
||||||
@@ -1,574 +0,0 @@
|
|||||||
//===--- PrintPreprocessedOutput.cpp - Implement the -E mode --------------===//
|
|
||||||
//
|
|
||||||
// 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 code simply runs the preprocessor on the input file and prints out the
|
|
||||||
// result. This is the traditional behavior of the -E option.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang.h"
|
|
||||||
#include "clang/Lex/PPCallbacks.h"
|
|
||||||
#include "clang/Lex/Preprocessor.h"
|
|
||||||
#include "clang/Lex/Pragma.h"
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
#include "llvm/Support/CommandLine.h"
|
|
||||||
#include "llvm/ADT/SmallString.h"
|
|
||||||
#include "llvm/ADT/StringExtras.h"
|
|
||||||
#include "llvm/Config/config.h"
|
|
||||||
#include <cstdio>
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Simple buffered I/O
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Empirically, iostream is over 30% slower than stdio for this workload, and
|
|
||||||
// stdio itself isn't very well suited. The problem with stdio is use of
|
|
||||||
// putchar_unlocked. We have many newline characters that need to be emitted,
|
|
||||||
// but stdio needs to do extra checks to handle line buffering mode. These
|
|
||||||
// extra checks make putchar_unlocked fall off its inlined code path, hitting
|
|
||||||
// slow system code. In practice, using 'write' directly makes 'clang -E -P'
|
|
||||||
// about 10% faster than using the stdio path on darwin.
|
|
||||||
|
|
||||||
#ifdef HAVE_UNISTD_H
|
|
||||||
#include <unistd.h>
|
|
||||||
#else
|
|
||||||
#define USE_STDIO 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static char *OutBufStart = 0, *OutBufEnd, *OutBufCur;
|
|
||||||
|
|
||||||
/// InitOutputBuffer - Initialize our output buffer.
|
|
||||||
///
|
|
||||||
static void InitOutputBuffer() {
|
|
||||||
#ifndef USE_STDIO
|
|
||||||
OutBufStart = new char[64*1024];
|
|
||||||
OutBufEnd = OutBufStart+64*1024;
|
|
||||||
OutBufCur = OutBufStart;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/// FlushBuffer - Write the accumulated bytes to the output stream.
|
|
||||||
///
|
|
||||||
static void FlushBuffer() {
|
|
||||||
#ifndef USE_STDIO
|
|
||||||
write(STDOUT_FILENO, OutBufStart, OutBufCur-OutBufStart);
|
|
||||||
OutBufCur = OutBufStart;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/// CleanupOutputBuffer - Finish up output.
|
|
||||||
///
|
|
||||||
static void CleanupOutputBuffer() {
|
|
||||||
#ifndef USE_STDIO
|
|
||||||
FlushBuffer();
|
|
||||||
delete [] OutBufStart;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void OutputChar(char c) {
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
putchar(c);
|
|
||||||
#elif defined(USE_STDIO)
|
|
||||||
putchar_unlocked(c);
|
|
||||||
#else
|
|
||||||
if (OutBufCur >= OutBufEnd)
|
|
||||||
FlushBuffer();
|
|
||||||
*OutBufCur++ = c;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void OutputString(const char *Ptr, unsigned Size) {
|
|
||||||
#ifdef USE_STDIO
|
|
||||||
fwrite(Ptr, Size, 1, stdout);
|
|
||||||
#else
|
|
||||||
if (OutBufCur+Size >= OutBufEnd)
|
|
||||||
FlushBuffer();
|
|
||||||
|
|
||||||
switch (Size) {
|
|
||||||
default:
|
|
||||||
memcpy(OutBufCur, Ptr, Size);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
OutBufCur[2] = Ptr[2];
|
|
||||||
case 2:
|
|
||||||
OutBufCur[1] = Ptr[1];
|
|
||||||
case 1:
|
|
||||||
OutBufCur[0] = Ptr[0];
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
OutBufCur += Size;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Preprocessed token printer
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
DisableLineMarkers("P", llvm::cl::desc("Disable linemarker output in -E mode"));
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
EnableCommentOutput("C", llvm::cl::desc("Enable comment output in -E mode"));
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
EnableMacroCommentOutput("CC",
|
|
||||||
llvm::cl::desc("Enable comment output in -E mode, "
|
|
||||||
"even from macro expansions"));
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class PrintPPOutputPPCallbacks : public PPCallbacks {
|
|
||||||
Preprocessor &PP;
|
|
||||||
unsigned CurLine;
|
|
||||||
bool EmittedTokensOnThisLine;
|
|
||||||
DirectoryLookup::DirType FileType;
|
|
||||||
llvm::SmallString<512> CurFilename;
|
|
||||||
public:
|
|
||||||
PrintPPOutputPPCallbacks(Preprocessor &pp) : PP(pp) {
|
|
||||||
CurLine = 0;
|
|
||||||
CurFilename += "<uninit>";
|
|
||||||
EmittedTokensOnThisLine = false;
|
|
||||||
FileType = DirectoryLookup::NormalHeaderDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
|
|
||||||
bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; }
|
|
||||||
|
|
||||||
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
|
|
||||||
DirectoryLookup::DirType FileType);
|
|
||||||
virtual void Ident(SourceLocation Loc, const std::string &str);
|
|
||||||
|
|
||||||
|
|
||||||
void HandleFirstTokOnLine(Token &Tok);
|
|
||||||
void MoveToLine(SourceLocation Loc);
|
|
||||||
bool AvoidConcat(const Token &PrevTok, const Token &Tok);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// UToStr - Do itoa on the specified number, in-place in the specified buffer.
|
|
||||||
/// endptr points to the end of the buffer.
|
|
||||||
static char *UToStr(unsigned N, char *EndPtr) {
|
|
||||||
// Null terminate the buffer.
|
|
||||||
*--EndPtr = '\0';
|
|
||||||
if (N == 0) // Zero is a special case.
|
|
||||||
*--EndPtr = '0';
|
|
||||||
while (N) {
|
|
||||||
*--EndPtr = '0' + char(N % 10);
|
|
||||||
N /= 10;
|
|
||||||
}
|
|
||||||
return EndPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// MoveToLine - Move the output to the source line specified by the location
|
|
||||||
/// object. We can do this by emitting some number of \n's, or be emitting a
|
|
||||||
/// #line directive.
|
|
||||||
void PrintPPOutputPPCallbacks::MoveToLine(SourceLocation Loc) {
|
|
||||||
if (DisableLineMarkers) {
|
|
||||||
if (EmittedTokensOnThisLine) {
|
|
||||||
OutputChar('\n');
|
|
||||||
EmittedTokensOnThisLine = false;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned LineNo = PP.getSourceManager().getLogicalLineNumber(Loc);
|
|
||||||
|
|
||||||
// If this line is "close enough" to the original line, just print newlines,
|
|
||||||
// otherwise print a #line directive.
|
|
||||||
if (LineNo-CurLine < 8) {
|
|
||||||
if (LineNo-CurLine == 1)
|
|
||||||
OutputChar('\n');
|
|
||||||
else {
|
|
||||||
const char *NewLines = "\n\n\n\n\n\n\n\n";
|
|
||||||
OutputString(NewLines, LineNo-CurLine);
|
|
||||||
CurLine = LineNo;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (EmittedTokensOnThisLine) {
|
|
||||||
OutputChar('\n');
|
|
||||||
EmittedTokensOnThisLine = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurLine = LineNo;
|
|
||||||
|
|
||||||
OutputChar('#');
|
|
||||||
OutputChar(' ');
|
|
||||||
char NumberBuffer[20];
|
|
||||||
const char *NumStr = UToStr(LineNo, NumberBuffer+20);
|
|
||||||
OutputString(NumStr, (NumberBuffer+20)-NumStr-1);
|
|
||||||
OutputChar(' ');
|
|
||||||
OutputChar('"');
|
|
||||||
OutputString(&CurFilename[0], CurFilename.size());
|
|
||||||
OutputChar('"');
|
|
||||||
|
|
||||||
if (FileType == DirectoryLookup::SystemHeaderDir)
|
|
||||||
OutputString(" 3", 2);
|
|
||||||
else if (FileType == DirectoryLookup::ExternCSystemHeaderDir)
|
|
||||||
OutputString(" 3 4", 4);
|
|
||||||
OutputChar('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// FileChanged - Whenever the preprocessor enters or exits a #include file
|
|
||||||
/// it invokes this handler. Update our conception of the current source
|
|
||||||
/// position.
|
|
||||||
void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
|
|
||||||
FileChangeReason Reason,
|
|
||||||
DirectoryLookup::DirType FileType) {
|
|
||||||
if (DisableLineMarkers) return;
|
|
||||||
|
|
||||||
// Unless we are exiting a #include, make sure to skip ahead to the line the
|
|
||||||
// #include directive was at.
|
|
||||||
SourceManager &SourceMgr = PP.getSourceManager();
|
|
||||||
if (Reason == PPCallbacks::EnterFile) {
|
|
||||||
MoveToLine(SourceMgr.getIncludeLoc(Loc));
|
|
||||||
} else if (Reason == PPCallbacks::SystemHeaderPragma) {
|
|
||||||
MoveToLine(Loc);
|
|
||||||
|
|
||||||
// TODO GCC emits the # directive for this directive on the line AFTER the
|
|
||||||
// directive and emits a bunch of spaces that aren't needed. Emulate this
|
|
||||||
// strange behavior.
|
|
||||||
}
|
|
||||||
|
|
||||||
Loc = SourceMgr.getLogicalLoc(Loc);
|
|
||||||
CurLine = SourceMgr.getLineNumber(Loc);
|
|
||||||
CurFilename.clear();
|
|
||||||
CurFilename += SourceMgr.getSourceName(Loc);
|
|
||||||
Lexer::Stringify(CurFilename);
|
|
||||||
FileType = FileType;
|
|
||||||
|
|
||||||
if (EmittedTokensOnThisLine) {
|
|
||||||
OutputChar('\n');
|
|
||||||
EmittedTokensOnThisLine = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputChar('#');
|
|
||||||
OutputChar(' ');
|
|
||||||
|
|
||||||
char NumberBuffer[20];
|
|
||||||
const char *NumStr = UToStr(CurLine, NumberBuffer+20);
|
|
||||||
OutputString(NumStr, (NumberBuffer+20)-NumStr-1);
|
|
||||||
OutputChar(' ');
|
|
||||||
OutputChar('"');
|
|
||||||
OutputString(&CurFilename[0], CurFilename.size());
|
|
||||||
OutputChar('"');
|
|
||||||
|
|
||||||
switch (Reason) {
|
|
||||||
case PPCallbacks::EnterFile:
|
|
||||||
OutputString(" 1", 2);
|
|
||||||
break;
|
|
||||||
case PPCallbacks::ExitFile:
|
|
||||||
OutputString(" 2", 2);
|
|
||||||
break;
|
|
||||||
case PPCallbacks::SystemHeaderPragma: break;
|
|
||||||
case PPCallbacks::RenameFile: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FileType == DirectoryLookup::SystemHeaderDir)
|
|
||||||
OutputString(" 3", 2);
|
|
||||||
else if (FileType == DirectoryLookup::ExternCSystemHeaderDir)
|
|
||||||
OutputString(" 3 4", 4);
|
|
||||||
|
|
||||||
OutputChar('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
/// HandleIdent - Handle #ident directives when read by the preprocessor.
|
|
||||||
///
|
|
||||||
void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
|
|
||||||
MoveToLine(Loc);
|
|
||||||
|
|
||||||
OutputString("#ident ", strlen("#ident "));
|
|
||||||
OutputString(&S[0], S.size());
|
|
||||||
EmittedTokensOnThisLine = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this
|
|
||||||
/// is called for the first token on each new line.
|
|
||||||
void PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
|
|
||||||
// Figure out what line we went to and insert the appropriate number of
|
|
||||||
// newline characters.
|
|
||||||
MoveToLine(Tok.getLocation());
|
|
||||||
|
|
||||||
// Print out space characters so that the first token on a line is
|
|
||||||
// indented for easy reading.
|
|
||||||
const SourceManager &SourceMgr = PP.getSourceManager();
|
|
||||||
unsigned ColNo = SourceMgr.getLogicalColumnNumber(Tok.getLocation());
|
|
||||||
|
|
||||||
// This hack prevents stuff like:
|
|
||||||
// #define HASH #
|
|
||||||
// HASH define foo bar
|
|
||||||
// From having the # character end up at column 1, which makes it so it
|
|
||||||
// is not handled as a #define next time through the preprocessor if in
|
|
||||||
// -fpreprocessed mode.
|
|
||||||
if (ColNo <= 1 && Tok.getKind() == tok::hash)
|
|
||||||
OutputChar(' ');
|
|
||||||
|
|
||||||
// Otherwise, indent the appropriate number of spaces.
|
|
||||||
for (; ColNo > 1; --ColNo)
|
|
||||||
OutputChar(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
struct UnknownPragmaHandler : public PragmaHandler {
|
|
||||||
const char *Prefix;
|
|
||||||
PrintPPOutputPPCallbacks *Callbacks;
|
|
||||||
|
|
||||||
UnknownPragmaHandler(const char *prefix, PrintPPOutputPPCallbacks *callbacks)
|
|
||||||
: PragmaHandler(0), Prefix(prefix), Callbacks(callbacks) {}
|
|
||||||
virtual void HandlePragma(Preprocessor &PP, Token &PragmaTok) {
|
|
||||||
// Figure out what line we went to and insert the appropriate number of
|
|
||||||
// newline characters.
|
|
||||||
Callbacks->MoveToLine(PragmaTok.getLocation());
|
|
||||||
OutputString(Prefix, strlen(Prefix));
|
|
||||||
|
|
||||||
// Read and print all of the pragma tokens.
|
|
||||||
while (PragmaTok.getKind() != tok::eom) {
|
|
||||||
if (PragmaTok.hasLeadingSpace())
|
|
||||||
OutputChar(' ');
|
|
||||||
std::string TokSpell = PP.getSpelling(PragmaTok);
|
|
||||||
OutputString(&TokSpell[0], TokSpell.size());
|
|
||||||
PP.LexUnexpandedToken(PragmaTok);
|
|
||||||
}
|
|
||||||
OutputChar('\n');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
|
|
||||||
enum AvoidConcatInfo {
|
|
||||||
/// By default, a token never needs to avoid concatenation. Most tokens (e.g.
|
|
||||||
/// ',', ')', etc) don't cause a problem when concatenated.
|
|
||||||
aci_never_avoid_concat = 0,
|
|
||||||
|
|
||||||
/// aci_custom_firstchar - AvoidConcat contains custom code to handle this
|
|
||||||
/// token's requirements, and it needs to know the first character of the
|
|
||||||
/// token.
|
|
||||||
aci_custom_firstchar = 1,
|
|
||||||
|
|
||||||
/// aci_custom - AvoidConcat contains custom code to handle this token's
|
|
||||||
/// requirements, but it doesn't need to know the first character of the
|
|
||||||
/// token.
|
|
||||||
aci_custom = 2,
|
|
||||||
|
|
||||||
/// aci_avoid_equal - Many tokens cannot be safely followed by an '='
|
|
||||||
/// character. For example, "<<" turns into "<<=" when followed by an =.
|
|
||||||
aci_avoid_equal = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
/// This array contains information for each token on what action to take when
|
|
||||||
/// avoiding concatenation of tokens in the AvoidConcat method.
|
|
||||||
static char TokenInfo[tok::NUM_TOKENS];
|
|
||||||
|
|
||||||
/// InitAvoidConcatTokenInfo - Tokens that must avoid concatenation should be
|
|
||||||
/// marked by this function.
|
|
||||||
static void InitAvoidConcatTokenInfo() {
|
|
||||||
// These tokens have custom code in AvoidConcat.
|
|
||||||
TokenInfo[tok::identifier ] |= aci_custom;
|
|
||||||
TokenInfo[tok::numeric_constant] |= aci_custom_firstchar;
|
|
||||||
TokenInfo[tok::period ] |= aci_custom_firstchar;
|
|
||||||
TokenInfo[tok::amp ] |= aci_custom_firstchar;
|
|
||||||
TokenInfo[tok::plus ] |= aci_custom_firstchar;
|
|
||||||
TokenInfo[tok::minus ] |= aci_custom_firstchar;
|
|
||||||
TokenInfo[tok::slash ] |= aci_custom_firstchar;
|
|
||||||
TokenInfo[tok::less ] |= aci_custom_firstchar;
|
|
||||||
TokenInfo[tok::greater ] |= aci_custom_firstchar;
|
|
||||||
TokenInfo[tok::pipe ] |= aci_custom_firstchar;
|
|
||||||
TokenInfo[tok::percent ] |= aci_custom_firstchar;
|
|
||||||
TokenInfo[tok::colon ] |= aci_custom_firstchar;
|
|
||||||
TokenInfo[tok::hash ] |= aci_custom_firstchar;
|
|
||||||
TokenInfo[tok::arrow ] |= aci_custom_firstchar;
|
|
||||||
|
|
||||||
// These tokens change behavior if followed by an '='.
|
|
||||||
TokenInfo[tok::amp ] |= aci_avoid_equal; // &=
|
|
||||||
TokenInfo[tok::plus ] |= aci_avoid_equal; // +=
|
|
||||||
TokenInfo[tok::minus ] |= aci_avoid_equal; // -=
|
|
||||||
TokenInfo[tok::slash ] |= aci_avoid_equal; // /=
|
|
||||||
TokenInfo[tok::less ] |= aci_avoid_equal; // <=
|
|
||||||
TokenInfo[tok::greater ] |= aci_avoid_equal; // >=
|
|
||||||
TokenInfo[tok::pipe ] |= aci_avoid_equal; // |=
|
|
||||||
TokenInfo[tok::percent ] |= aci_avoid_equal; // %=
|
|
||||||
TokenInfo[tok::star ] |= aci_avoid_equal; // *=
|
|
||||||
TokenInfo[tok::exclaim ] |= aci_avoid_equal; // !=
|
|
||||||
TokenInfo[tok::lessless ] |= aci_avoid_equal; // <<=
|
|
||||||
TokenInfo[tok::greaterequal] |= aci_avoid_equal; // >>=
|
|
||||||
TokenInfo[tok::caret ] |= aci_avoid_equal; // ^=
|
|
||||||
TokenInfo[tok::equal ] |= aci_avoid_equal; // ==
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AvoidConcat - If printing PrevTok immediately followed by Tok would cause
|
|
||||||
/// the two individual tokens to be lexed as a single token, return true (which
|
|
||||||
/// causes a space to be printed between them). This allows the output of -E
|
|
||||||
/// mode to be lexed to the same token stream as lexing the input directly
|
|
||||||
/// would.
|
|
||||||
///
|
|
||||||
/// This code must conservatively return true if it doesn't want to be 100%
|
|
||||||
/// accurate. This will cause the output to include extra space characters, but
|
|
||||||
/// the resulting output won't have incorrect concatenations going on. Examples
|
|
||||||
/// include "..", which we print with a space between, because we don't want to
|
|
||||||
/// track enough to tell "x.." from "...".
|
|
||||||
bool PrintPPOutputPPCallbacks::AvoidConcat(const Token &PrevTok,
|
|
||||||
const Token &Tok) {
|
|
||||||
char Buffer[256];
|
|
||||||
|
|
||||||
tok::TokenKind PrevKind = PrevTok.getKind();
|
|
||||||
if (PrevTok.getIdentifierInfo()) // Language keyword or named operator.
|
|
||||||
PrevKind = tok::identifier;
|
|
||||||
|
|
||||||
// Look up information on when we should avoid concatenation with prevtok.
|
|
||||||
unsigned ConcatInfo = TokenInfo[PrevKind];
|
|
||||||
|
|
||||||
// If prevtok never causes a problem for anything after it, return quickly.
|
|
||||||
if (ConcatInfo == 0) return false;
|
|
||||||
|
|
||||||
if (ConcatInfo & aci_avoid_equal) {
|
|
||||||
// If the next token is '=' or '==', avoid concatenation.
|
|
||||||
if (Tok.getKind() == tok::equal ||
|
|
||||||
Tok.getKind() == tok::equalequal)
|
|
||||||
return true;
|
|
||||||
ConcatInfo &= ~aci_avoid_equal;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ConcatInfo == 0) return false;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Basic algorithm: we look at the first character of the second token, and
|
|
||||||
// determine whether it, if appended to the first token, would form (or would
|
|
||||||
// contribute) to a larger token if concatenated.
|
|
||||||
char FirstChar = 0;
|
|
||||||
if (ConcatInfo & aci_custom) {
|
|
||||||
// If the token does not need to know the first character, don't get it.
|
|
||||||
} else if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
|
|
||||||
// Avoid spelling identifiers, the most common form of token.
|
|
||||||
FirstChar = II->getName()[0];
|
|
||||||
} else if (!Tok.needsCleaning()) {
|
|
||||||
SourceManager &SrcMgr = PP.getSourceManager();
|
|
||||||
FirstChar =
|
|
||||||
*SrcMgr.getCharacterData(SrcMgr.getPhysicalLoc(Tok.getLocation()));
|
|
||||||
} else if (Tok.getLength() < 256) {
|
|
||||||
const char *TokPtr = Buffer;
|
|
||||||
PP.getSpelling(Tok, TokPtr);
|
|
||||||
FirstChar = TokPtr[0];
|
|
||||||
} else {
|
|
||||||
FirstChar = PP.getSpelling(Tok)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (PrevKind) {
|
|
||||||
default: assert(0 && "InitAvoidConcatTokenInfo built wrong");
|
|
||||||
case tok::identifier: // id+id or id+number or id+L"foo".
|
|
||||||
if (Tok.getKind() == tok::numeric_constant || Tok.getIdentifierInfo() ||
|
|
||||||
Tok.getKind() == tok::wide_string_literal /* ||
|
|
||||||
Tok.getKind() == tok::wide_char_literal*/)
|
|
||||||
return true;
|
|
||||||
if (Tok.getKind() != tok::char_constant)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// FIXME: need a wide_char_constant!
|
|
||||||
if (!Tok.needsCleaning()) {
|
|
||||||
SourceManager &SrcMgr = PP.getSourceManager();
|
|
||||||
return *SrcMgr.getCharacterData(SrcMgr.getPhysicalLoc(Tok.getLocation()))
|
|
||||||
== 'L';
|
|
||||||
} else if (Tok.getLength() < 256) {
|
|
||||||
const char *TokPtr = Buffer;
|
|
||||||
PP.getSpelling(Tok, TokPtr);
|
|
||||||
return TokPtr[0] == 'L';
|
|
||||||
} else {
|
|
||||||
return PP.getSpelling(Tok)[0] == 'L';
|
|
||||||
}
|
|
||||||
case tok::numeric_constant:
|
|
||||||
return isalnum(FirstChar) || Tok.getKind() == tok::numeric_constant ||
|
|
||||||
FirstChar == '+' || FirstChar == '-' || FirstChar == '.';
|
|
||||||
case tok::period: // ..., .*, .1234
|
|
||||||
return FirstChar == '.' || FirstChar == '*' || isdigit(FirstChar);
|
|
||||||
case tok::amp: // &&
|
|
||||||
return FirstChar == '&';
|
|
||||||
case tok::plus: // ++
|
|
||||||
return FirstChar == '+';
|
|
||||||
case tok::minus: // --, ->, ->*
|
|
||||||
return FirstChar == '-' || FirstChar == '>';
|
|
||||||
case tok::slash: //, /*, //
|
|
||||||
return FirstChar == '*' || FirstChar == '/';
|
|
||||||
case tok::less: // <<, <<=, <:, <%
|
|
||||||
return FirstChar == '<' || FirstChar == ':' || FirstChar == '%';
|
|
||||||
case tok::greater: // >>, >>=
|
|
||||||
return FirstChar == '>';
|
|
||||||
case tok::pipe: // ||
|
|
||||||
return FirstChar == '|';
|
|
||||||
case tok::percent: // %>, %:
|
|
||||||
return FirstChar == '>' || FirstChar == ':';
|
|
||||||
case tok::colon: // ::, :>
|
|
||||||
return FirstChar == ':' || FirstChar == '>';
|
|
||||||
case tok::hash: // ##, #@, %:%:
|
|
||||||
return FirstChar == '#' || FirstChar == '@' || FirstChar == '%';
|
|
||||||
case tok::arrow: // ->*
|
|
||||||
return FirstChar == '*';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// DoPrintPreprocessedInput - This implements -E mode.
|
|
||||||
///
|
|
||||||
void clang::DoPrintPreprocessedInput(unsigned MainFileID, Preprocessor &PP,
|
|
||||||
const LangOptions &Options) {
|
|
||||||
// Inform the preprocessor whether we want it to retain comments or not, due
|
|
||||||
// to -C or -CC.
|
|
||||||
PP.SetCommentRetentionState(EnableCommentOutput, EnableMacroCommentOutput);
|
|
||||||
|
|
||||||
InitOutputBuffer();
|
|
||||||
InitAvoidConcatTokenInfo();
|
|
||||||
|
|
||||||
Token Tok, PrevTok;
|
|
||||||
char Buffer[256];
|
|
||||||
PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks(PP);
|
|
||||||
PP.setPPCallbacks(Callbacks);
|
|
||||||
|
|
||||||
PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks));
|
|
||||||
PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",Callbacks));
|
|
||||||
|
|
||||||
// After we have configured the preprocessor, enter the main file.
|
|
||||||
|
|
||||||
// Start parsing the specified input file.
|
|
||||||
PP.EnterSourceFile(MainFileID, 0, true);
|
|
||||||
|
|
||||||
do {
|
|
||||||
PrevTok = Tok;
|
|
||||||
PP.Lex(Tok);
|
|
||||||
|
|
||||||
// If this token is at the start of a line, emit newlines if needed.
|
|
||||||
if (Tok.isAtStartOfLine()) {
|
|
||||||
Callbacks->HandleFirstTokOnLine(Tok);
|
|
||||||
} else if (Tok.hasLeadingSpace() ||
|
|
||||||
// If we haven't emitted a token on this line yet, PrevTok isn't
|
|
||||||
// useful to look at and no concatenation could happen anyway.
|
|
||||||
(Callbacks->hasEmittedTokensOnThisLine() &&
|
|
||||||
// Don't print "-" next to "-", it would form "--".
|
|
||||||
Callbacks->AvoidConcat(PrevTok, Tok))) {
|
|
||||||
OutputChar(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
|
|
||||||
const char *Str = II->getName();
|
|
||||||
unsigned Len = Tok.needsCleaning() ? strlen(Str) : Tok.getLength();
|
|
||||||
OutputString(Str, Len);
|
|
||||||
} else if (Tok.getLength() < 256) {
|
|
||||||
const char *TokPtr = Buffer;
|
|
||||||
unsigned Len = PP.getSpelling(Tok, TokPtr);
|
|
||||||
OutputString(TokPtr, Len);
|
|
||||||
} else {
|
|
||||||
std::string S = PP.getSpelling(Tok);
|
|
||||||
OutputString(&S[0], S.size());
|
|
||||||
}
|
|
||||||
Callbacks->SetEmittedTokensOnThisLine();
|
|
||||||
} while (Tok.getKind() != tok::eof);
|
|
||||||
OutputChar('\n');
|
|
||||||
|
|
||||||
CleanupOutputBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,444 +0,0 @@
|
|||||||
//===--- Targets.cpp - Implement -arch option and targets -----------------===//
|
|
||||||
//
|
|
||||||
// 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 -arch command line option and creates a TargetInfo
|
|
||||||
// that represents them.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang.h"
|
|
||||||
#include "clang/AST/Builtins.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "clang/Basic/TargetInfo.h"
|
|
||||||
#include "llvm/Support/CommandLine.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
/// Note: a hard coded list of targets is clearly silly, these should be
|
|
||||||
/// dynamicly registered and loadable with "-load".
|
|
||||||
enum SupportedTargets {
|
|
||||||
target_ppc, target_ppc64,
|
|
||||||
target_i386, target_x86_64,
|
|
||||||
target_linux_i386
|
|
||||||
};
|
|
||||||
|
|
||||||
static llvm::cl::list<SupportedTargets>
|
|
||||||
Archs("arch", llvm::cl::desc("Architectures to compile for"),
|
|
||||||
llvm::cl::values(clEnumValN(target_ppc, "ppc", "32-bit Darwin PowerPC"),
|
|
||||||
clEnumValN(target_ppc64, "ppc64", "64-bit Darwin PowerPC"),
|
|
||||||
clEnumValN(target_i386, "i386", "32-bit Darwin X86"),
|
|
||||||
clEnumValN(target_x86_64, "x86_64","64-bit Darwin X86"),
|
|
||||||
clEnumValN(target_linux_i386,"linux", "Linux i386"),
|
|
||||||
clEnumValEnd));
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Common code shared among targets.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class DarwinTargetInfo : public TargetInfoImpl {
|
|
||||||
public:
|
|
||||||
virtual void getTargetDefines(std::vector<std::string> &Defines) const {
|
|
||||||
Defines.push_back("__APPLE__=1");
|
|
||||||
Defines.push_back("__MACH__=1");
|
|
||||||
|
|
||||||
if (1) {// -fobjc-gc controls this.
|
|
||||||
Defines.push_back("__weak=");
|
|
||||||
Defines.push_back("__strong=");
|
|
||||||
} else {
|
|
||||||
Defines.push_back("__weak=__attribute__((objc_gc(weak)))");
|
|
||||||
Defines.push_back("__strong=__attribute__((objc_gc(strong)))");
|
|
||||||
Defines.push_back("__OBJC_GC__");
|
|
||||||
}
|
|
||||||
|
|
||||||
// darwin_constant_cfstrings controls this.
|
|
||||||
Defines.push_back("__CONSTANT_CFSTRINGS__=1");
|
|
||||||
|
|
||||||
if (0) // darwin_pascal_strings
|
|
||||||
Defines.push_back("__PASCAL_STRINGS__");
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
} // end anonymous namespace.
|
|
||||||
|
|
||||||
|
|
||||||
/// getPowerPCDefines - Return a set of the PowerPC-specific #defines that are
|
|
||||||
/// not tied to a specific subtarget.
|
|
||||||
static void getPowerPCDefines(std::vector<std::string> &Defines, bool is64Bit) {
|
|
||||||
// Target identification.
|
|
||||||
Defines.push_back("__ppc__");
|
|
||||||
Defines.push_back("_ARCH_PPC=1");
|
|
||||||
Defines.push_back("__POWERPC__=1");
|
|
||||||
if (is64Bit) {
|
|
||||||
Defines.push_back("_ARCH_PPC64");
|
|
||||||
Defines.push_back("_LP64");
|
|
||||||
Defines.push_back("__LP64__");
|
|
||||||
Defines.push_back("__ppc64__");
|
|
||||||
} else {
|
|
||||||
Defines.push_back("__ppc__=1");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Target properties.
|
|
||||||
Defines.push_back("_BIG_ENDIAN=1");
|
|
||||||
Defines.push_back("__BIG_ENDIAN__=1");
|
|
||||||
|
|
||||||
if (is64Bit) {
|
|
||||||
Defines.push_back("__INTMAX_MAX__=9223372036854775807L");
|
|
||||||
Defines.push_back("__INTMAX_TYPE__=long int");
|
|
||||||
Defines.push_back("__LONG_MAX__=9223372036854775807L");
|
|
||||||
Defines.push_back("__PTRDIFF_TYPE__=long int");
|
|
||||||
Defines.push_back("__UINTMAX_TYPE__=long unsigned int");
|
|
||||||
} else {
|
|
||||||
Defines.push_back("__INTMAX_MAX__=9223372036854775807LL");
|
|
||||||
Defines.push_back("__INTMAX_TYPE__=long long int");
|
|
||||||
Defines.push_back("__LONG_MAX__=2147483647L");
|
|
||||||
Defines.push_back("__PTRDIFF_TYPE__=int");
|
|
||||||
Defines.push_back("__UINTMAX_TYPE__=long long unsigned int");
|
|
||||||
}
|
|
||||||
Defines.push_back("__INT_MAX__=2147483647");
|
|
||||||
Defines.push_back("__LONG_LONG_MAX__=9223372036854775807LL");
|
|
||||||
Defines.push_back("__CHAR_BIT__=8");
|
|
||||||
Defines.push_back("__SCHAR_MAX__=127");
|
|
||||||
Defines.push_back("__SHRT_MAX__=32767");
|
|
||||||
Defines.push_back("__SIZE_TYPE__=long unsigned int");
|
|
||||||
|
|
||||||
// Subtarget options.
|
|
||||||
Defines.push_back("__USER_LABEL_PREFIX__=_");
|
|
||||||
Defines.push_back("__NATURAL_ALIGNMENT__=1");
|
|
||||||
Defines.push_back("__REGISTER_PREFIX__=");
|
|
||||||
|
|
||||||
Defines.push_back("__WCHAR_MAX__=2147483647");
|
|
||||||
Defines.push_back("__WCHAR_TYPE__=int");
|
|
||||||
Defines.push_back("__WINT_TYPE__=int");
|
|
||||||
|
|
||||||
// Float macros.
|
|
||||||
Defines.push_back("__FLT_DENORM_MIN__=1.40129846e-45F");
|
|
||||||
Defines.push_back("__FLT_DIG__=6");
|
|
||||||
Defines.push_back("__FLT_EPSILON__=1.19209290e-7F");
|
|
||||||
Defines.push_back("__FLT_EVAL_METHOD__=0");
|
|
||||||
Defines.push_back("__FLT_HAS_INFINITY__=1");
|
|
||||||
Defines.push_back("__FLT_HAS_QUIET_NAN__=1");
|
|
||||||
Defines.push_back("__FLT_MANT_DIG__=24");
|
|
||||||
Defines.push_back("__FLT_MAX_10_EXP__=38");
|
|
||||||
Defines.push_back("__FLT_MAX_EXP__=128");
|
|
||||||
Defines.push_back("__FLT_MAX__=3.40282347e+38F");
|
|
||||||
Defines.push_back("__FLT_MIN_10_EXP__=(-37)");
|
|
||||||
Defines.push_back("__FLT_MIN_EXP__=(-125)");
|
|
||||||
Defines.push_back("__FLT_MIN__=1.17549435e-38F");
|
|
||||||
Defines.push_back("__FLT_RADIX__=2");
|
|
||||||
|
|
||||||
// double macros.
|
|
||||||
Defines.push_back("__DBL_DENORM_MIN__=4.9406564584124654e-324");
|
|
||||||
Defines.push_back("__DBL_DIG__=15");
|
|
||||||
Defines.push_back("__DBL_EPSILON__=2.2204460492503131e-16");
|
|
||||||
Defines.push_back("__DBL_HAS_INFINITY__=1");
|
|
||||||
Defines.push_back("__DBL_HAS_QUIET_NAN__=1");
|
|
||||||
Defines.push_back("__DBL_MANT_DIG__=53");
|
|
||||||
Defines.push_back("__DBL_MAX_10_EXP__=308");
|
|
||||||
Defines.push_back("__DBL_MAX_EXP__=1024");
|
|
||||||
Defines.push_back("__DBL_MAX__=1.7976931348623157e+308");
|
|
||||||
Defines.push_back("__DBL_MIN_10_EXP__=(-307)");
|
|
||||||
Defines.push_back("__DBL_MIN_EXP__=(-1021)");
|
|
||||||
Defines.push_back("__DBL_MIN__=2.2250738585072014e-308");
|
|
||||||
Defines.push_back("__DECIMAL_DIG__=33");
|
|
||||||
|
|
||||||
// 128-bit long double macros.
|
|
||||||
Defines.push_back("__LDBL_DENORM_MIN__=4.940656458412465441765687"
|
|
||||||
"92868221e-324L");
|
|
||||||
Defines.push_back("__LDBL_DIG__=31");
|
|
||||||
Defines.push_back("__LDBL_EPSILON__=4.9406564584124654417656879286822"
|
|
||||||
"1e-324L");
|
|
||||||
Defines.push_back("__LDBL_HAS_INFINITY__=1");
|
|
||||||
Defines.push_back("__LDBL_HAS_QUIET_NAN__=1");
|
|
||||||
Defines.push_back("__LDBL_MANT_DIG__=106");
|
|
||||||
Defines.push_back("__LDBL_MAX_10_EXP__=308");
|
|
||||||
Defines.push_back("__LDBL_MAX_EXP__=1024");
|
|
||||||
Defines.push_back("__LDBL_MAX__=1.7976931348623158079372897140"
|
|
||||||
"5301e+308L");
|
|
||||||
Defines.push_back("__LDBL_MIN_10_EXP__=(-291)");
|
|
||||||
Defines.push_back("__LDBL_MIN_EXP__=(-968)");
|
|
||||||
Defines.push_back("__LDBL_MIN__=2.004168360008972777996108051350"
|
|
||||||
"16e-292L");
|
|
||||||
Defines.push_back("__LONG_DOUBLE_128__=1");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getX86Defines - Return a set of the X86-specific #defines that are
|
|
||||||
/// not tied to a specific subtarget.
|
|
||||||
static void getX86Defines(std::vector<std::string> &Defines, bool is64Bit) {
|
|
||||||
// Target identification.
|
|
||||||
if (is64Bit) {
|
|
||||||
Defines.push_back("_LP64");
|
|
||||||
Defines.push_back("__LP64__");
|
|
||||||
Defines.push_back("__amd64__");
|
|
||||||
Defines.push_back("__amd64");
|
|
||||||
Defines.push_back("__x86_64");
|
|
||||||
Defines.push_back("__x86_64__");
|
|
||||||
} else {
|
|
||||||
Defines.push_back("__i386__=1");
|
|
||||||
Defines.push_back("__i386=1");
|
|
||||||
Defines.push_back("i386=1");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Target properties.
|
|
||||||
Defines.push_back("__LITTLE_ENDIAN__=1");
|
|
||||||
|
|
||||||
if (is64Bit) {
|
|
||||||
Defines.push_back("__INTMAX_MAX__=9223372036854775807L");
|
|
||||||
Defines.push_back("__INTMAX_TYPE__=long int");
|
|
||||||
Defines.push_back("__LONG_MAX__=9223372036854775807L");
|
|
||||||
Defines.push_back("__PTRDIFF_TYPE__=long int");
|
|
||||||
Defines.push_back("__UINTMAX_TYPE__=long unsigned int");
|
|
||||||
} else {
|
|
||||||
Defines.push_back("__INTMAX_MAX__=9223372036854775807LL");
|
|
||||||
Defines.push_back("__INTMAX_TYPE__=long long int");
|
|
||||||
Defines.push_back("__LONG_MAX__=2147483647L");
|
|
||||||
Defines.push_back("__PTRDIFF_TYPE__=int");
|
|
||||||
Defines.push_back("__UINTMAX_TYPE__=long long unsigned int");
|
|
||||||
}
|
|
||||||
Defines.push_back("__CHAR_BIT__=8");
|
|
||||||
Defines.push_back("__INT_MAX__=2147483647");
|
|
||||||
Defines.push_back("__LONG_LONG_MAX__=9223372036854775807LL");
|
|
||||||
Defines.push_back("__SCHAR_MAX__=127");
|
|
||||||
Defines.push_back("__SHRT_MAX__=32767");
|
|
||||||
Defines.push_back("__SIZE_TYPE__=long unsigned int");
|
|
||||||
|
|
||||||
// Subtarget options.
|
|
||||||
Defines.push_back("__nocona=1");
|
|
||||||
Defines.push_back("__nocona__=1");
|
|
||||||
Defines.push_back("__tune_nocona__=1");
|
|
||||||
Defines.push_back("__SSE2_MATH__=1");
|
|
||||||
Defines.push_back("__SSE2__=1");
|
|
||||||
Defines.push_back("__SSE_MATH__=1");
|
|
||||||
Defines.push_back("__SSE__=1");
|
|
||||||
Defines.push_back("__MMX__=1");
|
|
||||||
Defines.push_back("__REGISTER_PREFIX__=");
|
|
||||||
|
|
||||||
Defines.push_back("__WCHAR_MAX__=2147483647");
|
|
||||||
Defines.push_back("__WCHAR_TYPE__=int");
|
|
||||||
Defines.push_back("__WINT_TYPE__=int");
|
|
||||||
|
|
||||||
// Float macros.
|
|
||||||
Defines.push_back("__FLT_DENORM_MIN__=1.40129846e-45F");
|
|
||||||
Defines.push_back("__FLT_DIG__=6");
|
|
||||||
Defines.push_back("__FLT_EPSILON__=1.19209290e-7F");
|
|
||||||
Defines.push_back("__FLT_EVAL_METHOD__=0");
|
|
||||||
Defines.push_back("__FLT_HAS_INFINITY__=1");
|
|
||||||
Defines.push_back("__FLT_HAS_QUIET_NAN__=1");
|
|
||||||
Defines.push_back("__FLT_MANT_DIG__=24");
|
|
||||||
Defines.push_back("__FLT_MAX_10_EXP__=38");
|
|
||||||
Defines.push_back("__FLT_MAX_EXP__=128");
|
|
||||||
Defines.push_back("__FLT_MAX__=3.40282347e+38F");
|
|
||||||
Defines.push_back("__FLT_MIN_10_EXP__=(-37)");
|
|
||||||
Defines.push_back("__FLT_MIN_EXP__=(-125)");
|
|
||||||
Defines.push_back("__FLT_MIN__=1.17549435e-38F");
|
|
||||||
Defines.push_back("__FLT_RADIX__=2");
|
|
||||||
|
|
||||||
// Double macros.
|
|
||||||
Defines.push_back("__DBL_DENORM_MIN__=4.9406564584124654e-324");
|
|
||||||
Defines.push_back("__DBL_DIG__=15");
|
|
||||||
Defines.push_back("__DBL_EPSILON__=2.2204460492503131e-16");
|
|
||||||
Defines.push_back("__DBL_HAS_INFINITY__=1");
|
|
||||||
Defines.push_back("__DBL_HAS_QUIET_NAN__=1");
|
|
||||||
Defines.push_back("__DBL_MANT_DIG__=53");
|
|
||||||
Defines.push_back("__DBL_MAX_10_EXP__=308");
|
|
||||||
Defines.push_back("__DBL_MAX_EXP__=1024");
|
|
||||||
Defines.push_back("__DBL_MAX__=1.7976931348623157e+308");
|
|
||||||
Defines.push_back("__DBL_MIN_10_EXP__=(-307)");
|
|
||||||
Defines.push_back("__DBL_MIN_EXP__=(-1021)");
|
|
||||||
Defines.push_back("__DBL_MIN__=2.2250738585072014e-308");
|
|
||||||
Defines.push_back("__DECIMAL_DIG__=21");
|
|
||||||
|
|
||||||
// 80-bit Long double macros.
|
|
||||||
Defines.push_back("__LDBL_DENORM_MIN__=3.64519953188247460253e-4951L");
|
|
||||||
Defines.push_back("__LDBL_DIG__=18");
|
|
||||||
Defines.push_back("__LDBL_EPSILON__=1.08420217248550443401e-19L");
|
|
||||||
Defines.push_back("__LDBL_HAS_INFINITY__=1");
|
|
||||||
Defines.push_back("__LDBL_HAS_QUIET_NAN__=1");
|
|
||||||
Defines.push_back("__LDBL_MANT_DIG__=64");
|
|
||||||
Defines.push_back("__LDBL_MAX_10_EXP__=4932");
|
|
||||||
Defines.push_back("__LDBL_MAX_EXP__=16384");
|
|
||||||
Defines.push_back("__LDBL_MAX__=1.18973149535723176502e+4932L");
|
|
||||||
Defines.push_back("__LDBL_MIN_10_EXP__=(-4931)");
|
|
||||||
Defines.push_back("__LDBL_MIN_EXP__=(-16381)");
|
|
||||||
Defines.push_back("__LDBL_MIN__=3.36210314311209350626e-4932L");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PPC builtin info.
|
|
||||||
namespace PPC {
|
|
||||||
enum {
|
|
||||||
LastTIBuiltin = Builtin::FirstTSBuiltin-1,
|
|
||||||
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
|
|
||||||
#include "PPCBuiltins.def"
|
|
||||||
LastTSBuiltin
|
|
||||||
};
|
|
||||||
|
|
||||||
static const Builtin::Info BuiltinInfo[] = {
|
|
||||||
#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS },
|
|
||||||
#include "PPCBuiltins.def"
|
|
||||||
};
|
|
||||||
|
|
||||||
static void getBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) {
|
|
||||||
Records = BuiltinInfo;
|
|
||||||
NumRecords = LastTSBuiltin-Builtin::FirstTSBuiltin;
|
|
||||||
}
|
|
||||||
} // End namespace PPC
|
|
||||||
|
|
||||||
|
|
||||||
/// X86 builtin info.
|
|
||||||
namespace X86 {
|
|
||||||
enum {
|
|
||||||
LastTIBuiltin = Builtin::FirstTSBuiltin-1,
|
|
||||||
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
|
|
||||||
#include "X86Builtins.def"
|
|
||||||
LastTSBuiltin
|
|
||||||
};
|
|
||||||
|
|
||||||
static const Builtin::Info BuiltinInfo[] = {
|
|
||||||
#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS },
|
|
||||||
#include "X86Builtins.def"
|
|
||||||
};
|
|
||||||
|
|
||||||
static void getBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) {
|
|
||||||
Records = BuiltinInfo;
|
|
||||||
NumRecords = LastTSBuiltin-Builtin::FirstTSBuiltin;
|
|
||||||
}
|
|
||||||
} // End namespace X86
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Specific target implementations.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class DarwinPPCTargetInfo : public DarwinTargetInfo {
|
|
||||||
public:
|
|
||||||
virtual void getTargetDefines(std::vector<std::string> &Defines) const {
|
|
||||||
DarwinTargetInfo::getTargetDefines(Defines);
|
|
||||||
getPowerPCDefines(Defines, false);
|
|
||||||
}
|
|
||||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
|
||||||
unsigned &NumRecords) const {
|
|
||||||
PPC::getBuiltins(Records, NumRecords);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // end anonymous namespace.
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class DarwinPPC64TargetInfo : public DarwinTargetInfo {
|
|
||||||
public:
|
|
||||||
virtual void getTargetDefines(std::vector<std::string> &Defines) const {
|
|
||||||
DarwinTargetInfo::getTargetDefines(Defines);
|
|
||||||
getPowerPCDefines(Defines, true);
|
|
||||||
}
|
|
||||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
|
||||||
unsigned &NumRecords) const {
|
|
||||||
PPC::getBuiltins(Records, NumRecords);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // end anonymous namespace.
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class DarwinI386TargetInfo : public DarwinTargetInfo {
|
|
||||||
public:
|
|
||||||
virtual void getTargetDefines(std::vector<std::string> &Defines) const {
|
|
||||||
DarwinTargetInfo::getTargetDefines(Defines);
|
|
||||||
getX86Defines(Defines, false);
|
|
||||||
}
|
|
||||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
|
||||||
unsigned &NumRecords) const {
|
|
||||||
X86::getBuiltins(Records, NumRecords);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // end anonymous namespace.
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class DarwinX86_64TargetInfo : public DarwinTargetInfo {
|
|
||||||
public:
|
|
||||||
virtual void getTargetDefines(std::vector<std::string> &Defines) const {
|
|
||||||
DarwinTargetInfo::getTargetDefines(Defines);
|
|
||||||
getX86Defines(Defines, true);
|
|
||||||
}
|
|
||||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
|
||||||
unsigned &NumRecords) const {
|
|
||||||
X86::getBuiltins(Records, NumRecords);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // end anonymous namespace.
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class LinuxTargetInfo : public DarwinTargetInfo {
|
|
||||||
public:
|
|
||||||
LinuxTargetInfo() {
|
|
||||||
// Note: I have no idea if this is right, just for testing.
|
|
||||||
WCharWidth = 16;
|
|
||||||
WCharAlign = 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void getTargetDefines(std::vector<std::string> &Defines) const {
|
|
||||||
// TODO: linux-specific stuff.
|
|
||||||
getX86Defines(Defines, false);
|
|
||||||
}
|
|
||||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
|
||||||
unsigned &NumRecords) const {
|
|
||||||
X86::getBuiltins(Records, NumRecords);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // end anonymous namespace.
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Driver code
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// CreateTarget - Create the TargetInfoImpl object for the specified target
|
|
||||||
/// enum value.
|
|
||||||
static TargetInfoImpl *CreateTarget(SupportedTargets T) {
|
|
||||||
switch (T) {
|
|
||||||
default: assert(0 && "Unknown target!");
|
|
||||||
case target_ppc: return new DarwinPPCTargetInfo();
|
|
||||||
case target_ppc64: return new DarwinPPC64TargetInfo();
|
|
||||||
case target_i386: return new DarwinI386TargetInfo();
|
|
||||||
case target_x86_64: return new DarwinX86_64TargetInfo();
|
|
||||||
case target_linux_i386: return new LinuxTargetInfo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// CreateTargetInfo - Return the set of target info objects as specified by
|
|
||||||
/// the -arch command line option.
|
|
||||||
TargetInfo *clang::CreateTargetInfo(Diagnostic &Diags) {
|
|
||||||
// If the user didn't specify at least one architecture, auto-sense the
|
|
||||||
// current host. TODO: This is a hack. :)
|
|
||||||
if (Archs.empty()) {
|
|
||||||
#ifndef __APPLE__
|
|
||||||
// Assume non-apple = i386 for now.
|
|
||||||
Archs.push_back(target_i386);
|
|
||||||
#elif (defined(__POWERPC__) || defined (__ppc__) || defined(_POWER)) && \
|
|
||||||
defined(__ppc64__)
|
|
||||||
Archs.push_back(target_ppc64);
|
|
||||||
#elif defined(__POWERPC__) || defined (__ppc__) || defined(_POWER)
|
|
||||||
Archs.push_back(target_ppc);
|
|
||||||
#elif defined(__x86_64__)
|
|
||||||
Archs.push_back(target_x86_64);
|
|
||||||
#elif defined(__i386__) || defined(i386) || defined(_M_IX86)
|
|
||||||
Archs.push_back(target_i386);
|
|
||||||
#else
|
|
||||||
// Don't know what this is!
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the primary target and target info.
|
|
||||||
TargetInfo *TI = new TargetInfo(CreateTarget(Archs[0]), &Diags);
|
|
||||||
|
|
||||||
// Add all secondary targets.
|
|
||||||
for (unsigned i = 1, e = Archs.size(); i != e; ++i)
|
|
||||||
TI->AddSecondaryTarget(CreateTarget(Archs[i]));
|
|
||||||
return TI;
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
//===--- TextDiagnosticBuffer.cpp - Buffer Text Diagnostics ---------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Bill Wendling and is distributed under the
|
|
||||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This is a concrete diagnostic client, which buffers the diagnostic messages.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "TextDiagnosticBuffer.h"
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
/// HandleDiagnostic - Store the errors & warnings that are reported.
|
|
||||||
///
|
|
||||||
void TextDiagnosticBuffer::HandleDiagnostic(Diagnostic::Level Level,
|
|
||||||
SourceLocation Pos,
|
|
||||||
diag::kind ID,
|
|
||||||
const std::string *Strs,
|
|
||||||
unsigned NumStrs,
|
|
||||||
const SourceRange *,
|
|
||||||
unsigned) {
|
|
||||||
switch (Level) {
|
|
||||||
default: assert(0 && "Diagnostic not handled during diagnostic buffering!");
|
|
||||||
case Diagnostic::Warning:
|
|
||||||
Warnings.push_back(std::make_pair(Pos, FormatDiagnostic(Level, ID, Strs,
|
|
||||||
NumStrs)));
|
|
||||||
break;
|
|
||||||
case Diagnostic::Error:
|
|
||||||
Errors.push_back(std::make_pair(Pos, FormatDiagnostic(Level, ID, Strs,
|
|
||||||
NumStrs)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
//===--- TextDiagnosticBuffer.h - Buffer Text Diagnostics -------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Bill Wendling and is distributed under the
|
|
||||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This is a concrete diagnostic client, which buffers the diagnostic messages.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef DRIVER_TEXT_DIAGNOSTIC_BUFFER_H_
|
|
||||||
#define DRIVER_TEXT_DIAGNOSTIC_BUFFER_H_
|
|
||||||
|
|
||||||
#include "TextDiagnostics.h"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace clang {
|
|
||||||
|
|
||||||
class Preprocessor;
|
|
||||||
class SourceManager;
|
|
||||||
|
|
||||||
class TextDiagnosticBuffer : public TextDiagnostics {
|
|
||||||
public:
|
|
||||||
typedef std::vector<std::pair<SourceLocation, std::string> > DiagList;
|
|
||||||
typedef DiagList::iterator iterator;
|
|
||||||
typedef DiagList::const_iterator const_iterator;
|
|
||||||
private:
|
|
||||||
DiagList Errors, Warnings;
|
|
||||||
public:
|
|
||||||
TextDiagnosticBuffer(SourceManager &SM) : TextDiagnostics(SM) {}
|
|
||||||
|
|
||||||
const_iterator err_begin() const { return Errors.begin(); }
|
|
||||||
const_iterator err_end() const { return Errors.end(); }
|
|
||||||
|
|
||||||
const_iterator warn_begin() const { return Warnings.begin(); }
|
|
||||||
const_iterator warn_end() const { return Warnings.end(); }
|
|
||||||
|
|
||||||
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
|
|
||||||
SourceLocation Pos,
|
|
||||||
diag::kind ID, const std::string *Strs,
|
|
||||||
unsigned NumStrs,
|
|
||||||
const SourceRange *Ranges,
|
|
||||||
unsigned NumRanges);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end namspace clang
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,218 +0,0 @@
|
|||||||
//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Bill Wendling and is distributed under the
|
|
||||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This diagnostic client prints out their diagnostic messages.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "TextDiagnosticPrinter.h"
|
|
||||||
#include "clang/Basic/FileManager.h"
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
#include "clang/Lex/HeaderSearch.h"
|
|
||||||
#include "clang/Lex/Lexer.h"
|
|
||||||
#include "llvm/Support/CommandLine.h"
|
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
NoShowColumn("fno-show-column",
|
|
||||||
llvm::cl::desc("Do not include column number on diagnostics"));
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
NoCaretDiagnostics("fno-caret-diagnostics",
|
|
||||||
llvm::cl::desc("Do not include source line and caret with"
|
|
||||||
" diagnostics"));
|
|
||||||
|
|
||||||
void TextDiagnosticPrinter::
|
|
||||||
PrintIncludeStack(SourceLocation Pos) {
|
|
||||||
if (Pos.isInvalid()) return;
|
|
||||||
|
|
||||||
Pos = SourceMgr.getLogicalLoc(Pos);
|
|
||||||
|
|
||||||
// Print out the other include frames first.
|
|
||||||
PrintIncludeStack(SourceMgr.getIncludeLoc(Pos));
|
|
||||||
unsigned LineNo = SourceMgr.getLineNumber(Pos);
|
|
||||||
|
|
||||||
std::cerr << "In file included from " << SourceMgr.getSourceName(Pos)
|
|
||||||
<< ":" << LineNo << ":\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s)
|
|
||||||
/// any characters in LineNo that intersect the SourceRange.
|
|
||||||
void TextDiagnosticPrinter::HighlightRange(const SourceRange &R,
|
|
||||||
unsigned LineNo,
|
|
||||||
std::string &CaratLine,
|
|
||||||
const std::string &SourceLine) {
|
|
||||||
assert(CaratLine.size() == SourceLine.size() &&
|
|
||||||
"Expect a correspondence between source and carat line!");
|
|
||||||
if (!R.isValid()) return;
|
|
||||||
|
|
||||||
unsigned StartLineNo = SourceMgr.getLogicalLineNumber(R.Begin());
|
|
||||||
if (StartLineNo > LineNo) return; // No intersection.
|
|
||||||
|
|
||||||
unsigned EndLineNo = SourceMgr.getLogicalLineNumber(R.End());
|
|
||||||
if (EndLineNo < LineNo) return; // No intersection.
|
|
||||||
|
|
||||||
// Compute the column number of the start.
|
|
||||||
unsigned StartColNo = 0;
|
|
||||||
if (StartLineNo == LineNo) {
|
|
||||||
StartColNo = SourceMgr.getLogicalColumnNumber(R.Begin());
|
|
||||||
if (StartColNo) --StartColNo; // Zero base the col #.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pick the first non-whitespace column.
|
|
||||||
while (StartColNo < SourceLine.size() &&
|
|
||||||
(SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
|
|
||||||
++StartColNo;
|
|
||||||
|
|
||||||
// Compute the column number of the end.
|
|
||||||
unsigned EndColNo = CaratLine.size();
|
|
||||||
if (EndLineNo == LineNo) {
|
|
||||||
EndColNo = SourceMgr.getLogicalColumnNumber(R.End());
|
|
||||||
if (EndColNo) {
|
|
||||||
--EndColNo; // Zero base the col #.
|
|
||||||
|
|
||||||
// Add in the length of the token, so that we cover multi-char tokens.
|
|
||||||
EndColNo += GetTokenLength(R.End());
|
|
||||||
} else {
|
|
||||||
EndColNo = CaratLine.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pick the last non-whitespace column.
|
|
||||||
while (EndColNo-1 &&
|
|
||||||
(SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
|
|
||||||
--EndColNo;
|
|
||||||
|
|
||||||
// Fill the range with ~'s.
|
|
||||||
assert(StartColNo <= EndColNo && "Invalid range!");
|
|
||||||
for (unsigned i = StartColNo; i != EndColNo; ++i)
|
|
||||||
CaratLine[i] = '~';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// GetTokenLength - Given the source location of a token, determine its length.
|
|
||||||
/// This is a fully general function that uses a lexer to relex the token.
|
|
||||||
unsigned TextDiagnosticPrinter::GetTokenLength(SourceLocation Loc) {
|
|
||||||
// If this comes from a macro expansion, we really do want the macro name, not
|
|
||||||
// the token this macro expanded to.
|
|
||||||
Loc = SourceMgr.getLogicalLoc(Loc);
|
|
||||||
const char *StrData = SourceMgr.getCharacterData(Loc);
|
|
||||||
|
|
||||||
// TODO: this could be special cased for common tokens like identifiers, ')',
|
|
||||||
// etc to make this faster, if it mattered. This could use
|
|
||||||
// Lexer::isObviouslySimpleCharacter for example.
|
|
||||||
|
|
||||||
// Create a lexer starting at the beginning of this token.
|
|
||||||
Lexer TheLexer(Loc, *ThePreprocessor, StrData);
|
|
||||||
Token TheTok;
|
|
||||||
TheLexer.LexRawToken(TheTok);
|
|
||||||
return TheTok.getLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
|
|
||||||
SourceLocation Pos,
|
|
||||||
diag::kind ID,
|
|
||||||
const std::string *Strs,
|
|
||||||
unsigned NumStrs,
|
|
||||||
const SourceRange *Ranges,
|
|
||||||
unsigned NumRanges) {
|
|
||||||
unsigned LineNo = 0, ColNo = 0;
|
|
||||||
const char *LineStart = 0, *LineEnd = 0;
|
|
||||||
|
|
||||||
if (Pos.isValid()) {
|
|
||||||
SourceLocation LPos = SourceMgr.getLogicalLoc(Pos);
|
|
||||||
LineNo = SourceMgr.getLineNumber(LPos);
|
|
||||||
|
|
||||||
// First, if this diagnostic is not in the main file, print out the
|
|
||||||
// "included from" lines.
|
|
||||||
if (LastWarningLoc != SourceMgr.getIncludeLoc(LPos)) {
|
|
||||||
LastWarningLoc = SourceMgr.getIncludeLoc(LPos);
|
|
||||||
PrintIncludeStack(LastWarningLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the column number. Rewind from the current position to the start
|
|
||||||
// of the line.
|
|
||||||
ColNo = SourceMgr.getColumnNumber(LPos);
|
|
||||||
const char *TokLogicalPtr = SourceMgr.getCharacterData(LPos);
|
|
||||||
LineStart = TokLogicalPtr-ColNo+1; // Column # is 1-based
|
|
||||||
|
|
||||||
// Compute the line end. Scan forward from the error position to the end of
|
|
||||||
// the line.
|
|
||||||
const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(LPos.getFileID());
|
|
||||||
const char *BufEnd = Buffer->getBufferEnd();
|
|
||||||
LineEnd = TokLogicalPtr;
|
|
||||||
while (LineEnd != BufEnd &&
|
|
||||||
*LineEnd != '\n' && *LineEnd != '\r')
|
|
||||||
++LineEnd;
|
|
||||||
|
|
||||||
std::cerr << Buffer->getBufferIdentifier()
|
|
||||||
<< ":" << LineNo << ":";
|
|
||||||
if (ColNo && !NoShowColumn)
|
|
||||||
std::cerr << ColNo << ":";
|
|
||||||
std::cerr << " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (Level) {
|
|
||||||
default: assert(0 && "Unknown diagnostic type!");
|
|
||||||
case Diagnostic::Note: std::cerr << "note: "; break;
|
|
||||||
case Diagnostic::Warning: std::cerr << "warning: "; break;
|
|
||||||
case Diagnostic::Error: std::cerr << "error: "; break;
|
|
||||||
case Diagnostic::Fatal: std::cerr << "fatal error: "; break;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << FormatDiagnostic(Level, ID, Strs, NumStrs) << "\n";
|
|
||||||
|
|
||||||
if (!NoCaretDiagnostics && Pos.isValid()) {
|
|
||||||
// Get the line of the source file.
|
|
||||||
std::string SourceLine(LineStart, LineEnd);
|
|
||||||
|
|
||||||
// Create a line for the carat that is filled with spaces that is the same
|
|
||||||
// length as the line of source code.
|
|
||||||
std::string CaratLine(LineEnd-LineStart, ' ');
|
|
||||||
|
|
||||||
// Highlight all of the characters covered by Ranges with ~ characters.
|
|
||||||
for (unsigned i = 0; i != NumRanges; ++i)
|
|
||||||
HighlightRange(Ranges[i], LineNo, CaratLine, SourceLine);
|
|
||||||
|
|
||||||
// Next, insert the carat itself.
|
|
||||||
if (ColNo-1 < CaratLine.size())
|
|
||||||
CaratLine[ColNo-1] = '^';
|
|
||||||
else
|
|
||||||
CaratLine.push_back('^');
|
|
||||||
|
|
||||||
// Scan the source line, looking for tabs. If we find any, manually expand
|
|
||||||
// them to 8 characters and update the CaratLine to match.
|
|
||||||
for (unsigned i = 0; i != SourceLine.size(); ++i) {
|
|
||||||
if (SourceLine[i] != '\t') continue;
|
|
||||||
|
|
||||||
// Replace this tab with at least one space.
|
|
||||||
SourceLine[i] = ' ';
|
|
||||||
|
|
||||||
// Compute the number of spaces we need to insert.
|
|
||||||
unsigned NumSpaces = ((i+8)&~7) - (i+1);
|
|
||||||
assert(NumSpaces < 8 && "Invalid computation of space amt");
|
|
||||||
|
|
||||||
// Insert spaces into the SourceLine.
|
|
||||||
SourceLine.insert(i+1, NumSpaces, ' ');
|
|
||||||
|
|
||||||
// Insert spaces or ~'s into CaratLine.
|
|
||||||
CaratLine.insert(i+1, NumSpaces, CaratLine[i] == '~' ? '~' : ' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, remove any blank spaces from the end of CaratLine.
|
|
||||||
while (CaratLine[CaratLine.size()-1] == ' ')
|
|
||||||
CaratLine.erase(CaratLine.end()-1);
|
|
||||||
|
|
||||||
// Emit what we have computed.
|
|
||||||
std::cerr << SourceLine << "\n";
|
|
||||||
std::cerr << CaratLine << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
//===--- TextDiagnosticPrinter.h - Text Diagnostic Client -------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Bill Wendling and is distributed under the
|
|
||||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This is a concrete diagnostic client, which prints the diagnostics to
|
|
||||||
// standard error.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef TEXT_DIAGNOSTIC_PRINTER_H_
|
|
||||||
#define TEXT_DIAGNOSTIC_PRINTER_H_
|
|
||||||
|
|
||||||
#include "TextDiagnostics.h"
|
|
||||||
#include "clang/Basic/SourceLocation.h"
|
|
||||||
|
|
||||||
namespace clang {
|
|
||||||
class SourceManager;
|
|
||||||
|
|
||||||
class TextDiagnosticPrinter : public TextDiagnostics {
|
|
||||||
SourceLocation LastWarningLoc;
|
|
||||||
public:
|
|
||||||
TextDiagnosticPrinter(SourceManager &sourceMgr)
|
|
||||||
: TextDiagnostics(sourceMgr) {}
|
|
||||||
|
|
||||||
void PrintIncludeStack(SourceLocation Pos);
|
|
||||||
void HighlightRange(const SourceRange &R, unsigned LineNo,
|
|
||||||
std::string &CaratLine,
|
|
||||||
const std::string &SourceLine);
|
|
||||||
unsigned GetTokenLength(SourceLocation Loc);
|
|
||||||
|
|
||||||
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
|
|
||||||
SourceLocation Pos,
|
|
||||||
diag::kind ID, const std::string *Strs,
|
|
||||||
unsigned NumStrs,
|
|
||||||
const SourceRange *Ranges,
|
|
||||||
unsigned NumRanges);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end namspace clang
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
//===--- TextDiagnostics.cpp - Text Diagnostics Parent Class --------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Bill Wendling and is distributed under the
|
|
||||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This is the parent class for all text diagnostics.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "TextDiagnostics.h"
|
|
||||||
#include "clang/Basic/SourceLocation.h"
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
#include "clang/Lex/HeaderSearch.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
TextDiagnostics:: ~TextDiagnostics() {}
|
|
||||||
|
|
||||||
std::string TextDiagnostics::FormatDiagnostic(Diagnostic::Level Level,
|
|
||||||
diag::kind ID,
|
|
||||||
const std::string *Strs,
|
|
||||||
unsigned NumStrs) {
|
|
||||||
std::string Msg = Diagnostic::getDescription(ID);
|
|
||||||
|
|
||||||
// Replace all instances of %0 in Msg with 'Extra'.
|
|
||||||
for (unsigned i = 0; i < Msg.size() - 1; ++i) {
|
|
||||||
if (Msg[i] == '%' && isdigit(Msg[i + 1])) {
|
|
||||||
unsigned StrNo = Msg[i + 1] - '0';
|
|
||||||
Msg = std::string(Msg.begin(), Msg.begin() + i) +
|
|
||||||
(StrNo < NumStrs ? Strs[StrNo] : "<<<INTERNAL ERROR>>>") +
|
|
||||||
std::string(Msg.begin() + i + 2, Msg.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextDiagnostics::IgnoreDiagnostic(Diagnostic::Level Level,
|
|
||||||
SourceLocation Pos) {
|
|
||||||
if (Pos.isValid()) {
|
|
||||||
// If this is a warning or note, and if it a system header, suppress the
|
|
||||||
// diagnostic.
|
|
||||||
if (Level == Diagnostic::Warning ||
|
|
||||||
Level == Diagnostic::Note) {
|
|
||||||
if (const FileEntry *F = SourceMgr.getFileEntryForLoc(Pos)) {
|
|
||||||
DirectoryLookup::DirType DirInfo = TheHeaderSearch->getFileDirFlavor(F);
|
|
||||||
if (DirInfo == DirectoryLookup::SystemHeaderDir ||
|
|
||||||
DirInfo == DirectoryLookup::ExternCSystemHeaderDir)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
//===--- TextDiagnostics.h - Text Diagnostics Checkers ----------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Bill Wendling and is distributed under the
|
|
||||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This is the parent class for all text diagnostics.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef TEXT_DIAGNOSTICS_H_
|
|
||||||
#define TEXT_DIAGNOSTICS_H_
|
|
||||||
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
|
|
||||||
namespace clang {
|
|
||||||
class SourceManager;
|
|
||||||
class HeaderSearch;
|
|
||||||
class Preprocessor;
|
|
||||||
|
|
||||||
class TextDiagnostics : public DiagnosticClient {
|
|
||||||
HeaderSearch *TheHeaderSearch;
|
|
||||||
protected:
|
|
||||||
SourceManager &SourceMgr;
|
|
||||||
Preprocessor *ThePreprocessor;
|
|
||||||
|
|
||||||
std::string FormatDiagnostic(Diagnostic::Level Level,
|
|
||||||
diag::kind ID,
|
|
||||||
const std::string *Strs,
|
|
||||||
unsigned NumStrs);
|
|
||||||
public:
|
|
||||||
TextDiagnostics(SourceManager &sourceMgr) : SourceMgr(sourceMgr) {}
|
|
||||||
virtual ~TextDiagnostics();
|
|
||||||
|
|
||||||
void setHeaderSearch(HeaderSearch &HS) { TheHeaderSearch = &HS; }
|
|
||||||
void setPreprocessor(Preprocessor &P) { ThePreprocessor = &P; }
|
|
||||||
|
|
||||||
virtual bool IgnoreDiagnostic(Diagnostic::Level Level,
|
|
||||||
SourceLocation Pos);
|
|
||||||
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
|
|
||||||
SourceLocation Pos,
|
|
||||||
diag::kind ID, const std::string *Strs,
|
|
||||||
unsigned NumStrs,
|
|
||||||
const SourceRange *Ranges,
|
|
||||||
unsigned NumRanges) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end namspace clang
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,420 +0,0 @@
|
|||||||
//===--- X86Builtins.def - X86 Builtin function database --------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// 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 defines the X86-specific builtin function database. Users of
|
|
||||||
// this file must define the BUILTIN macro to make use of this information.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// FIXME: this needs to be the full list supported by GCC. Right now, I'm just
|
|
||||||
// adding stuff on demand.
|
|
||||||
|
|
||||||
// The format of this database matches clang/AST/Builtins.def.
|
|
||||||
|
|
||||||
BUILTIN(__builtin_ia32_emms , "v", "")
|
|
||||||
|
|
||||||
// FIXME: These types are incorrect.
|
|
||||||
// SSE intrinsics.
|
|
||||||
BUILTIN(__builtin_ia32_comieq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_comilt, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_comile, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_comigt, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_comige, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_comineq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_ucomieq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_ucomilt, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_ucomile, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_ucomigt, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_ucomige, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_ucomineq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_comisdeq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_comisdlt, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_comisdle, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_comisdgt, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_comisdge, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_comisdneq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_ucomisdeq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_ucomisdlt, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_ucomisdle, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_ucomisdgt, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_ucomisdge, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_ucomisdneq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_addps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_subps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_mulps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_divps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_addss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_subss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_mulss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_divss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpeqps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpltps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpleps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpgtps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpgeps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpunordps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpneqps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpnltps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpnleps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpngtps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpngeps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpordps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpeqss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpltss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpless, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpunordss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpneqss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpnltss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpnless, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpngtss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpngess, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpordss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_minps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_maxps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_minss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_maxss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_andps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_andnps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_orps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_xorps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_movss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_movhlps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_movlhps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_unpckhps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_unpcklps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddsb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddsw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubsb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubsw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddusb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddusw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubusb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubusw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmullw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmulhw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmulhuw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pand, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pandn, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_por, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pxor, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pavgb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pavgw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pcmpeqb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pcmpeqw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pcmpeqd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pcmpgtb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pcmpgtw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pcmpgtd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmaxub, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmaxsw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pminub, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pminsw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpckhbw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpckhwd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpckhdq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpcklbw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpcklwd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpckldq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_addpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_subpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_mulpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_divpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_addsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_subsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_mulsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_divsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpeqpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpltpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmplepd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpgtpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpgepd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpunordpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpneqpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpnltpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpnlepd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpngtpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpngepd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpordpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpeqsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpltsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmplesd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpunordsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpneqsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpnltsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpnlesd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cmpordsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_minpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_maxpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_minsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_maxsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_andpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_andnpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_orpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_xorpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_movsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_unpckhpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_unpcklpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddd128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddq128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubd128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubq128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddsb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddsw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubsb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubsw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddusb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_paddusw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubusb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psubusw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmullw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmulhw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pand128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pandn128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_por128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pxor128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pavgb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pavgw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pcmpeqb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pcmpeqw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pcmpeqd128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pcmpgtb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pcmpgtw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pcmpgtd128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmaxub128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmaxsw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pminub128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pminsw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpckhbw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpckhwd128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpckhdq128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpckhqdq128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpcklbw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpcklwd128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpckldq128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_punpcklqdq128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_packsswb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_packssdw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_packuswb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmulhuw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_addsubps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_addsubpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_haddps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_haddpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_hsubps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_hsubpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_phaddw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_phaddw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_phaddd128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_phaddd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_phaddsw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_phaddsw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_phsubw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_phsubw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_phsubd128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_phsubd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_phsubsw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_phsubsw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmaddubsw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmaddubsw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmulhrsw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmulhrsw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pshufb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pshufb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psignb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psignb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psignw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psignw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psignd128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psignd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pabsb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pabsb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pabsw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pabsw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pabsd128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pabsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psllw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pslld, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psllq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrlw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrld, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrlq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psraw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrad, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pshufw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmaddwd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_packsswb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_packssdw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_packuswb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_ldmxcsr, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_stmxcsr, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtpi2ps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtps2pi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtsi2ss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtsi642ss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtss2si, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtss2si64, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvttps2pi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvttss2si, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvttss2si64, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_maskmovq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_loadups, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_storeups, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_loadhps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_loadlps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_storehps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_storelps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_movmskps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmovmskb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_movntps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_movntq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_sfence, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psadbw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_rcpps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_rcpss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_rsqrtps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_rsqrtss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_sqrtps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_sqrtss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_shufps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_femms, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pavgusb, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pf2id, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfacc, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfadd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfcmpeq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfcmpge, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfcmpgt, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfmax, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfmin, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfmul, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfrcp, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfrcpit1, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfrcpit2, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfrsqrt, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfrsqit1, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfsub, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfsubr, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pi2fd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmulhrw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pf2iw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfnacc, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pfpnacc, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pi2fw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pswapdsf, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pswapdsi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_maskmovdqu, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_loadupd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_storeupd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_loadhpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_loadlpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_movmskpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmovmskb128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_movnti, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_movntpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_movntdq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pshufd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pshuflw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pshufhw, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psadbw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_sqrtpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_sqrtsd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_shufpd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtdq2pd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtdq2ps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtpd2dq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtpd2pi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtpd2ps, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvttpd2dq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvttpd2pi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtpi2pd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtsd2si, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvttsd2si, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtsd2si64, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvttsd2si64, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtps2dq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtps2pd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvttps2dq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtsi2sd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtsi642sd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtsd2ss, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_cvtss2sd, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_clflush, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_lfence, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_mfence, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_loaddqu, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_storedqu, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psllwi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pslldi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psllqi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrawi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psradi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrlwi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrldi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrlqi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmuludq, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmuludq128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psllw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pslld128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psllq128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrlw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrld128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrlq128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psraw128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrad128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pslldqi128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psllwi128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pslldi128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psllqi128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrldqi128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrlwi128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrldi128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrlqi128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psrawi128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_psradi128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_pmaddwd128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_monitor, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_mwait, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_movshdup, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_movsldup, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_lddqu, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_palignr128, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_palignr, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_vec_init_v2si, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_vec_init_v4hi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_vec_init_v8qi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_vec_ext_v2df, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_vec_ext_v2di, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_vec_ext_v4sf, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_vec_ext_v4si, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_vec_ext_v8hi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_vec_ext_v4hi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_vec_ext_v2si, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_vec_set_v8hi, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_vec_set_v4hi, "v", "")
|
|
||||||
|
|
||||||
// Apple local SSE builtins? These are probably not needed eventually, but are
|
|
||||||
// in the apple-gcc xmmintrin.h file (rdar://4099020).
|
|
||||||
BUILTIN(__builtin_ia32_movqv4si, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_loadlv4si, "v", "")
|
|
||||||
BUILTIN(__builtin_ia32_storelv4si, "v", "")
|
|
||||||
|
|
||||||
|
|
||||||
#undef BUILTIN
|
|
||||||
@@ -1,978 +0,0 @@
|
|||||||
//===--- clang.cpp - C-Language Front-end ---------------------------------===//
|
|
||||||
//
|
|
||||||
// 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 utility may be invoked in the following manner:
|
|
||||||
// clang --help - Output help info.
|
|
||||||
// clang [options] - Read from stdin.
|
|
||||||
// clang [options] file - Read from "file".
|
|
||||||
// clang [options] file1 file2 - Read these files.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// TODO: Options to support:
|
|
||||||
//
|
|
||||||
// -ffatal-errors
|
|
||||||
// -ftabstop=width
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang.h"
|
|
||||||
#include "ASTStreamers.h"
|
|
||||||
#include "TextDiagnosticBuffer.h"
|
|
||||||
#include "TextDiagnosticPrinter.h"
|
|
||||||
#include "clang/Parse/Parser.h"
|
|
||||||
#include "clang/Lex/HeaderSearch.h"
|
|
||||||
#include "clang/Basic/FileManager.h"
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
#include "clang/Basic/TargetInfo.h"
|
|
||||||
#include "llvm/Support/CommandLine.h"
|
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
|
||||||
#include "llvm/System/Signals.h"
|
|
||||||
#include <memory>
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Global options.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
Verbose("v", llvm::cl::desc("Enable verbose output"));
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
Stats("stats", llvm::cl::desc("Print performance metrics and statistics"));
|
|
||||||
|
|
||||||
enum ProgActions {
|
|
||||||
EmitLLVM, // Emit a .ll file.
|
|
||||||
ParseASTPrint, // Parse ASTs and print them.
|
|
||||||
ParseASTDump, // Parse ASTs and dump them.
|
|
||||||
ParseASTCheck, // Parse ASTs and check diagnostics.
|
|
||||||
ParseAST, // Parse ASTs.
|
|
||||||
ParseCFGDump, // Parse ASTS. Build CFGs. Print CFGs.
|
|
||||||
ParseCFGView, // Parse ASTS. Build CFGs. View CFGs.
|
|
||||||
AnalysisLiveVariables, // Print results of live-variable analysis.
|
|
||||||
WarnDeadStores, // Run DeadStores checker on parsed ASTs.
|
|
||||||
ParsePrintCallbacks, // Parse and print each callback.
|
|
||||||
ParseSyntaxOnly, // Parse and perform semantic analysis.
|
|
||||||
ParseNoop, // Parse with noop callbacks.
|
|
||||||
RunPreprocessorOnly, // Just lex, no output.
|
|
||||||
PrintPreprocessedInput, // -E mode.
|
|
||||||
DumpTokens // Token dump mode.
|
|
||||||
};
|
|
||||||
|
|
||||||
static llvm::cl::opt<ProgActions>
|
|
||||||
ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore,
|
|
||||||
llvm::cl::init(ParseSyntaxOnly),
|
|
||||||
llvm::cl::values(
|
|
||||||
clEnumValN(RunPreprocessorOnly, "Eonly",
|
|
||||||
"Just run preprocessor, no output (for timings)"),
|
|
||||||
clEnumValN(PrintPreprocessedInput, "E",
|
|
||||||
"Run preprocessor, emit preprocessed file"),
|
|
||||||
clEnumValN(DumpTokens, "dumptokens",
|
|
||||||
"Run preprocessor, dump internal rep of tokens"),
|
|
||||||
clEnumValN(ParseNoop, "parse-noop",
|
|
||||||
"Run parser with noop callbacks (for timings)"),
|
|
||||||
clEnumValN(ParseSyntaxOnly, "fsyntax-only",
|
|
||||||
"Run parser and perform semantic analysis"),
|
|
||||||
clEnumValN(ParsePrintCallbacks, "parse-print-callbacks",
|
|
||||||
"Run parser and print each callback invoked"),
|
|
||||||
clEnumValN(ParseAST, "parse-ast",
|
|
||||||
"Run parser and build ASTs"),
|
|
||||||
clEnumValN(ParseASTPrint, "parse-ast-print",
|
|
||||||
"Run parser, build ASTs, then print ASTs"),
|
|
||||||
clEnumValN(ParseASTDump, "parse-ast-dump",
|
|
||||||
"Run parser, build ASTs, then dump them"),
|
|
||||||
clEnumValN(ParseASTCheck, "parse-ast-check",
|
|
||||||
"Run parser, build ASTs, then check diagnostics"),
|
|
||||||
clEnumValN(ParseCFGDump, "dump-cfg",
|
|
||||||
"Run parser, then build and print CFGs."),
|
|
||||||
clEnumValN(ParseCFGView, "view-cfg",
|
|
||||||
"Run parser, then build and view CFGs with Graphviz."),
|
|
||||||
clEnumValN(AnalysisLiveVariables, "dump-live-variables",
|
|
||||||
"Print results of live variable analysis."),
|
|
||||||
clEnumValN(WarnDeadStores, "check-dead-stores",
|
|
||||||
"Flag warnings of stores to dead variables."),
|
|
||||||
clEnumValN(EmitLLVM, "emit-llvm",
|
|
||||||
"Build ASTs then convert to LLVM, emit .ll file"),
|
|
||||||
clEnumValEnd));
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Language Options
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
enum LangKind {
|
|
||||||
langkind_unspecified,
|
|
||||||
langkind_c,
|
|
||||||
langkind_c_cpp,
|
|
||||||
langkind_cxx,
|
|
||||||
langkind_cxx_cpp,
|
|
||||||
langkind_objc,
|
|
||||||
langkind_objc_cpp,
|
|
||||||
langkind_objcxx,
|
|
||||||
langkind_objcxx_cpp
|
|
||||||
};
|
|
||||||
|
|
||||||
/* TODO: GCC also accepts:
|
|
||||||
c-header c++-header objective-c-header objective-c++-header
|
|
||||||
assembler assembler-with-cpp
|
|
||||||
ada, f77*, ratfor (!), f95, java, treelang
|
|
||||||
*/
|
|
||||||
static llvm::cl::opt<LangKind>
|
|
||||||
BaseLang("x", llvm::cl::desc("Base language to compile"),
|
|
||||||
llvm::cl::init(langkind_unspecified),
|
|
||||||
llvm::cl::values(clEnumValN(langkind_c, "c", "C"),
|
|
||||||
clEnumValN(langkind_cxx, "c++", "C++"),
|
|
||||||
clEnumValN(langkind_objc, "objective-c", "Objective C"),
|
|
||||||
clEnumValN(langkind_objcxx,"objective-c++","Objective C++"),
|
|
||||||
clEnumValN(langkind_c_cpp, "c-cpp-output",
|
|
||||||
"Preprocessed C"),
|
|
||||||
clEnumValN(langkind_cxx_cpp, "c++-cpp-output",
|
|
||||||
"Preprocessed C++"),
|
|
||||||
clEnumValN(langkind_objc_cpp, "objective-c-cpp-output",
|
|
||||||
"Preprocessed Objective C"),
|
|
||||||
clEnumValN(langkind_objcxx_cpp,"objective-c++-cpp-output",
|
|
||||||
"Preprocessed Objective C++"),
|
|
||||||
clEnumValEnd));
|
|
||||||
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
LangObjC("ObjC", llvm::cl::desc("Set base language to Objective-C"),
|
|
||||||
llvm::cl::Hidden);
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
LangObjCXX("ObjC++", llvm::cl::desc("Set base language to Objective-C++"),
|
|
||||||
llvm::cl::Hidden);
|
|
||||||
|
|
||||||
/// InitializeBaseLanguage - Handle the -x foo options or infer a base language
|
|
||||||
/// from the input filename.
|
|
||||||
static void InitializeBaseLanguage(LangOptions &Options,
|
|
||||||
const std::string &Filename) {
|
|
||||||
if (BaseLang == langkind_unspecified) {
|
|
||||||
std::string::size_type DotPos = Filename.rfind('.');
|
|
||||||
if (LangObjC) {
|
|
||||||
BaseLang = langkind_objc;
|
|
||||||
} else if (LangObjCXX) {
|
|
||||||
BaseLang = langkind_objcxx;
|
|
||||||
} else if (DotPos == std::string::npos) {
|
|
||||||
BaseLang = langkind_c; // Default to C if no extension.
|
|
||||||
} else {
|
|
||||||
std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
|
|
||||||
// C header: .h
|
|
||||||
// C++ header: .hh or .H;
|
|
||||||
// assembler no preprocessing: .s
|
|
||||||
// assembler: .S
|
|
||||||
if (Ext == "c")
|
|
||||||
BaseLang = langkind_c;
|
|
||||||
else if (Ext == "i")
|
|
||||||
BaseLang = langkind_c_cpp;
|
|
||||||
else if (Ext == "ii")
|
|
||||||
BaseLang = langkind_cxx_cpp;
|
|
||||||
else if (Ext == "m")
|
|
||||||
BaseLang = langkind_objc;
|
|
||||||
else if (Ext == "mi")
|
|
||||||
BaseLang = langkind_objc_cpp;
|
|
||||||
else if (Ext == "mm" || Ext == "M")
|
|
||||||
BaseLang = langkind_objcxx;
|
|
||||||
else if (Ext == "mii")
|
|
||||||
BaseLang = langkind_objcxx_cpp;
|
|
||||||
else if (Ext == "C" || Ext == "cc" || Ext == "cpp" || Ext == "CPP" ||
|
|
||||||
Ext == "c++" || Ext == "cp" || Ext == "cxx")
|
|
||||||
BaseLang = langkind_cxx;
|
|
||||||
else
|
|
||||||
BaseLang = langkind_c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: implement -fpreprocessed mode.
|
|
||||||
bool NoPreprocess = false;
|
|
||||||
|
|
||||||
switch (BaseLang) {
|
|
||||||
default: assert(0 && "Unknown language kind!");
|
|
||||||
case langkind_c_cpp:
|
|
||||||
NoPreprocess = true;
|
|
||||||
// FALLTHROUGH
|
|
||||||
case langkind_c:
|
|
||||||
break;
|
|
||||||
case langkind_cxx_cpp:
|
|
||||||
NoPreprocess = true;
|
|
||||||
// FALLTHROUGH
|
|
||||||
case langkind_cxx:
|
|
||||||
Options.CPlusPlus = 1;
|
|
||||||
break;
|
|
||||||
case langkind_objc_cpp:
|
|
||||||
NoPreprocess = true;
|
|
||||||
// FALLTHROUGH
|
|
||||||
case langkind_objc:
|
|
||||||
Options.ObjC1 = Options.ObjC2 = 1;
|
|
||||||
break;
|
|
||||||
case langkind_objcxx_cpp:
|
|
||||||
NoPreprocess = true;
|
|
||||||
// FALLTHROUGH
|
|
||||||
case langkind_objcxx:
|
|
||||||
Options.ObjC1 = Options.ObjC2 = 1;
|
|
||||||
Options.CPlusPlus = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// LangStds - Language standards we support.
|
|
||||||
enum LangStds {
|
|
||||||
lang_unspecified,
|
|
||||||
lang_c89, lang_c94, lang_c99,
|
|
||||||
lang_gnu89, lang_gnu99,
|
|
||||||
lang_cxx98, lang_gnucxx98,
|
|
||||||
lang_cxx0x, lang_gnucxx0x
|
|
||||||
};
|
|
||||||
|
|
||||||
static llvm::cl::opt<LangStds>
|
|
||||||
LangStd("std", llvm::cl::desc("Language standard to compile for"),
|
|
||||||
llvm::cl::init(lang_unspecified),
|
|
||||||
llvm::cl::values(clEnumValN(lang_c89, "c89", "ISO C 1990"),
|
|
||||||
clEnumValN(lang_c89, "c90", "ISO C 1990"),
|
|
||||||
clEnumValN(lang_c89, "iso9899:1990", "ISO C 1990"),
|
|
||||||
clEnumValN(lang_c94, "iso9899:199409",
|
|
||||||
"ISO C 1990 with amendment 1"),
|
|
||||||
clEnumValN(lang_c99, "c99", "ISO C 1999"),
|
|
||||||
// clEnumValN(lang_c99, "c9x", "ISO C 1999"),
|
|
||||||
clEnumValN(lang_c99, "iso9899:1999", "ISO C 1999"),
|
|
||||||
// clEnumValN(lang_c99, "iso9899:199x", "ISO C 1999"),
|
|
||||||
clEnumValN(lang_gnu89, "gnu89",
|
|
||||||
"ISO C 1990 with GNU extensions (default for C)"),
|
|
||||||
clEnumValN(lang_gnu99, "gnu99",
|
|
||||||
"ISO C 1999 with GNU extensions"),
|
|
||||||
clEnumValN(lang_gnu99, "gnu9x",
|
|
||||||
"ISO C 1999 with GNU extensions"),
|
|
||||||
clEnumValN(lang_cxx98, "c++98",
|
|
||||||
"ISO C++ 1998 with amendments"),
|
|
||||||
clEnumValN(lang_gnucxx98, "gnu++98",
|
|
||||||
"ISO C++ 1998 with amendments and GNU "
|
|
||||||
"extensions (default for C++)"),
|
|
||||||
clEnumValN(lang_cxx0x, "c++0x",
|
|
||||||
"Upcoming ISO C++ 200x with amendments"),
|
|
||||||
clEnumValN(lang_gnucxx0x, "gnu++0x",
|
|
||||||
"Upcoming ISO C++ 200x with amendments and GNU "
|
|
||||||
"extensions (default for C++)"),
|
|
||||||
clEnumValEnd));
|
|
||||||
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
NoOperatorNames("fno-operator-names",
|
|
||||||
llvm::cl::desc("Do not treat C++ operator name keywords as "
|
|
||||||
"synonyms for operators"));
|
|
||||||
|
|
||||||
// FIXME: add:
|
|
||||||
// -ansi
|
|
||||||
// -trigraphs
|
|
||||||
// -fdollars-in-identifiers
|
|
||||||
static void InitializeLanguageStandard(LangOptions &Options) {
|
|
||||||
if (LangStd == lang_unspecified) {
|
|
||||||
// Based on the base language, pick one.
|
|
||||||
switch (BaseLang) {
|
|
||||||
default: assert(0 && "Unknown base language");
|
|
||||||
case langkind_c:
|
|
||||||
case langkind_c_cpp:
|
|
||||||
case langkind_objc:
|
|
||||||
case langkind_objc_cpp:
|
|
||||||
LangStd = lang_gnu99;
|
|
||||||
break;
|
|
||||||
case langkind_cxx:
|
|
||||||
case langkind_cxx_cpp:
|
|
||||||
case langkind_objcxx:
|
|
||||||
case langkind_objcxx_cpp:
|
|
||||||
LangStd = lang_gnucxx98;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (LangStd) {
|
|
||||||
default: assert(0 && "Unknown language standard!");
|
|
||||||
|
|
||||||
// Fall through from newer standards to older ones. This isn't really right.
|
|
||||||
// FIXME: Enable specifically the right features based on the language stds.
|
|
||||||
case lang_gnucxx0x:
|
|
||||||
case lang_cxx0x:
|
|
||||||
Options.CPlusPlus0x = 1;
|
|
||||||
// FALL THROUGH
|
|
||||||
case lang_gnucxx98:
|
|
||||||
case lang_cxx98:
|
|
||||||
Options.CPlusPlus = 1;
|
|
||||||
Options.CXXOperatorNames = !NoOperatorNames;
|
|
||||||
// FALL THROUGH.
|
|
||||||
case lang_gnu99:
|
|
||||||
case lang_c99:
|
|
||||||
Options.Digraphs = 1;
|
|
||||||
Options.C99 = 1;
|
|
||||||
Options.HexFloats = 1;
|
|
||||||
// FALL THROUGH.
|
|
||||||
case lang_gnu89:
|
|
||||||
Options.BCPLComment = 1; // Only for C99/C++.
|
|
||||||
// FALL THROUGH.
|
|
||||||
case lang_c94:
|
|
||||||
case lang_c89:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Options.Trigraphs = 1; // -trigraphs or -ansi
|
|
||||||
Options.DollarIdents = 1; // FIXME: Really a target property.
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Our DiagnosticClient implementation
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// FIXME: Werror should take a list of things, -Werror=foo,bar
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
WarningsAsErrors("Werror", llvm::cl::desc("Treat all warnings as errors"));
|
|
||||||
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
WarnOnExtensions("pedantic", llvm::cl::init(false),
|
|
||||||
llvm::cl::desc("Issue a warning on uses of GCC extensions"));
|
|
||||||
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
ErrorOnExtensions("pedantic-errors",
|
|
||||||
llvm::cl::desc("Issue an error on uses of GCC extensions"));
|
|
||||||
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
WarnUnusedMacros("Wunused_macros",
|
|
||||||
llvm::cl::desc("Warn for unused macros in the main translation unit"));
|
|
||||||
|
|
||||||
|
|
||||||
/// InitializeDiagnostics - Initialize the diagnostic object, based on the
|
|
||||||
/// current command line option settings.
|
|
||||||
static void InitializeDiagnostics(Diagnostic &Diags) {
|
|
||||||
Diags.setWarningsAsErrors(WarningsAsErrors);
|
|
||||||
Diags.setWarnOnExtensions(WarnOnExtensions);
|
|
||||||
Diags.setErrorOnExtensions(ErrorOnExtensions);
|
|
||||||
|
|
||||||
// Silence the "macro is not used" warning unless requested.
|
|
||||||
if (!WarnUnusedMacros)
|
|
||||||
Diags.setDiagnosticMapping(diag::pp_macro_not_used, diag::MAP_IGNORE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Preprocessor Initialization
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// FIXME: Preprocessor builtins to support.
|
|
||||||
// -A... - Play with #assertions
|
|
||||||
// -undef - Undefine all predefined macros
|
|
||||||
|
|
||||||
static llvm::cl::list<std::string>
|
|
||||||
D_macros("D", llvm::cl::value_desc("macro"), llvm::cl::Prefix,
|
|
||||||
llvm::cl::desc("Predefine the specified macro"));
|
|
||||||
static llvm::cl::list<std::string>
|
|
||||||
U_macros("U", llvm::cl::value_desc("macro"), llvm::cl::Prefix,
|
|
||||||
llvm::cl::desc("Undefine the specified macro"));
|
|
||||||
|
|
||||||
// Append a #define line to Buf for Macro. Macro should be of the form XXX,
|
|
||||||
// in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit
|
|
||||||
// "#define XXX Y z W". To get a #define with no value, use "XXX=".
|
|
||||||
static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro,
|
|
||||||
const char *Command = "#define ") {
|
|
||||||
Buf.insert(Buf.end(), Command, Command+strlen(Command));
|
|
||||||
if (const char *Equal = strchr(Macro, '=')) {
|
|
||||||
// Turn the = into ' '.
|
|
||||||
Buf.insert(Buf.end(), Macro, Equal);
|
|
||||||
Buf.push_back(' ');
|
|
||||||
Buf.insert(Buf.end(), Equal+1, Equal+strlen(Equal));
|
|
||||||
} else {
|
|
||||||
// Push "macroname 1".
|
|
||||||
Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
|
|
||||||
Buf.push_back(' ');
|
|
||||||
Buf.push_back('1');
|
|
||||||
}
|
|
||||||
Buf.push_back('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
static void InitializePredefinedMacros(Preprocessor &PP,
|
|
||||||
std::vector<char> &Buf) {
|
|
||||||
// FIXME: Implement magic like cpp_init_builtins for things like __STDC__
|
|
||||||
// and __DATE__ etc.
|
|
||||||
#if 0
|
|
||||||
/* __STDC__ has the value 1 under normal circumstances.
|
|
||||||
However, if (a) we are in a system header, (b) the option
|
|
||||||
stdc_0_in_system_headers is true (set by target config), and
|
|
||||||
(c) we are not in strictly conforming mode, then it has the
|
|
||||||
value 0. (b) and (c) are already checked in cpp_init_builtins. */
|
|
||||||
//case BT_STDC:
|
|
||||||
if (cpp_in_system_header (pfile))
|
|
||||||
number = 0;
|
|
||||||
else
|
|
||||||
number = 1;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
// These should all be defined in the preprocessor according to the
|
|
||||||
// current language configuration.
|
|
||||||
DefineBuiltinMacro(Buf, "__STDC__=1");
|
|
||||||
//DefineBuiltinMacro(Buf, "__ASSEMBLER__=1");
|
|
||||||
if (PP.getLangOptions().C99 && !PP.getLangOptions().CPlusPlus)
|
|
||||||
DefineBuiltinMacro(Buf, "__STDC_VERSION__=199901L");
|
|
||||||
else if (0) // STDC94 ?
|
|
||||||
DefineBuiltinMacro(Buf, "__STDC_VERSION__=199409L");
|
|
||||||
|
|
||||||
DefineBuiltinMacro(Buf, "__STDC_HOSTED__=1");
|
|
||||||
if (PP.getLangOptions().ObjC1)
|
|
||||||
DefineBuiltinMacro(Buf, "__OBJC__=1");
|
|
||||||
if (PP.getLangOptions().ObjC2)
|
|
||||||
DefineBuiltinMacro(Buf, "__OBJC2__=1");
|
|
||||||
|
|
||||||
// Get the target #defines.
|
|
||||||
PP.getTargetInfo().getTargetDefines(Buf);
|
|
||||||
|
|
||||||
// Compiler set macros.
|
|
||||||
DefineBuiltinMacro(Buf, "__APPLE_CC__=5250");
|
|
||||||
DefineBuiltinMacro(Buf, "__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__=1030");
|
|
||||||
DefineBuiltinMacro(Buf, "__GNUC_MINOR__=0");
|
|
||||||
DefineBuiltinMacro(Buf, "__GNUC_PATCHLEVEL__=1");
|
|
||||||
DefineBuiltinMacro(Buf, "__GNUC__=4");
|
|
||||||
DefineBuiltinMacro(Buf, "__GXX_ABI_VERSION=1002");
|
|
||||||
DefineBuiltinMacro(Buf, "__VERSION__=\"4.0.1 (Apple Computer, Inc. "
|
|
||||||
"build 5250)\"");
|
|
||||||
|
|
||||||
// Build configuration options.
|
|
||||||
DefineBuiltinMacro(Buf, "__DYNAMIC__=1");
|
|
||||||
DefineBuiltinMacro(Buf, "__FINITE_MATH_ONLY__=0");
|
|
||||||
DefineBuiltinMacro(Buf, "__NO_INLINE__=1");
|
|
||||||
DefineBuiltinMacro(Buf, "__PIC__=1");
|
|
||||||
|
|
||||||
|
|
||||||
if (PP.getLangOptions().CPlusPlus) {
|
|
||||||
DefineBuiltinMacro(Buf, "__DEPRECATED=1");
|
|
||||||
DefineBuiltinMacro(Buf, "__EXCEPTIONS=1");
|
|
||||||
DefineBuiltinMacro(Buf, "__GNUG__=4");
|
|
||||||
DefineBuiltinMacro(Buf, "__GXX_WEAK__=1");
|
|
||||||
DefineBuiltinMacro(Buf, "__cplusplus=1");
|
|
||||||
DefineBuiltinMacro(Buf, "__private_extern__=extern");
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Should emit a #line directive here.
|
|
||||||
|
|
||||||
// Add macros from the command line.
|
|
||||||
// FIXME: Should traverse the #define/#undef lists in parallel.
|
|
||||||
for (unsigned i = 0, e = D_macros.size(); i != e; ++i)
|
|
||||||
DefineBuiltinMacro(Buf, D_macros[i].c_str());
|
|
||||||
for (unsigned i = 0, e = U_macros.size(); i != e; ++i)
|
|
||||||
DefineBuiltinMacro(Buf, U_macros[i].c_str(), "#undef ");
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Preprocessor include path information.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// This tool exports a large number of command line options to control how the
|
|
||||||
// preprocessor searches for header files. At root, however, the Preprocessor
|
|
||||||
// object takes a very simple interface: a list of directories to search for
|
|
||||||
//
|
|
||||||
// FIXME: -nostdinc,-nostdinc++
|
|
||||||
// FIXME: -imultilib
|
|
||||||
//
|
|
||||||
// FIXME: -include,-imacros
|
|
||||||
|
|
||||||
static llvm::cl::opt<bool>
|
|
||||||
nostdinc("nostdinc", llvm::cl::desc("Disable standard #include directories"));
|
|
||||||
|
|
||||||
// Various command line options. These four add directories to each chain.
|
|
||||||
static llvm::cl::list<std::string>
|
|
||||||
F_dirs("F", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
|
|
||||||
llvm::cl::desc("Add directory to framework include search path"));
|
|
||||||
static llvm::cl::list<std::string>
|
|
||||||
I_dirs("I", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
|
|
||||||
llvm::cl::desc("Add directory to include search path"));
|
|
||||||
static llvm::cl::list<std::string>
|
|
||||||
idirafter_dirs("idirafter", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
|
|
||||||
llvm::cl::desc("Add directory to AFTER include search path"));
|
|
||||||
static llvm::cl::list<std::string>
|
|
||||||
iquote_dirs("iquote", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
|
|
||||||
llvm::cl::desc("Add directory to QUOTE include search path"));
|
|
||||||
static llvm::cl::list<std::string>
|
|
||||||
isystem_dirs("isystem", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
|
|
||||||
llvm::cl::desc("Add directory to SYSTEM include search path"));
|
|
||||||
|
|
||||||
// These handle -iprefix/-iwithprefix/-iwithprefixbefore.
|
|
||||||
static llvm::cl::list<std::string>
|
|
||||||
iprefix_vals("iprefix", llvm::cl::value_desc("prefix"), llvm::cl::Prefix,
|
|
||||||
llvm::cl::desc("Set the -iwithprefix/-iwithprefixbefore prefix"));
|
|
||||||
static llvm::cl::list<std::string>
|
|
||||||
iwithprefix_vals("iwithprefix", llvm::cl::value_desc("dir"), llvm::cl::Prefix,
|
|
||||||
llvm::cl::desc("Set directory to SYSTEM include search path with prefix"));
|
|
||||||
static llvm::cl::list<std::string>
|
|
||||||
iwithprefixbefore_vals("iwithprefixbefore", llvm::cl::value_desc("dir"),
|
|
||||||
llvm::cl::Prefix,
|
|
||||||
llvm::cl::desc("Set directory to include search path with prefix"));
|
|
||||||
|
|
||||||
static llvm::cl::opt<std::string>
|
|
||||||
isysroot("isysroot", llvm::cl::value_desc("dir"), llvm::cl::init("/"),
|
|
||||||
llvm::cl::desc("Set the system root directory (usually /)"));
|
|
||||||
|
|
||||||
// Finally, implement the code that groks the options above.
|
|
||||||
enum IncludeDirGroup {
|
|
||||||
Quoted = 0,
|
|
||||||
Angled,
|
|
||||||
System,
|
|
||||||
After
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::vector<DirectoryLookup> IncludeGroup[4];
|
|
||||||
|
|
||||||
/// AddPath - Add the specified path to the specified group list.
|
|
||||||
///
|
|
||||||
static void AddPath(const std::string &Path, IncludeDirGroup Group,
|
|
||||||
bool isCXXAware, bool isUserSupplied,
|
|
||||||
bool isFramework, FileManager &FM) {
|
|
||||||
const DirectoryEntry *DE;
|
|
||||||
if (Group == System)
|
|
||||||
DE = FM.getDirectory(isysroot + "/" + Path);
|
|
||||||
else
|
|
||||||
DE = FM.getDirectory(Path);
|
|
||||||
|
|
||||||
if (DE == 0) {
|
|
||||||
if (Verbose)
|
|
||||||
fprintf(stderr, "ignoring nonexistent directory \"%s\"\n",
|
|
||||||
Path.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectoryLookup::DirType Type;
|
|
||||||
if (Group == Quoted || Group == Angled)
|
|
||||||
Type = DirectoryLookup::NormalHeaderDir;
|
|
||||||
else if (isCXXAware)
|
|
||||||
Type = DirectoryLookup::SystemHeaderDir;
|
|
||||||
else
|
|
||||||
Type = DirectoryLookup::ExternCSystemHeaderDir;
|
|
||||||
|
|
||||||
IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied,
|
|
||||||
isFramework));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// RemoveDuplicates - If there are duplicate directory entries in the specified
|
|
||||||
/// search list, remove the later (dead) ones.
|
|
||||||
static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList) {
|
|
||||||
std::set<const DirectoryEntry *> SeenDirs;
|
|
||||||
for (unsigned i = 0; i != SearchList.size(); ++i) {
|
|
||||||
// If this isn't the first time we've seen this dir, remove it.
|
|
||||||
if (!SeenDirs.insert(SearchList[i].getDir()).second) {
|
|
||||||
if (Verbose)
|
|
||||||
fprintf(stderr, "ignoring duplicate directory \"%s\"\n",
|
|
||||||
SearchList[i].getDir()->getName());
|
|
||||||
SearchList.erase(SearchList.begin()+i);
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// InitializeIncludePaths - Process the -I options and set them in the
|
|
||||||
/// HeaderSearch object.
|
|
||||||
static void InitializeIncludePaths(HeaderSearch &Headers, FileManager &FM,
|
|
||||||
Diagnostic &Diags, const LangOptions &Lang) {
|
|
||||||
// Handle -F... options.
|
|
||||||
for (unsigned i = 0, e = F_dirs.size(); i != e; ++i)
|
|
||||||
AddPath(F_dirs[i], Angled, false, true, true, FM);
|
|
||||||
|
|
||||||
// Handle -I... options.
|
|
||||||
for (unsigned i = 0, e = I_dirs.size(); i != e; ++i) {
|
|
||||||
if (I_dirs[i] == "-") {
|
|
||||||
// -I- is a deprecated GCC feature.
|
|
||||||
Diags.Report(SourceLocation(), diag::err_pp_I_dash_not_supported);
|
|
||||||
} else {
|
|
||||||
AddPath(I_dirs[i], Angled, false, true, false, FM);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle -idirafter... options.
|
|
||||||
for (unsigned i = 0, e = idirafter_dirs.size(); i != e; ++i)
|
|
||||||
AddPath(idirafter_dirs[i], After, false, true, false, FM);
|
|
||||||
|
|
||||||
// Handle -iquote... options.
|
|
||||||
for (unsigned i = 0, e = iquote_dirs.size(); i != e; ++i)
|
|
||||||
AddPath(iquote_dirs[i], Quoted, false, true, false, FM);
|
|
||||||
|
|
||||||
// Handle -isystem... options.
|
|
||||||
for (unsigned i = 0, e = isystem_dirs.size(); i != e; ++i)
|
|
||||||
AddPath(isystem_dirs[i], System, false, true, false, FM);
|
|
||||||
|
|
||||||
// Walk the -iprefix/-iwithprefix/-iwithprefixbefore argument lists in
|
|
||||||
// parallel, processing the values in order of occurance to get the right
|
|
||||||
// prefixes.
|
|
||||||
{
|
|
||||||
std::string Prefix = ""; // FIXME: this isn't the correct default prefix.
|
|
||||||
unsigned iprefix_idx = 0;
|
|
||||||
unsigned iwithprefix_idx = 0;
|
|
||||||
unsigned iwithprefixbefore_idx = 0;
|
|
||||||
bool iprefix_done = iprefix_vals.empty();
|
|
||||||
bool iwithprefix_done = iwithprefix_vals.empty();
|
|
||||||
bool iwithprefixbefore_done = iwithprefixbefore_vals.empty();
|
|
||||||
while (!iprefix_done || !iwithprefix_done || !iwithprefixbefore_done) {
|
|
||||||
if (!iprefix_done &&
|
|
||||||
(iwithprefix_done ||
|
|
||||||
iprefix_vals.getPosition(iprefix_idx) <
|
|
||||||
iwithprefix_vals.getPosition(iwithprefix_idx)) &&
|
|
||||||
(iwithprefixbefore_done ||
|
|
||||||
iprefix_vals.getPosition(iprefix_idx) <
|
|
||||||
iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) {
|
|
||||||
Prefix = iprefix_vals[iprefix_idx];
|
|
||||||
++iprefix_idx;
|
|
||||||
iprefix_done = iprefix_idx == iprefix_vals.size();
|
|
||||||
} else if (!iwithprefix_done &&
|
|
||||||
(iwithprefixbefore_done ||
|
|
||||||
iwithprefix_vals.getPosition(iwithprefix_idx) <
|
|
||||||
iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) {
|
|
||||||
AddPath(Prefix+iwithprefix_vals[iwithprefix_idx],
|
|
||||||
System, false, false, false, FM);
|
|
||||||
++iwithprefix_idx;
|
|
||||||
iwithprefix_done = iwithprefix_idx == iwithprefix_vals.size();
|
|
||||||
} else {
|
|
||||||
AddPath(Prefix+iwithprefixbefore_vals[iwithprefixbefore_idx],
|
|
||||||
Angled, false, false, false, FM);
|
|
||||||
++iwithprefixbefore_idx;
|
|
||||||
iwithprefixbefore_done =
|
|
||||||
iwithprefixbefore_idx == iwithprefixbefore_vals.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Add contents of the CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH,
|
|
||||||
// OBJC_INCLUDE_PATH, OBJCPLUS_INCLUDE_PATH environment variables.
|
|
||||||
|
|
||||||
// FIXME: temporary hack: hard-coded paths.
|
|
||||||
// FIXME: get these from the target?
|
|
||||||
if (!nostdinc) {
|
|
||||||
if (Lang.CPlusPlus) {
|
|
||||||
AddPath("/usr/include/c++/4.0.0", System, true, false, false, FM);
|
|
||||||
AddPath("/usr/include/c++/4.0.0/i686-apple-darwin8", System, true, false,
|
|
||||||
false, FM);
|
|
||||||
AddPath("/usr/include/c++/4.0.0/backward", System, true, false, false,FM);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddPath("/usr/local/include", System, false, false, false, FM);
|
|
||||||
// leopard
|
|
||||||
AddPath("/usr/lib/gcc/i686-apple-darwin9/4.0.1/include", System,
|
|
||||||
false, false, false, FM);
|
|
||||||
AddPath("/usr/lib/gcc/powerpc-apple-darwin9/4.0.1/include",
|
|
||||||
System, false, false, false, FM);
|
|
||||||
AddPath("/usr/lib/gcc/powerpc-apple-darwin9/"
|
|
||||||
"4.0.1/../../../../powerpc-apple-darwin0/include",
|
|
||||||
System, false, false, false, FM);
|
|
||||||
|
|
||||||
// tiger
|
|
||||||
AddPath("/usr/lib/gcc/i686-apple-darwin8/4.0.1/include", System,
|
|
||||||
false, false, false, FM);
|
|
||||||
AddPath("/usr/lib/gcc/powerpc-apple-darwin8/4.0.1/include",
|
|
||||||
System, false, false, false, FM);
|
|
||||||
AddPath("/usr/lib/gcc/powerpc-apple-darwin8/"
|
|
||||||
"4.0.1/../../../../powerpc-apple-darwin8/include",
|
|
||||||
System, false, false, false, FM);
|
|
||||||
|
|
||||||
AddPath("/usr/include", System, false, false, false, FM);
|
|
||||||
AddPath("/System/Library/Frameworks", System, true, false, true, FM);
|
|
||||||
AddPath("/Library/Frameworks", System, true, false, true, FM);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we have collected all of the include paths, merge them all
|
|
||||||
// together and tell the preprocessor about them.
|
|
||||||
|
|
||||||
// Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList.
|
|
||||||
std::vector<DirectoryLookup> SearchList;
|
|
||||||
SearchList = IncludeGroup[Angled];
|
|
||||||
SearchList.insert(SearchList.end(), IncludeGroup[System].begin(),
|
|
||||||
IncludeGroup[System].end());
|
|
||||||
SearchList.insert(SearchList.end(), IncludeGroup[After].begin(),
|
|
||||||
IncludeGroup[After].end());
|
|
||||||
RemoveDuplicates(SearchList);
|
|
||||||
RemoveDuplicates(IncludeGroup[Quoted]);
|
|
||||||
|
|
||||||
// Prepend QUOTED list on the search list.
|
|
||||||
SearchList.insert(SearchList.begin(), IncludeGroup[Quoted].begin(),
|
|
||||||
IncludeGroup[Quoted].end());
|
|
||||||
|
|
||||||
|
|
||||||
bool DontSearchCurDir = false; // TODO: set to true if -I- is set?
|
|
||||||
Headers.SetSearchPaths(SearchList, IncludeGroup[Quoted].size(),
|
|
||||||
DontSearchCurDir);
|
|
||||||
|
|
||||||
// If verbose, print the list of directories that will be searched.
|
|
||||||
if (Verbose) {
|
|
||||||
fprintf(stderr, "#include \"...\" search starts here:\n");
|
|
||||||
unsigned QuotedIdx = IncludeGroup[Quoted].size();
|
|
||||||
for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
|
|
||||||
if (i == QuotedIdx)
|
|
||||||
fprintf(stderr, "#include <...> search starts here:\n");
|
|
||||||
fprintf(stderr, " %s\n", SearchList[i].getDir()->getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Read any files specified by -imacros or -include.
|
|
||||||
static void ReadPrologFiles(Preprocessor &PP, std::vector<char> &Buf) {
|
|
||||||
// FIXME: IMPLEMENT
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Basic Parser driver
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
static void ParseFile(Preprocessor &PP, MinimalAction *PA, unsigned MainFileID){
|
|
||||||
Parser P(PP, *PA);
|
|
||||||
PP.EnterSourceFile(MainFileID, 0, true);
|
|
||||||
|
|
||||||
// Parsing the specified input file.
|
|
||||||
P.ParseTranslationUnit();
|
|
||||||
delete PA;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Main driver
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// InitializePreprocessor - Initialize the preprocessor getting it and the
|
|
||||||
/// environment ready to process a single file. This returns the file ID for the
|
|
||||||
/// input file. If a failure happens, it returns 0.
|
|
||||||
///
|
|
||||||
static unsigned InitializePreprocessor(Preprocessor &PP,
|
|
||||||
const std::string &InFile,
|
|
||||||
SourceManager &SourceMgr,
|
|
||||||
HeaderSearch &HeaderInfo,
|
|
||||||
const LangOptions &LangInfo,
|
|
||||||
std::vector<char> &PrologMacros) {
|
|
||||||
FileManager &FileMgr = HeaderInfo.getFileMgr();
|
|
||||||
|
|
||||||
// Install things like __POWERPC__, __GNUC__, etc into the macro table.
|
|
||||||
InitializePredefinedMacros(PP, PrologMacros);
|
|
||||||
|
|
||||||
// Read any files specified by -imacros or -include.
|
|
||||||
ReadPrologFiles(PP, PrologMacros);
|
|
||||||
|
|
||||||
// Figure out where to get and map in the main file.
|
|
||||||
unsigned MainFileID = 0;
|
|
||||||
if (InFile != "-") {
|
|
||||||
const FileEntry *File = FileMgr.getFile(InFile);
|
|
||||||
if (File) MainFileID = SourceMgr.createFileID(File, SourceLocation());
|
|
||||||
if (MainFileID == 0) {
|
|
||||||
fprintf(stderr, "Error reading '%s'!\n",InFile.c_str());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN();
|
|
||||||
if (SB) MainFileID = SourceMgr.createFileIDForMemBuffer(SB);
|
|
||||||
if (MainFileID == 0) {
|
|
||||||
fprintf(stderr, "Error reading standard input! Empty?\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we have emitted the predefined macros, #includes, etc into
|
|
||||||
// PrologMacros, preprocess it to populate the initial preprocessor state.
|
|
||||||
|
|
||||||
// Memory buffer must end with a null byte!
|
|
||||||
PrologMacros.push_back(0);
|
|
||||||
|
|
||||||
llvm::MemoryBuffer *SB =
|
|
||||||
llvm::MemoryBuffer::getMemBuffer(&PrologMacros.front(),&PrologMacros.back(),
|
|
||||||
"<predefines>");
|
|
||||||
assert(SB && "Cannot fail to create predefined source buffer");
|
|
||||||
unsigned FileID = SourceMgr.createFileIDForMemBuffer(SB);
|
|
||||||
assert(FileID && "Could not create FileID for predefines?");
|
|
||||||
|
|
||||||
// Start parsing the predefines.
|
|
||||||
PP.EnterSourceFile(FileID, 0);
|
|
||||||
|
|
||||||
// Lex the file, which will read all the macros.
|
|
||||||
Token Tok;
|
|
||||||
PP.Lex(Tok);
|
|
||||||
assert(Tok.getKind() == tok::eof && "Didn't read entire file!");
|
|
||||||
|
|
||||||
// Once we've read this, we're done.
|
|
||||||
return MainFileID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ProcessInputFile - Process a single input file with the specified state.
|
|
||||||
///
|
|
||||||
static void ProcessInputFile(Preprocessor &PP, unsigned MainFileID,
|
|
||||||
const std::string &InFile,
|
|
||||||
SourceManager &SourceMgr,
|
|
||||||
TextDiagnostics &OurDiagnosticClient,
|
|
||||||
HeaderSearch &HeaderInfo,
|
|
||||||
const LangOptions &LangInfo) {
|
|
||||||
bool ClearSourceMgr = false;
|
|
||||||
switch (ProgAction) {
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Unexpected program action!\n");
|
|
||||||
return;
|
|
||||||
case DumpTokens: { // Token dump mode.
|
|
||||||
Token Tok;
|
|
||||||
// Start parsing the specified input file.
|
|
||||||
PP.EnterSourceFile(MainFileID, 0, true);
|
|
||||||
do {
|
|
||||||
PP.Lex(Tok);
|
|
||||||
PP.DumpToken(Tok, true);
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
} while (Tok.getKind() != tok::eof);
|
|
||||||
ClearSourceMgr = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RunPreprocessorOnly: { // Just lex as fast as we can, no output.
|
|
||||||
Token Tok;
|
|
||||||
// Start parsing the specified input file.
|
|
||||||
PP.EnterSourceFile(MainFileID, 0, true);
|
|
||||||
do {
|
|
||||||
PP.Lex(Tok);
|
|
||||||
} while (Tok.getKind() != tok::eof);
|
|
||||||
ClearSourceMgr = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PrintPreprocessedInput: // -E mode.
|
|
||||||
DoPrintPreprocessedInput(MainFileID, PP, LangInfo);
|
|
||||||
ClearSourceMgr = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ParseNoop: // -parse-noop
|
|
||||||
ParseFile(PP, new MinimalAction(), MainFileID);
|
|
||||||
ClearSourceMgr = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ParsePrintCallbacks:
|
|
||||||
ParseFile(PP, CreatePrintParserActionsAction(), MainFileID);
|
|
||||||
ClearSourceMgr = true;
|
|
||||||
break;
|
|
||||||
case ParseSyntaxOnly: // -fsyntax-only
|
|
||||||
case ParseAST:
|
|
||||||
BuildASTs(PP, MainFileID, Stats);
|
|
||||||
break;
|
|
||||||
case ParseASTPrint:
|
|
||||||
PrintASTs(PP, MainFileID, Stats);
|
|
||||||
break;
|
|
||||||
case ParseASTDump:
|
|
||||||
DumpASTs(PP, MainFileID, Stats);
|
|
||||||
break;
|
|
||||||
case ParseCFGDump:
|
|
||||||
DumpCFGs(PP, MainFileID, Stats);
|
|
||||||
break;
|
|
||||||
case ParseCFGView:
|
|
||||||
DumpCFGs(PP, MainFileID, Stats, true);
|
|
||||||
break;
|
|
||||||
case AnalysisLiveVariables:
|
|
||||||
AnalyzeLiveVariables(PP, MainFileID);
|
|
||||||
break;
|
|
||||||
case WarnDeadStores:
|
|
||||||
RunDeadStoresCheck(PP, MainFileID, Stats);
|
|
||||||
break;
|
|
||||||
case EmitLLVM:
|
|
||||||
EmitLLVMFromASTs(PP, MainFileID, Stats);
|
|
||||||
break;
|
|
||||||
case ParseASTCheck:
|
|
||||||
exit(CheckDiagnostics(PP, MainFileID));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Stats) {
|
|
||||||
fprintf(stderr, "\nSTATISTICS FOR '%s':\n", InFile.c_str());
|
|
||||||
PP.PrintStats();
|
|
||||||
PP.getIdentifierTable().PrintStats();
|
|
||||||
HeaderInfo.PrintStats();
|
|
||||||
if (ClearSourceMgr)
|
|
||||||
SourceMgr.PrintStats();
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// For a multi-file compilation, some things are ok with nuking the source
|
|
||||||
// manager tables, other require stable fileid/macroid's across multiple
|
|
||||||
// files.
|
|
||||||
if (ClearSourceMgr) {
|
|
||||||
SourceMgr.clearIDTables();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static llvm::cl::list<std::string>
|
|
||||||
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input files>"));
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
llvm::cl::ParseCommandLineOptions(argc, argv, " llvm cfe\n");
|
|
||||||
llvm::sys::PrintStackTraceOnErrorSignal();
|
|
||||||
|
|
||||||
// If no input was specified, read from stdin.
|
|
||||||
if (InputFilenames.empty())
|
|
||||||
InputFilenames.push_back("-");
|
|
||||||
|
|
||||||
/// Create a SourceManager object. This tracks and owns all the file buffers
|
|
||||||
/// allocated to the program.
|
|
||||||
SourceManager SourceMgr;
|
|
||||||
|
|
||||||
// Create a file manager object to provide access to and cache the filesystem.
|
|
||||||
FileManager FileMgr;
|
|
||||||
|
|
||||||
// Initialize language options, inferring file types from input filenames.
|
|
||||||
// FIXME: This infers info from the first file, we should clump by language
|
|
||||||
// to handle 'x.c y.c a.cpp b.cpp'.
|
|
||||||
LangOptions LangInfo;
|
|
||||||
InitializeBaseLanguage(LangInfo, InputFilenames[0]);
|
|
||||||
InitializeLanguageStandard(LangInfo);
|
|
||||||
|
|
||||||
std::auto_ptr<TextDiagnostics> DiagClient;
|
|
||||||
if (ProgAction != ParseASTCheck) {
|
|
||||||
// Print diagnostics to stderr by default.
|
|
||||||
DiagClient.reset(new TextDiagnosticPrinter(SourceMgr));
|
|
||||||
} else {
|
|
||||||
// When checking diagnostics, just buffer them up.
|
|
||||||
DiagClient.reset(new TextDiagnosticBuffer(SourceMgr));
|
|
||||||
|
|
||||||
if (InputFilenames.size() != 1) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"parse-ast-check only works on single input files for now.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure our handling of diagnostics.
|
|
||||||
Diagnostic Diags(*DiagClient);
|
|
||||||
InitializeDiagnostics(Diags);
|
|
||||||
|
|
||||||
// Get information about the targets being compiled for. Note that this
|
|
||||||
// pointer and the TargetInfoImpl objects are never deleted by this toy
|
|
||||||
// driver.
|
|
||||||
TargetInfo *Target = CreateTargetInfo(Diags);
|
|
||||||
if (Target == 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Sorry, don't know what target this is, please use -arch.\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the -I options and set them in the HeaderInfo.
|
|
||||||
HeaderSearch HeaderInfo(FileMgr);
|
|
||||||
DiagClient->setHeaderSearch(HeaderInfo);
|
|
||||||
InitializeIncludePaths(HeaderInfo, FileMgr, Diags, LangInfo);
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
|
|
||||||
// Set up the preprocessor with these options.
|
|
||||||
Preprocessor PP(Diags, LangInfo, *Target, SourceMgr, HeaderInfo);
|
|
||||||
DiagClient->setPreprocessor(PP);
|
|
||||||
const std::string &InFile = InputFilenames[i];
|
|
||||||
std::vector<char> PrologMacros;
|
|
||||||
unsigned MainFileID = InitializePreprocessor(PP, InFile, SourceMgr,
|
|
||||||
HeaderInfo, LangInfo,
|
|
||||||
PrologMacros);
|
|
||||||
|
|
||||||
if (!MainFileID) continue;
|
|
||||||
|
|
||||||
ProcessInputFile(PP, MainFileID, InFile, SourceMgr,
|
|
||||||
*DiagClient, HeaderInfo, LangInfo);
|
|
||||||
HeaderInfo.ClearFileInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned NumDiagnostics = Diags.getNumDiagnostics();
|
|
||||||
|
|
||||||
if (NumDiagnostics)
|
|
||||||
fprintf(stderr, "%d diagnostic%s generated.\n", NumDiagnostics,
|
|
||||||
(NumDiagnostics == 1 ? "" : "s"));
|
|
||||||
|
|
||||||
if (Stats) {
|
|
||||||
// Printed from high-to-low level.
|
|
||||||
SourceMgr.PrintStats();
|
|
||||||
FileMgr.PrintStats();
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Diags.getNumErrors() != 0;
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
//===--- clang.h - C-Language Front-end -----------------------------------===//
|
|
||||||
//
|
|
||||||
// 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 is the header file that pulls together the top-level driver.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef LLVM_CLANG_CLANG_H
|
|
||||||
#define LLVM_CLANG_CLANG_H
|
|
||||||
|
|
||||||
namespace clang {
|
|
||||||
class Preprocessor;
|
|
||||||
struct LangOptions;
|
|
||||||
class MinimalAction;
|
|
||||||
class TargetInfo;
|
|
||||||
class Diagnostic;
|
|
||||||
|
|
||||||
/// DoPrintPreprocessedInput - Implement -E mode.
|
|
||||||
void DoPrintPreprocessedInput(unsigned MainFileID, Preprocessor &PP,
|
|
||||||
const LangOptions &Options);
|
|
||||||
|
|
||||||
/// CreatePrintParserActionsAction - Return the actions implementation that
|
|
||||||
/// implements the -parse-print-callbacks option.
|
|
||||||
MinimalAction *CreatePrintParserActionsAction();
|
|
||||||
|
|
||||||
/// CreateTargetInfo - Return the set of target info objects as specified by
|
|
||||||
/// the -arch command line option.
|
|
||||||
TargetInfo *CreateTargetInfo(Diagnostic &Diags);
|
|
||||||
|
|
||||||
/// EmitLLVMFromASTs - Implement -emit-llvm, which generates llvm IR from C.
|
|
||||||
void EmitLLVMFromASTs(Preprocessor &PP, unsigned MainFileID,
|
|
||||||
bool PrintStats);
|
|
||||||
|
|
||||||
/// CheckDiagnostics - Implement the -parse-ast-check diagnostic verifier.
|
|
||||||
bool CheckDiagnostics(Preprocessor &PP, unsigned MainFileID);
|
|
||||||
|
|
||||||
} // end namespace clang
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
|
|
||||||
#include <Carbon/Carbon.h>
|
|
||||||
|
|
||||||
//#import<vecLib/vecLib.h>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
// clang -I/usr/include/c++/4.0.0 -I/usr/include/c++/4.0.0/powerpc-apple-darwin8 -I/usr/include/c++/4.0.0/backward INPUTS/iostream.cc -Eonly
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
|
|
||||||
// This pounds on macro expansion for performance reasons. This is currently
|
|
||||||
// heavily constrained by darwin's malloc.
|
|
||||||
|
|
||||||
// Function-like macros.
|
|
||||||
#define A0(A, B) A B
|
|
||||||
#define A1(A, B) A0(A,B) A0(A,B) A0(A,B) A0(A,B) A0(A,B) A0(A,B)
|
|
||||||
#define A2(A, B) A1(A,B) A1(A,B) A1(A,B) A1(A,B) A1(A,B) A1(A,B)
|
|
||||||
#define A3(A, B) A2(A,B) A2(A,B) A2(A,B) A2(A,B) A2(A,B) A2(A,B)
|
|
||||||
#define A4(A, B) A3(A,B) A3(A,B) A3(A,B) A3(A,B) A3(A,B) A3(A,B)
|
|
||||||
#define A5(A, B) A4(A,B) A4(A,B) A4(A,B) A4(A,B) A4(A,B) A4(A,B)
|
|
||||||
#define A6(A, B) A5(A,B) A5(A,B) A5(A,B) A5(A,B) A5(A,B) A5(A,B)
|
|
||||||
#define A7(A, B) A6(A,B) A6(A,B) A6(A,B) A6(A,B) A6(A,B) A6(A,B)
|
|
||||||
#define A8(A, B) A7(A,B) A7(A,B) A7(A,B) A7(A,B) A7(A,B) A7(A,B)
|
|
||||||
|
|
||||||
A8(a, b)
|
|
||||||
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
|
|
||||||
// This pounds on macro expansion for performance reasons. This is currently
|
|
||||||
// heavily constrained by darwin's malloc.
|
|
||||||
|
|
||||||
// Object-like expansions
|
|
||||||
#define A0 a b
|
|
||||||
#define A1 A0 A0 A0 A0 A0 A0
|
|
||||||
#define A2 A1 A1 A1 A1 A1 A1
|
|
||||||
#define A3 A2 A2 A2 A2 A2 A2
|
|
||||||
#define A4 A3 A3 A3 A3 A3 A3
|
|
||||||
#define A5 A4 A4 A4 A4 A4 A4
|
|
||||||
#define A6 A5 A5 A5 A5 A5 A5
|
|
||||||
#define A7 A6 A6 A6 A6 A6 A6
|
|
||||||
#define A8 A7 A7 A7 A7 A7 A7
|
|
||||||
|
|
||||||
A8
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#define __extension__
|
|
||||||
|
|
||||||
#define __stpcpy(dest, src) (__extension__ (__builtin_constant_p (src) ? (__string2_1bptr_p (src) && strlen (src) + 1 <= 8 ? __stpcpy_small (dest, __stpcpy_args (src), strlen (src) + 1) : ((char *) __mempcpy (dest, src, strlen (src) + 1) - 1)) : __stpcpy (dest, src)))
|
|
||||||
#define stpcpy(dest, src) __stpcpy (dest, src)
|
|
||||||
#define __stpcpy_args(src) __extension__ __STRING2_SMALL_GET16 (src, 0), __extension__ __STRING2_SMALL_GET16 (src, 4), __extension__ __STRING2_SMALL_GET32 (src, 0), __extension__ __STRING2_SMALL_GET32 (src, 4)
|
|
||||||
|
|
||||||
#define __mempcpy(dest, src, n) (__extension__ (__builtin_constant_p (src) && __builtin_constant_p (n) && __string2_1bptr_p (src) && n <= 8 ? __mempcpy_small (dest, __mempcpy_args (src), n) : __mempcpy (dest, src, n)))
|
|
||||||
#define mempcpy(dest, src, n) __mempcpy (dest, src, n)
|
|
||||||
#define __mempcpy_args(src) ((char *) (src))[0], ((char *) (src))[2], ((char *) (src))[4], ((char *) (src))[6], __extension__ __STRING2_SMALL_GET16 (src, 0), __extension__ __STRING2_SMALL_GET16 (src, 4), __extension__ __STRING2_SMALL_GET32 (src, 0), __extension__ __STRING2_SMALL_GET32 (src, 4)
|
|
||||||
|
|
||||||
#define __STRING2_SMALL_GET16(src, idx) (((__const unsigned char *) (__const char *) (src))[idx + 1] << 8 | ((__const unsigned char *) (__const char *) (src))[idx])
|
|
||||||
|
|
||||||
#define __STRING2_SMALL_GET32(src, idx) (((((__const unsigned char *) (__const char *) (src))[idx + 3] << 8 | ((__const unsigned char *) (__const char *) (src))[idx + 2]) << 8 | ((__const unsigned char *) (__const char *) (src))[idx + 1]) << 8 | ((__const unsigned char *) (__const char *) (src))[idx])
|
|
||||||
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
==============================================================================
|
|
||||||
LLVM Release License
|
|
||||||
==============================================================================
|
|
||||||
University of Illinois/NCSA
|
|
||||||
Open Source License
|
|
||||||
|
|
||||||
Copyright (c) 2007 University of Illinois at Urbana-Champaign.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Developed by:
|
|
||||||
|
|
||||||
LLVM Team
|
|
||||||
|
|
||||||
University of Illinois at Urbana-Champaign
|
|
||||||
|
|
||||||
http://llvm.org
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal with
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
so, subject to the following conditions:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimers.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimers in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
* Neither the names of the LLVM Team, University of Illinois at
|
|
||||||
Urbana-Champaign, nor the names of its contributors may be used to
|
|
||||||
endorse or promote products derived from this Software without specific
|
|
||||||
prior written permission.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
The LLVM software contains code written by third parties. Such software will
|
|
||||||
have its own individual LICENSE.TXT file in the directory in which it appears.
|
|
||||||
This file will describe the copyrights, license, and restrictions which apply
|
|
||||||
to that code.
|
|
||||||
|
|
||||||
The disclaimer of warranty in the University of Illinois Open Source License
|
|
||||||
applies to all code in the LLVM Distribution, and nothing in any of the
|
|
||||||
other licenses gives permission to use the names of the LLVM Team or the
|
|
||||||
University of Illinois to endorse or promote products derived from this
|
|
||||||
Software.
|
|
||||||
|
|
||||||
The following pieces of software have additional or alternate copyrights,
|
|
||||||
licenses, and/or restrictions:
|
|
||||||
|
|
||||||
Program Directory
|
|
||||||
------- ---------
|
|
||||||
<none yet>
|
|
||||||
|
|
||||||
@@ -1,343 +0,0 @@
|
|||||||
//===--- HeaderSearch.cpp - Resolve Header File Locations ---===//
|
|
||||||
//
|
|
||||||
// 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 DirectoryLookup and HeaderSearch interfaces.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Basic/FileManager.h"
|
|
||||||
#include "clang/Lex/HeaderSearch.h"
|
|
||||||
#include "clang/Lex/IdentifierTable.h"
|
|
||||||
#include "llvm/System/Path.h"
|
|
||||||
#include "llvm/ADT/SmallString.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
HeaderSearch::HeaderSearch(FileManager &FM) : FileMgr(FM), FrameworkMap(64) {
|
|
||||||
SystemDirIdx = 0;
|
|
||||||
NoCurDirSearch = false;
|
|
||||||
|
|
||||||
NumIncluded = 0;
|
|
||||||
NumMultiIncludeFileOptzn = 0;
|
|
||||||
NumFrameworkLookups = NumSubFrameworkLookups = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HeaderSearch::PrintStats() {
|
|
||||||
fprintf(stderr, "\n*** HeaderSearch Stats:\n");
|
|
||||||
fprintf(stderr, "%d files tracked.\n", (int)FileInfo.size());
|
|
||||||
unsigned NumOnceOnlyFiles = 0, MaxNumIncludes = 0, NumSingleIncludedFiles = 0;
|
|
||||||
for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) {
|
|
||||||
NumOnceOnlyFiles += FileInfo[i].isImport;
|
|
||||||
if (MaxNumIncludes < FileInfo[i].NumIncludes)
|
|
||||||
MaxNumIncludes = FileInfo[i].NumIncludes;
|
|
||||||
NumSingleIncludedFiles += FileInfo[i].NumIncludes == 1;
|
|
||||||
}
|
|
||||||
fprintf(stderr, " %d #import/#pragma once files.\n", NumOnceOnlyFiles);
|
|
||||||
fprintf(stderr, " %d included exactly once.\n", NumSingleIncludedFiles);
|
|
||||||
fprintf(stderr, " %d max times a file is included.\n", MaxNumIncludes);
|
|
||||||
|
|
||||||
fprintf(stderr, " %d #include/#include_next/#import.\n", NumIncluded);
|
|
||||||
fprintf(stderr, " %d #includes skipped due to"
|
|
||||||
" the multi-include optimization.\n", NumMultiIncludeFileOptzn);
|
|
||||||
|
|
||||||
fprintf(stderr, "%d framework lookups.\n", NumFrameworkLookups);
|
|
||||||
fprintf(stderr, "%d subframework lookups.\n", NumSubFrameworkLookups);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Header File Location.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
const FileEntry *HeaderSearch::DoFrameworkLookup(const DirectoryEntry *Dir,
|
|
||||||
const char *FilenameStart,
|
|
||||||
const char *FilenameEnd) {
|
|
||||||
// Framework names must have a '/' in the filename.
|
|
||||||
const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/');
|
|
||||||
if (SlashPos == FilenameEnd) return 0;
|
|
||||||
|
|
||||||
llvm::StringMapEntry<const DirectoryEntry *> &CacheLookup =
|
|
||||||
FrameworkMap.GetOrCreateValue(FilenameStart, SlashPos);
|
|
||||||
|
|
||||||
// If it is some other directory, fail.
|
|
||||||
if (CacheLookup.getValue() && CacheLookup.getValue() != Dir)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// FrameworkName = "/System/Library/Frameworks/"
|
|
||||||
llvm::SmallString<1024> FrameworkName;
|
|
||||||
FrameworkName += Dir->getName();
|
|
||||||
if (FrameworkName.empty() || FrameworkName.back() != '/')
|
|
||||||
FrameworkName.push_back('/');
|
|
||||||
|
|
||||||
// FrameworkName = "/System/Library/Frameworks/Cocoa"
|
|
||||||
FrameworkName.append(FilenameStart, SlashPos);
|
|
||||||
|
|
||||||
// FrameworkName = "/System/Library/Frameworks/Cocoa.framework/"
|
|
||||||
FrameworkName += ".framework/";
|
|
||||||
|
|
||||||
if (CacheLookup.getValue() == 0) {
|
|
||||||
++NumFrameworkLookups;
|
|
||||||
|
|
||||||
// If the framework dir doesn't exist, we fail.
|
|
||||||
if (!llvm::sys::Path(std::string(FrameworkName.begin(),
|
|
||||||
FrameworkName.end())).exists())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Otherwise, if it does, remember that this is the right direntry for this
|
|
||||||
// framework.
|
|
||||||
CacheLookup.setValue(Dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
|
|
||||||
unsigned OrigSize = FrameworkName.size();
|
|
||||||
|
|
||||||
FrameworkName += "Headers/";
|
|
||||||
FrameworkName.append(SlashPos+1, FilenameEnd);
|
|
||||||
if (const FileEntry *FE = FileMgr.getFile(FrameworkName.begin(),
|
|
||||||
FrameworkName.end())) {
|
|
||||||
return FE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
|
|
||||||
const char *Private = "Private";
|
|
||||||
FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
|
|
||||||
Private+strlen(Private));
|
|
||||||
return FileMgr.getFile(FrameworkName.begin(), FrameworkName.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
|
|
||||||
/// return null on failure. isAngled indicates whether the file reference is
|
|
||||||
/// for system #include's or not (i.e. using <> instead of ""). CurFileEnt, if
|
|
||||||
/// non-null, indicates where the #including file is, in case a relative search
|
|
||||||
/// is needed.
|
|
||||||
const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
|
|
||||||
const char *FilenameEnd,
|
|
||||||
bool isAngled,
|
|
||||||
const DirectoryLookup *FromDir,
|
|
||||||
const DirectoryLookup *&CurDir,
|
|
||||||
const FileEntry *CurFileEnt) {
|
|
||||||
// If 'Filename' is absolute, check to see if it exists and no searching.
|
|
||||||
// FIXME: Portability. This should be a sys::Path interface, this doesn't
|
|
||||||
// handle things like C:\foo.txt right, nor win32 \\network\device\blah.
|
|
||||||
if (FilenameStart[0] == '/') {
|
|
||||||
CurDir = 0;
|
|
||||||
|
|
||||||
// If this was an #include_next "/absolute/file", fail.
|
|
||||||
if (FromDir) return 0;
|
|
||||||
|
|
||||||
// Otherwise, just return the file.
|
|
||||||
return FileMgr.getFile(FilenameStart, FilenameEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::SmallString<1024> TmpDir;
|
|
||||||
|
|
||||||
// Step #0, unless disabled, check to see if the file is in the #includer's
|
|
||||||
// directory. This search is not done for <> headers.
|
|
||||||
if (CurFileEnt && !isAngled && !NoCurDirSearch) {
|
|
||||||
// Concatenate the requested file onto the directory.
|
|
||||||
// FIXME: Portability. Filename concatenation should be in sys::Path.
|
|
||||||
TmpDir += CurFileEnt->getDir()->getName();
|
|
||||||
TmpDir.push_back('/');
|
|
||||||
TmpDir.append(FilenameStart, FilenameEnd);
|
|
||||||
if (const FileEntry *FE = FileMgr.getFile(TmpDir.begin(), TmpDir.end())) {
|
|
||||||
// Leave CurDir unset.
|
|
||||||
|
|
||||||
// This file is a system header or C++ unfriendly if the old file is.
|
|
||||||
getFileInfo(FE).DirInfo = getFileInfo(CurFileEnt).DirInfo;
|
|
||||||
return FE;
|
|
||||||
}
|
|
||||||
TmpDir.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
CurDir = 0;
|
|
||||||
|
|
||||||
// If this is a system #include, ignore the user #include locs.
|
|
||||||
unsigned i = isAngled ? SystemDirIdx : 0;
|
|
||||||
|
|
||||||
// If this is a #include_next request, start searching after the directory the
|
|
||||||
// file was found in.
|
|
||||||
if (FromDir)
|
|
||||||
i = FromDir-&SearchDirs[0];
|
|
||||||
|
|
||||||
// Cache all of the lookups performed by this method. Many headers are
|
|
||||||
// multiply included, and the "pragma once" optimization prevents them from
|
|
||||||
// being relex/pp'd, but they would still have to search through a
|
|
||||||
// (potentially huge) series of SearchDirs to find it.
|
|
||||||
std::pair<unsigned, unsigned> &CacheLookup =
|
|
||||||
LookupFileCache.GetOrCreateValue(FilenameStart, FilenameEnd).getValue();
|
|
||||||
|
|
||||||
// If the entry has been previously looked up, the first value will be
|
|
||||||
// non-zero. If the value is equal to i (the start point of our search), then
|
|
||||||
// this is a matching hit.
|
|
||||||
if (CacheLookup.first == i+1) {
|
|
||||||
// Skip querying potentially lots of directories for this lookup.
|
|
||||||
i = CacheLookup.second;
|
|
||||||
} else {
|
|
||||||
// Otherwise, this is the first query, or the previous query didn't match
|
|
||||||
// our search start. We will fill in our found location below, so prime the
|
|
||||||
// start point value.
|
|
||||||
CacheLookup.first = i+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check each directory in sequence to see if it contains this file.
|
|
||||||
for (; i != SearchDirs.size(); ++i) {
|
|
||||||
const FileEntry *FE = 0;
|
|
||||||
if (!SearchDirs[i].isFramework()) {
|
|
||||||
// FIXME: Portability. Adding file to dir should be in sys::Path.
|
|
||||||
// Concatenate the requested file onto the directory.
|
|
||||||
TmpDir.clear();
|
|
||||||
TmpDir += SearchDirs[i].getDir()->getName();
|
|
||||||
TmpDir.push_back('/');
|
|
||||||
TmpDir.append(FilenameStart, FilenameEnd);
|
|
||||||
FE = FileMgr.getFile(TmpDir.begin(), TmpDir.end());
|
|
||||||
} else {
|
|
||||||
FE = DoFrameworkLookup(SearchDirs[i].getDir(), FilenameStart,FilenameEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FE) {
|
|
||||||
CurDir = &SearchDirs[i];
|
|
||||||
|
|
||||||
// This file is a system header or C++ unfriendly if the dir is.
|
|
||||||
getFileInfo(FE).DirInfo = CurDir->getDirCharacteristic();
|
|
||||||
|
|
||||||
// Remember this location for the next lookup we do.
|
|
||||||
CacheLookup.second = i;
|
|
||||||
return FE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, didn't find it. Remember we didn't find this.
|
|
||||||
CacheLookup.second = SearchDirs.size();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// LookupSubframeworkHeader - Look up a subframework for the specified
|
|
||||||
/// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from
|
|
||||||
/// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
|
|
||||||
/// is a subframework within Carbon.framework. If so, return the FileEntry
|
|
||||||
/// for the designated file, otherwise return null.
|
|
||||||
const FileEntry *HeaderSearch::
|
|
||||||
LookupSubframeworkHeader(const char *FilenameStart,
|
|
||||||
const char *FilenameEnd,
|
|
||||||
const FileEntry *ContextFileEnt) {
|
|
||||||
// Framework names must have a '/' in the filename. Find it.
|
|
||||||
const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/');
|
|
||||||
if (SlashPos == FilenameEnd) return 0;
|
|
||||||
|
|
||||||
// Look up the base framework name of the ContextFileEnt.
|
|
||||||
const char *ContextName = ContextFileEnt->getName();
|
|
||||||
|
|
||||||
// If the context info wasn't a framework, couldn't be a subframework.
|
|
||||||
const char *FrameworkPos = strstr(ContextName, ".framework/");
|
|
||||||
if (FrameworkPos == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
llvm::SmallString<1024> FrameworkName(ContextName,
|
|
||||||
FrameworkPos+strlen(".framework/"));
|
|
||||||
|
|
||||||
// Append Frameworks/HIToolbox.framework/
|
|
||||||
FrameworkName += "Frameworks/";
|
|
||||||
FrameworkName.append(FilenameStart, SlashPos);
|
|
||||||
FrameworkName += ".framework/";
|
|
||||||
|
|
||||||
llvm::StringMapEntry<const DirectoryEntry *> &CacheLookup =
|
|
||||||
FrameworkMap.GetOrCreateValue(FilenameStart, SlashPos);
|
|
||||||
|
|
||||||
// Some other location?
|
|
||||||
if (CacheLookup.getValue() &&
|
|
||||||
CacheLookup.getKeyLength() == FrameworkName.size() &&
|
|
||||||
memcmp(CacheLookup.getKeyData(), &FrameworkName[0],
|
|
||||||
CacheLookup.getKeyLength()) != 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Cache subframework.
|
|
||||||
if (CacheLookup.getValue() == 0) {
|
|
||||||
++NumSubFrameworkLookups;
|
|
||||||
|
|
||||||
// If the framework dir doesn't exist, we fail.
|
|
||||||
const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.begin(),
|
|
||||||
FrameworkName.end());
|
|
||||||
if (Dir == 0) return 0;
|
|
||||||
|
|
||||||
// Otherwise, if it does, remember that this is the right direntry for this
|
|
||||||
// framework.
|
|
||||||
CacheLookup.setValue(Dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
const FileEntry *FE = 0;
|
|
||||||
|
|
||||||
// Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h"
|
|
||||||
llvm::SmallString<1024> HeadersFilename(FrameworkName);
|
|
||||||
HeadersFilename += "Headers/";
|
|
||||||
HeadersFilename.append(SlashPos+1, FilenameEnd);
|
|
||||||
if (!(FE = FileMgr.getFile(HeadersFilename.begin(),
|
|
||||||
HeadersFilename.end()))) {
|
|
||||||
|
|
||||||
// Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
|
|
||||||
HeadersFilename = FrameworkName;
|
|
||||||
HeadersFilename += "PrivateHeaders/";
|
|
||||||
HeadersFilename.append(SlashPos+1, FilenameEnd);
|
|
||||||
if (!(FE = FileMgr.getFile(HeadersFilename.begin(), HeadersFilename.end())))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This file is a system header or C++ unfriendly if the old file is.
|
|
||||||
getFileInfo(FE).DirInfo = getFileInfo(ContextFileEnt).DirInfo;
|
|
||||||
return FE;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// File Info Management.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
|
|
||||||
/// getFileInfo - Return the PerFileInfo structure for the specified
|
|
||||||
/// FileEntry.
|
|
||||||
HeaderSearch::PerFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
|
|
||||||
if (FE->getUID() >= FileInfo.size())
|
|
||||||
FileInfo.resize(FE->getUID()+1);
|
|
||||||
return FileInfo[FE->getUID()];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ShouldEnterIncludeFile - Mark the specified file as a target of of a
|
|
||||||
/// #include, #include_next, or #import directive. Return false if #including
|
|
||||||
/// the file will have no effect or true if we should include it.
|
|
||||||
bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
|
|
||||||
++NumIncluded; // Count # of attempted #includes.
|
|
||||||
|
|
||||||
// Get information about this file.
|
|
||||||
PerFileInfo &FileInfo = getFileInfo(File);
|
|
||||||
|
|
||||||
// If this is a #import directive, check that we have not already imported
|
|
||||||
// this header.
|
|
||||||
if (isImport) {
|
|
||||||
// If this has already been imported, don't import it again.
|
|
||||||
FileInfo.isImport = true;
|
|
||||||
|
|
||||||
// Has this already been #import'ed or #include'd?
|
|
||||||
if (FileInfo.NumIncludes) return false;
|
|
||||||
} else {
|
|
||||||
// Otherwise, if this is a #include of a file that was previously #import'd
|
|
||||||
// or if this is the second #include of a #pragma once file, ignore it.
|
|
||||||
if (FileInfo.isImport)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, check to see if the file is wrapped with #ifndef guards. If so, and
|
|
||||||
// if the macro that guards it is defined, we know the #include has no effect.
|
|
||||||
if (FileInfo.ControllingMacro && FileInfo.ControllingMacro->getMacroInfo()) {
|
|
||||||
++NumMultiIncludeFileOptzn;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment the number of times this file has been included.
|
|
||||||
++FileInfo.NumIncludes;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
//===--- IdentifierTable.cpp - Hash table for identifier lookup -----------===//
|
|
||||||
//
|
|
||||||
// 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 IdentifierInfo, IdentifierVisitor, and
|
|
||||||
// IdentifierTable interfaces.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Lex/IdentifierTable.h"
|
|
||||||
#include "clang/Lex/MacroInfo.h"
|
|
||||||
#include "clang/Basic/LangOptions.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Token Implementation
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// isObjCAtKeyword - Return true if we have an ObjC keyword identifier.
|
|
||||||
bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const {
|
|
||||||
return getKind() == tok::identifier &&
|
|
||||||
getIdentifierInfo()->getObjCKeywordID() == objcKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getObjCKeywordID - Return the ObjC keyword kind.
|
|
||||||
tok::ObjCKeywordKind Token::getObjCKeywordID() const {
|
|
||||||
IdentifierInfo *specId = getIdentifierInfo();
|
|
||||||
return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// IdentifierInfo Implementation
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
IdentifierInfo::IdentifierInfo() {
|
|
||||||
Macro = 0;
|
|
||||||
TokenID = tok::identifier;
|
|
||||||
PPID = tok::pp_not_keyword;
|
|
||||||
ObjCID = tok::objc_not_keyword;
|
|
||||||
BuiltinID = 0;
|
|
||||||
IsExtension = false;
|
|
||||||
IsPoisoned = false;
|
|
||||||
IsOtherTargetMacro = false;
|
|
||||||
IsCPPOperatorKeyword = false;
|
|
||||||
IsNonPortableBuiltin = false;
|
|
||||||
FETokenInfo = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
IdentifierInfo::~IdentifierInfo() {
|
|
||||||
delete Macro;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// IdentifierTable Implementation
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
IdentifierTable::IdentifierTable(const LangOptions &LangOpts)
|
|
||||||
// Start with space for 8K identifiers.
|
|
||||||
: HashTable(8192) {
|
|
||||||
|
|
||||||
// Populate the identifier table with info about keywords for the current
|
|
||||||
// language.
|
|
||||||
AddKeywords(LangOpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Language Keyword Implementation
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// AddKeyword - This method is used to associate a token ID with specific
|
|
||||||
/// identifiers because they are language keywords. This causes the lexer to
|
|
||||||
/// automatically map matching identifiers to specialized token codes.
|
|
||||||
///
|
|
||||||
/// The C90/C99/CPP/CPP0x flags are set to 0 if the token should be
|
|
||||||
/// enabled in the specified langauge, set to 1 if it is an extension
|
|
||||||
/// in the specified language, and set to 2 if disabled in the
|
|
||||||
/// specified language.
|
|
||||||
static void AddKeyword(const char *Keyword, unsigned KWLen,
|
|
||||||
tok::TokenKind TokenCode,
|
|
||||||
int C90, int C99, int CXX, int CXX0x,
|
|
||||||
const LangOptions &LangOpts, IdentifierTable &Table) {
|
|
||||||
int Flags = LangOpts.CPlusPlus ? (LangOpts.CPlusPlus0x? CXX0x : CXX)
|
|
||||||
: (LangOpts.C99 ? C99 : C90);
|
|
||||||
|
|
||||||
// Don't add this keyword if disabled in this language or if an extension
|
|
||||||
// and extensions are disabled.
|
|
||||||
if (Flags + LangOpts.NoExtensions >= 2) return;
|
|
||||||
|
|
||||||
IdentifierInfo &Info = Table.get(Keyword, Keyword+KWLen);
|
|
||||||
Info.setTokenID(TokenCode);
|
|
||||||
Info.setIsExtensionToken(Flags == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void AddAlias(const char *Keyword, unsigned KWLen,
|
|
||||||
const char *AliaseeKeyword, unsigned AliaseeKWLen,
|
|
||||||
const LangOptions &LangOpts, IdentifierTable &Table) {
|
|
||||||
IdentifierInfo &AliasInfo = Table.get(Keyword, Keyword+KWLen);
|
|
||||||
IdentifierInfo &AliaseeInfo = Table.get(AliaseeKeyword,
|
|
||||||
AliaseeKeyword+AliaseeKWLen);
|
|
||||||
AliasInfo.setTokenID(AliaseeInfo.getTokenID());
|
|
||||||
AliasInfo.setIsExtensionToken(AliaseeInfo.isExtensionToken());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AddPPKeyword - Register a preprocessor keyword like "define" "undef" or
|
|
||||||
/// "elif".
|
|
||||||
static void AddPPKeyword(tok::PPKeywordKind PPID,
|
|
||||||
const char *Name, unsigned NameLen,
|
|
||||||
IdentifierTable &Table) {
|
|
||||||
Table.get(Name, Name+NameLen).setPPKeywordID(PPID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative
|
|
||||||
/// representations.
|
|
||||||
static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen,
|
|
||||||
tok::TokenKind TokenCode,
|
|
||||||
IdentifierTable &Table) {
|
|
||||||
IdentifierInfo &Info = Table.get(Keyword, Keyword + KWLen);
|
|
||||||
Info.setTokenID(TokenCode);
|
|
||||||
Info.setIsCPlusplusOperatorKeyword();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or
|
|
||||||
/// "property".
|
|
||||||
static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID,
|
|
||||||
const char *Name, unsigned NameLen,
|
|
||||||
IdentifierTable &Table) {
|
|
||||||
Table.get(Name, Name+NameLen).setObjCKeywordID(ObjCID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AddKeywords - Add all keywords to the symbol table.
|
|
||||||
///
|
|
||||||
void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
|
|
||||||
enum {
|
|
||||||
C90Shift = 0,
|
|
||||||
EXTC90 = 1 << C90Shift,
|
|
||||||
NOTC90 = 2 << C90Shift,
|
|
||||||
C99Shift = 2,
|
|
||||||
EXTC99 = 1 << C99Shift,
|
|
||||||
NOTC99 = 2 << C99Shift,
|
|
||||||
CPPShift = 4,
|
|
||||||
EXTCPP = 1 << CPPShift,
|
|
||||||
NOTCPP = 2 << CPPShift,
|
|
||||||
CPP0xShift = 6,
|
|
||||||
EXTCPP0x = 1 << CPP0xShift,
|
|
||||||
NOTCPP0x = 2 << CPP0xShift,
|
|
||||||
Mask = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add keywords and tokens for the current language.
|
|
||||||
#define KEYWORD(NAME, FLAGS) \
|
|
||||||
AddKeyword(#NAME, strlen(#NAME), tok::kw_ ## NAME, \
|
|
||||||
((FLAGS) >> C90Shift) & Mask, \
|
|
||||||
((FLAGS) >> C99Shift) & Mask, \
|
|
||||||
((FLAGS) >> CPPShift) & Mask, \
|
|
||||||
((FLAGS) >> CPP0xShift) & Mask, LangOpts, *this);
|
|
||||||
#define ALIAS(NAME, TOK) \
|
|
||||||
AddAlias(NAME, strlen(NAME), #TOK, strlen(#TOK), LangOpts, *this);
|
|
||||||
#define PPKEYWORD(NAME) \
|
|
||||||
AddPPKeyword(tok::pp_##NAME, #NAME, strlen(#NAME), *this);
|
|
||||||
#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \
|
|
||||||
if (LangOpts.CXXOperatorNames) \
|
|
||||||
AddCXXOperatorKeyword(#NAME, strlen(#NAME), tok::ALIAS, *this);
|
|
||||||
#define OBJC1_AT_KEYWORD(NAME) \
|
|
||||||
if (LangOpts.ObjC1) \
|
|
||||||
AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this);
|
|
||||||
#define OBJC2_AT_KEYWORD(NAME) \
|
|
||||||
if (LangOpts.ObjC2) \
|
|
||||||
AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this);
|
|
||||||
#include "clang/Basic/TokenKinds.def"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Stats Implementation
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// PrintStats - Print statistics about how well the identifier table is doing
|
|
||||||
/// at hashing identifiers.
|
|
||||||
void IdentifierTable::PrintStats() const {
|
|
||||||
unsigned NumBuckets = HashTable.getNumBuckets();
|
|
||||||
unsigned NumIdentifiers = HashTable.getNumItems();
|
|
||||||
unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers;
|
|
||||||
unsigned AverageIdentifierSize = 0;
|
|
||||||
unsigned MaxIdentifierLength = 0;
|
|
||||||
|
|
||||||
// TODO: Figure out maximum times an identifier had to probe for -stats.
|
|
||||||
for (llvm::StringMap<IdentifierInfo, llvm::BumpPtrAllocator>::const_iterator
|
|
||||||
I = HashTable.begin(), E = HashTable.end(); I != E; ++I) {
|
|
||||||
unsigned IdLen = I->getKeyLength();
|
|
||||||
AverageIdentifierSize += IdLen;
|
|
||||||
if (MaxIdentifierLength < IdLen)
|
|
||||||
MaxIdentifierLength = IdLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "\n*** Identifier Table Stats:\n");
|
|
||||||
fprintf(stderr, "# Identifiers: %d\n", NumIdentifiers);
|
|
||||||
fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets);
|
|
||||||
fprintf(stderr, "Hash density (#identifiers per bucket): %f\n",
|
|
||||||
NumIdentifiers/(double)NumBuckets);
|
|
||||||
fprintf(stderr, "Ave identifier length: %f\n",
|
|
||||||
(AverageIdentifierSize/(double)NumIdentifiers));
|
|
||||||
fprintf(stderr, "Max identifier length: %d\n", MaxIdentifierLength);
|
|
||||||
|
|
||||||
// Compute statistics about the memory allocated for identifiers.
|
|
||||||
HashTable.getAllocator().PrintStats();
|
|
||||||
}
|
|
||||||
1551
clang/Lex/Lexer.cpp
1551
clang/Lex/Lexer.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,661 +0,0 @@
|
|||||||
//===--- LiteralSupport.cpp - Code to parse and process literals ----------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Steve Naroff and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file implements the NumericLiteralParser, CharLiteralParser, and
|
|
||||||
// StringLiteralParser interfaces.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Lex/LiteralSupport.h"
|
|
||||||
#include "clang/Lex/Preprocessor.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
#include "clang/Basic/TargetInfo.h"
|
|
||||||
#include "llvm/ADT/APInt.h"
|
|
||||||
#include "llvm/ADT/StringExtras.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
/// HexDigitValue - Return the value of the specified hex digit, or -1 if it's
|
|
||||||
/// not valid.
|
|
||||||
static int HexDigitValue(char C) {
|
|
||||||
if (C >= '0' && C <= '9') return C-'0';
|
|
||||||
if (C >= 'a' && C <= 'f') return C-'a'+10;
|
|
||||||
if (C >= 'A' && C <= 'F') return C-'A'+10;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ProcessCharEscape - Parse a standard C escape sequence, which can occur in
|
|
||||||
/// either a character or a string literal.
|
|
||||||
static unsigned ProcessCharEscape(const char *&ThisTokBuf,
|
|
||||||
const char *ThisTokEnd, bool &HadError,
|
|
||||||
SourceLocation Loc, bool IsWide,
|
|
||||||
Preprocessor &PP) {
|
|
||||||
// Skip the '\' char.
|
|
||||||
++ThisTokBuf;
|
|
||||||
|
|
||||||
// We know that this character can't be off the end of the buffer, because
|
|
||||||
// that would have been \", which would not have been the end of string.
|
|
||||||
unsigned ResultChar = *ThisTokBuf++;
|
|
||||||
switch (ResultChar) {
|
|
||||||
// These map to themselves.
|
|
||||||
case '\\': case '\'': case '"': case '?': break;
|
|
||||||
|
|
||||||
// These have fixed mappings.
|
|
||||||
case 'a':
|
|
||||||
// TODO: K&R: the meaning of '\\a' is different in traditional C
|
|
||||||
ResultChar = 7;
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
ResultChar = 8;
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
PP.Diag(Loc, diag::ext_nonstandard_escape, "e");
|
|
||||||
ResultChar = 27;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
ResultChar = 12;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
ResultChar = 10;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
ResultChar = 13;
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
ResultChar = 9;
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
ResultChar = 11;
|
|
||||||
break;
|
|
||||||
|
|
||||||
//case 'u': case 'U': // FIXME: UCNs.
|
|
||||||
case 'x': { // Hex escape.
|
|
||||||
ResultChar = 0;
|
|
||||||
if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
|
|
||||||
PP.Diag(Loc, diag::err_hex_escape_no_digits);
|
|
||||||
HadError = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hex escapes are a maximal series of hex digits.
|
|
||||||
bool Overflow = false;
|
|
||||||
for (; ThisTokBuf != ThisTokEnd; ++ThisTokBuf) {
|
|
||||||
int CharVal = HexDigitValue(ThisTokBuf[0]);
|
|
||||||
if (CharVal == -1) break;
|
|
||||||
Overflow |= (ResultChar & 0xF0000000) ? true : false; // About to shift out a digit?
|
|
||||||
ResultChar <<= 4;
|
|
||||||
ResultChar |= CharVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if any bits will be truncated when evaluated as a character.
|
|
||||||
unsigned CharWidth = IsWide ? PP.getTargetInfo().getWCharWidth(Loc)
|
|
||||||
: PP.getTargetInfo().getCharWidth(Loc);
|
|
||||||
if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
|
|
||||||
Overflow = true;
|
|
||||||
ResultChar &= ~0U >> (32-CharWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for overflow.
|
|
||||||
if (Overflow) // Too many digits to fit in
|
|
||||||
PP.Diag(Loc, diag::warn_hex_escape_too_large);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case '0': case '1': case '2': case '3':
|
|
||||||
case '4': case '5': case '6': case '7': {
|
|
||||||
// Octal escapes.
|
|
||||||
--ThisTokBuf;
|
|
||||||
ResultChar = 0;
|
|
||||||
|
|
||||||
// Octal escapes are a series of octal digits with maximum length 3.
|
|
||||||
// "\0123" is a two digit sequence equal to "\012" "3".
|
|
||||||
unsigned NumDigits = 0;
|
|
||||||
do {
|
|
||||||
ResultChar <<= 3;
|
|
||||||
ResultChar |= *ThisTokBuf++ - '0';
|
|
||||||
++NumDigits;
|
|
||||||
} while (ThisTokBuf != ThisTokEnd && NumDigits < 3 &&
|
|
||||||
ThisTokBuf[0] >= '0' && ThisTokBuf[0] <= '7');
|
|
||||||
|
|
||||||
// Check for overflow. Reject '\777', but not L'\777'.
|
|
||||||
unsigned CharWidth = IsWide ? PP.getTargetInfo().getWCharWidth(Loc)
|
|
||||||
: PP.getTargetInfo().getCharWidth(Loc);
|
|
||||||
if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
|
|
||||||
PP.Diag(Loc, diag::warn_octal_escape_too_large);
|
|
||||||
ResultChar &= ~0U >> (32-CharWidth);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, these are not valid escapes.
|
|
||||||
case '(': case '{': case '[': case '%':
|
|
||||||
// GCC accepts these as extensions. We warn about them as such though.
|
|
||||||
if (!PP.getLangOptions().NoExtensions) {
|
|
||||||
PP.Diag(Loc, diag::ext_nonstandard_escape,
|
|
||||||
std::string()+(char)ResultChar);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// FALL THROUGH.
|
|
||||||
default:
|
|
||||||
if (isgraph(ThisTokBuf[0])) {
|
|
||||||
PP.Diag(Loc, diag::ext_unknown_escape, std::string()+(char)ResultChar);
|
|
||||||
} else {
|
|
||||||
PP.Diag(Loc, diag::ext_unknown_escape, "x"+llvm::utohexstr(ResultChar));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultChar;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// integer-constant: [C99 6.4.4.1]
|
|
||||||
/// decimal-constant integer-suffix
|
|
||||||
/// octal-constant integer-suffix
|
|
||||||
/// hexadecimal-constant integer-suffix
|
|
||||||
/// decimal-constant:
|
|
||||||
/// nonzero-digit
|
|
||||||
/// decimal-constant digit
|
|
||||||
/// octal-constant:
|
|
||||||
/// 0
|
|
||||||
/// octal-constant octal-digit
|
|
||||||
/// hexadecimal-constant:
|
|
||||||
/// hexadecimal-prefix hexadecimal-digit
|
|
||||||
/// hexadecimal-constant hexadecimal-digit
|
|
||||||
/// hexadecimal-prefix: one of
|
|
||||||
/// 0x 0X
|
|
||||||
/// integer-suffix:
|
|
||||||
/// unsigned-suffix [long-suffix]
|
|
||||||
/// unsigned-suffix [long-long-suffix]
|
|
||||||
/// long-suffix [unsigned-suffix]
|
|
||||||
/// long-long-suffix [unsigned-sufix]
|
|
||||||
/// nonzero-digit:
|
|
||||||
/// 1 2 3 4 5 6 7 8 9
|
|
||||||
/// octal-digit:
|
|
||||||
/// 0 1 2 3 4 5 6 7
|
|
||||||
/// hexadecimal-digit:
|
|
||||||
/// 0 1 2 3 4 5 6 7 8 9
|
|
||||||
/// a b c d e f
|
|
||||||
/// A B C D E F
|
|
||||||
/// unsigned-suffix: one of
|
|
||||||
/// u U
|
|
||||||
/// long-suffix: one of
|
|
||||||
/// l L
|
|
||||||
/// long-long-suffix: one of
|
|
||||||
/// ll LL
|
|
||||||
///
|
|
||||||
/// floating-constant: [C99 6.4.4.2]
|
|
||||||
/// TODO: add rules...
|
|
||||||
///
|
|
||||||
|
|
||||||
NumericLiteralParser::
|
|
||||||
NumericLiteralParser(const char *begin, const char *end,
|
|
||||||
SourceLocation TokLoc, Preprocessor &pp)
|
|
||||||
: PP(pp), ThisTokBegin(begin), ThisTokEnd(end) {
|
|
||||||
s = DigitsBegin = begin;
|
|
||||||
saw_exponent = false;
|
|
||||||
saw_period = false;
|
|
||||||
isLong = false;
|
|
||||||
isUnsigned = false;
|
|
||||||
isLongLong = false;
|
|
||||||
isFloat = false;
|
|
||||||
isImaginary = false;
|
|
||||||
hadError = false;
|
|
||||||
|
|
||||||
if (*s == '0') { // parse radix
|
|
||||||
s++;
|
|
||||||
if ((*s == 'x' || *s == 'X') && (isxdigit(s[1]) || s[1] == '.')) {
|
|
||||||
s++;
|
|
||||||
radix = 16;
|
|
||||||
DigitsBegin = s;
|
|
||||||
s = SkipHexDigits(s);
|
|
||||||
if (s == ThisTokEnd) {
|
|
||||||
// Done.
|
|
||||||
} else if (*s == '.') {
|
|
||||||
s++;
|
|
||||||
saw_period = true;
|
|
||||||
s = SkipHexDigits(s);
|
|
||||||
}
|
|
||||||
// A binary exponent can appear with or with a '.'. If dotted, the
|
|
||||||
// binary exponent is required.
|
|
||||||
if (*s == 'p' || *s == 'P') {
|
|
||||||
s++;
|
|
||||||
saw_exponent = true;
|
|
||||||
if (*s == '+' || *s == '-') s++; // sign
|
|
||||||
const char *first_non_digit = SkipDigits(s);
|
|
||||||
if (first_non_digit == s) {
|
|
||||||
Diag(TokLoc, diag::err_exponent_has_no_digits);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
s = first_non_digit;
|
|
||||||
}
|
|
||||||
} else if (saw_period) {
|
|
||||||
Diag(TokLoc, diag::err_hexconstant_requires_exponent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (*s == 'b' || *s == 'B') {
|
|
||||||
// 0b101010 is a GCC extension.
|
|
||||||
++s;
|
|
||||||
radix = 2;
|
|
||||||
DigitsBegin = s;
|
|
||||||
s = SkipBinaryDigits(s);
|
|
||||||
if (s == ThisTokEnd) {
|
|
||||||
// Done.
|
|
||||||
} else if (isxdigit(*s)) {
|
|
||||||
Diag(TokLoc, diag::err_invalid_binary_digit, std::string(s, s+1));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PP.Diag(TokLoc, diag::ext_binary_literal);
|
|
||||||
} else {
|
|
||||||
// For now, the radix is set to 8. If we discover that we have a
|
|
||||||
// floating point constant, the radix will change to 10. Octal floating
|
|
||||||
// point constants are not permitted (only decimal and hexadecimal).
|
|
||||||
radix = 8;
|
|
||||||
DigitsBegin = s;
|
|
||||||
s = SkipOctalDigits(s);
|
|
||||||
if (s == ThisTokEnd) {
|
|
||||||
// Done.
|
|
||||||
} else if (isxdigit(*s)) {
|
|
||||||
TokLoc = PP.AdvanceToTokenCharacter(TokLoc, s-begin);
|
|
||||||
Diag(TokLoc, diag::err_invalid_octal_digit, std::string(s, s+1));
|
|
||||||
return;
|
|
||||||
} else if (*s == '.') {
|
|
||||||
s++;
|
|
||||||
radix = 10;
|
|
||||||
saw_period = true;
|
|
||||||
s = SkipDigits(s);
|
|
||||||
}
|
|
||||||
if (*s == 'e' || *s == 'E') { // exponent
|
|
||||||
s++;
|
|
||||||
radix = 10;
|
|
||||||
saw_exponent = true;
|
|
||||||
if (*s == '+' || *s == '-') s++; // sign
|
|
||||||
const char *first_non_digit = SkipDigits(s);
|
|
||||||
if (first_non_digit == s) {
|
|
||||||
Diag(TokLoc, diag::err_exponent_has_no_digits);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
s = first_non_digit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // the first digit is non-zero
|
|
||||||
radix = 10;
|
|
||||||
s = SkipDigits(s);
|
|
||||||
if (s == ThisTokEnd) {
|
|
||||||
// Done.
|
|
||||||
} else if (isxdigit(*s)) {
|
|
||||||
Diag(TokLoc, diag::err_invalid_decimal_digit, std::string(s, s+1));
|
|
||||||
return;
|
|
||||||
} else if (*s == '.') {
|
|
||||||
s++;
|
|
||||||
saw_period = true;
|
|
||||||
s = SkipDigits(s);
|
|
||||||
}
|
|
||||||
if (*s == 'e' || *s == 'E') { // exponent
|
|
||||||
s++;
|
|
||||||
saw_exponent = true;
|
|
||||||
if (*s == '+' || *s == '-') s++; // sign
|
|
||||||
const char *first_non_digit = SkipDigits(s);
|
|
||||||
if (first_non_digit == s) {
|
|
||||||
Diag(TokLoc, diag::err_exponent_has_no_digits);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
s = first_non_digit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SuffixBegin = s;
|
|
||||||
|
|
||||||
// Parse the suffix. At this point we can classify whether we have an FP or
|
|
||||||
// integer constant.
|
|
||||||
bool isFPConstant = isFloatingLiteral();
|
|
||||||
|
|
||||||
// Loop over all of the characters of the suffix. If we see something bad,
|
|
||||||
// we break out of the loop.
|
|
||||||
for (; s != ThisTokEnd; ++s) {
|
|
||||||
switch (*s) {
|
|
||||||
case 'f': // FP Suffix for "float"
|
|
||||||
case 'F':
|
|
||||||
if (!isFPConstant) break; // Error for integer constant.
|
|
||||||
if (isFloat || isLong) break; // FF, LF invalid.
|
|
||||||
isFloat = true;
|
|
||||||
continue; // Success.
|
|
||||||
case 'u':
|
|
||||||
case 'U':
|
|
||||||
if (isFPConstant) break; // Error for floating constant.
|
|
||||||
if (isUnsigned) break; // Cannot be repeated.
|
|
||||||
isUnsigned = true;
|
|
||||||
continue; // Success.
|
|
||||||
case 'l':
|
|
||||||
case 'L':
|
|
||||||
if (isLong || isLongLong) break; // Cannot be repeated.
|
|
||||||
if (isFloat) break; // LF invalid.
|
|
||||||
|
|
||||||
// Check for long long. The L's need to be adjacent and the same case.
|
|
||||||
if (s+1 != ThisTokEnd && s[1] == s[0]) {
|
|
||||||
if (isFPConstant) break; // long long invalid for floats.
|
|
||||||
isLongLong = true;
|
|
||||||
++s; // Eat both of them.
|
|
||||||
} else {
|
|
||||||
isLong = true;
|
|
||||||
}
|
|
||||||
continue; // Success.
|
|
||||||
case 'i':
|
|
||||||
case 'I':
|
|
||||||
case 'j':
|
|
||||||
case 'J':
|
|
||||||
if (isImaginary) break; // Cannot be repeated.
|
|
||||||
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
|
|
||||||
diag::ext_imaginary_constant);
|
|
||||||
isImaginary = true;
|
|
||||||
continue; // Success.
|
|
||||||
}
|
|
||||||
// If we reached here, there was an error.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Report an error if there are any.
|
|
||||||
if (s != ThisTokEnd) {
|
|
||||||
TokLoc = PP.AdvanceToTokenCharacter(TokLoc, s-begin);
|
|
||||||
Diag(TokLoc, isFPConstant ? diag::err_invalid_suffix_float_constant :
|
|
||||||
diag::err_invalid_suffix_integer_constant,
|
|
||||||
std::string(SuffixBegin, ThisTokEnd));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// GetIntegerValue - Convert this numeric literal value to an APInt that
|
|
||||||
/// matches Val's input width. If there is an overflow, set Val to the low bits
|
|
||||||
/// of the result and return true. Otherwise, return false.
|
|
||||||
bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
|
|
||||||
Val = 0;
|
|
||||||
s = DigitsBegin;
|
|
||||||
|
|
||||||
llvm::APInt RadixVal(Val.getBitWidth(), radix);
|
|
||||||
llvm::APInt CharVal(Val.getBitWidth(), 0);
|
|
||||||
llvm::APInt OldVal = Val;
|
|
||||||
|
|
||||||
bool OverflowOccurred = false;
|
|
||||||
while (s < SuffixBegin) {
|
|
||||||
unsigned C = HexDigitValue(*s++);
|
|
||||||
|
|
||||||
// If this letter is out of bound for this radix, reject it.
|
|
||||||
assert(C < radix && "NumericLiteralParser ctor should have rejected this");
|
|
||||||
|
|
||||||
CharVal = C;
|
|
||||||
|
|
||||||
// Add the digit to the value in the appropriate radix. If adding in digits
|
|
||||||
// made the value smaller, then this overflowed.
|
|
||||||
OldVal = Val;
|
|
||||||
|
|
||||||
// Multiply by radix, did overflow occur on the multiply?
|
|
||||||
Val *= RadixVal;
|
|
||||||
OverflowOccurred |= Val.udiv(RadixVal) != OldVal;
|
|
||||||
|
|
||||||
OldVal = Val;
|
|
||||||
// Add value, did overflow occur on the value?
|
|
||||||
Val += CharVal;
|
|
||||||
OverflowOccurred |= Val.ult(OldVal);
|
|
||||||
OverflowOccurred |= Val.ult(CharVal);
|
|
||||||
}
|
|
||||||
return OverflowOccurred;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFloatValue - Poor man's floatvalue (FIXME).
|
|
||||||
float NumericLiteralParser::GetFloatValue() {
|
|
||||||
char floatChars[256];
|
|
||||||
strncpy(floatChars, ThisTokBegin, ThisTokEnd-ThisTokBegin);
|
|
||||||
floatChars[ThisTokEnd-ThisTokBegin] = '\0';
|
|
||||||
return (float)strtod(floatChars, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NumericLiteralParser::Diag(SourceLocation Loc, unsigned DiagID,
|
|
||||||
const std::string &M) {
|
|
||||||
PP.Diag(Loc, DiagID, M);
|
|
||||||
hadError = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
|
|
||||||
SourceLocation Loc, Preprocessor &PP) {
|
|
||||||
// At this point we know that the character matches the regex "L?'.*'".
|
|
||||||
HadError = false;
|
|
||||||
Value = 0;
|
|
||||||
|
|
||||||
// Determine if this is a wide character.
|
|
||||||
IsWide = begin[0] == 'L';
|
|
||||||
if (IsWide) ++begin;
|
|
||||||
|
|
||||||
// Skip over the entry quote.
|
|
||||||
assert(begin[0] == '\'' && "Invalid token lexed");
|
|
||||||
++begin;
|
|
||||||
|
|
||||||
// FIXME: This assumes that 'int' is 32-bits in overflow calculation, and the
|
|
||||||
// size of "value".
|
|
||||||
assert(PP.getTargetInfo().getIntWidth(Loc) == 32 &&
|
|
||||||
"Assumes sizeof(int) == 4 for now");
|
|
||||||
// FIXME: This assumes that wchar_t is 32-bits for now.
|
|
||||||
assert(PP.getTargetInfo().getWCharWidth(Loc) == 32 &&
|
|
||||||
"Assumes sizeof(wchar_t) == 4 for now");
|
|
||||||
// FIXME: This extensively assumes that 'char' is 8-bits.
|
|
||||||
assert(PP.getTargetInfo().getCharWidth(Loc) == 8 &&
|
|
||||||
"Assumes char is 8 bits");
|
|
||||||
|
|
||||||
bool isFirstChar = true;
|
|
||||||
bool isMultiChar = false;
|
|
||||||
while (begin[0] != '\'') {
|
|
||||||
unsigned ResultChar;
|
|
||||||
if (begin[0] != '\\') // If this is a normal character, consume it.
|
|
||||||
ResultChar = *begin++;
|
|
||||||
else // Otherwise, this is an escape character.
|
|
||||||
ResultChar = ProcessCharEscape(begin, end, HadError, Loc, IsWide, PP);
|
|
||||||
|
|
||||||
// If this is a multi-character constant (e.g. 'abc'), handle it. These are
|
|
||||||
// implementation defined (C99 6.4.4.4p10).
|
|
||||||
if (!isFirstChar) {
|
|
||||||
// If this is the second character being processed, do special handling.
|
|
||||||
if (!isMultiChar) {
|
|
||||||
isMultiChar = true;
|
|
||||||
|
|
||||||
// Warn about discarding the top bits for multi-char wide-character
|
|
||||||
// constants (L'abcd').
|
|
||||||
if (IsWide)
|
|
||||||
PP.Diag(Loc, diag::warn_extraneous_wide_char_constant);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsWide) {
|
|
||||||
// Emulate GCC's (unintentional?) behavior: L'ab' -> L'b'.
|
|
||||||
Value = 0;
|
|
||||||
} else {
|
|
||||||
// Narrow character literals act as though their value is concatenated
|
|
||||||
// in this implementation.
|
|
||||||
if (((Value << 8) >> 8) != Value)
|
|
||||||
PP.Diag(Loc, diag::warn_char_constant_too_large);
|
|
||||||
Value <<= 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Value += ResultChar;
|
|
||||||
isFirstChar = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is a single narrow character, sign extend it (e.g. '\xFF' is "-1")
|
|
||||||
// if 'char' is signed for this target (C99 6.4.4.4p10). Note that multiple
|
|
||||||
// character constants are not sign extended in the this implementation:
|
|
||||||
// '\xFF\xFF' = 65536 and '\x0\xFF' = 255, which matches GCC.
|
|
||||||
if (!IsWide && !isMultiChar && (Value & 128) &&
|
|
||||||
PP.getTargetInfo().isCharSigned(Loc))
|
|
||||||
Value = (signed char)Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// string-literal: [C99 6.4.5]
|
|
||||||
/// " [s-char-sequence] "
|
|
||||||
/// L" [s-char-sequence] "
|
|
||||||
/// s-char-sequence:
|
|
||||||
/// s-char
|
|
||||||
/// s-char-sequence s-char
|
|
||||||
/// s-char:
|
|
||||||
/// any source character except the double quote ",
|
|
||||||
/// backslash \, or newline character
|
|
||||||
/// escape-character
|
|
||||||
/// universal-character-name
|
|
||||||
/// escape-character: [C99 6.4.4.4]
|
|
||||||
/// \ escape-code
|
|
||||||
/// universal-character-name
|
|
||||||
/// escape-code:
|
|
||||||
/// character-escape-code
|
|
||||||
/// octal-escape-code
|
|
||||||
/// hex-escape-code
|
|
||||||
/// character-escape-code: one of
|
|
||||||
/// n t b r f v a
|
|
||||||
/// \ ' " ?
|
|
||||||
/// octal-escape-code:
|
|
||||||
/// octal-digit
|
|
||||||
/// octal-digit octal-digit
|
|
||||||
/// octal-digit octal-digit octal-digit
|
|
||||||
/// hex-escape-code:
|
|
||||||
/// x hex-digit
|
|
||||||
/// hex-escape-code hex-digit
|
|
||||||
/// universal-character-name:
|
|
||||||
/// \u hex-quad
|
|
||||||
/// \U hex-quad hex-quad
|
|
||||||
/// hex-quad:
|
|
||||||
/// hex-digit hex-digit hex-digit hex-digit
|
|
||||||
///
|
|
||||||
StringLiteralParser::
|
|
||||||
StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
|
|
||||||
Preprocessor &pp, TargetInfo &t)
|
|
||||||
: PP(pp), Target(t) {
|
|
||||||
// Scan all of the string portions, remember the max individual token length,
|
|
||||||
// computing a bound on the concatenated string length, and see whether any
|
|
||||||
// piece is a wide-string. If any of the string portions is a wide-string
|
|
||||||
// literal, the result is a wide-string literal [C99 6.4.5p4].
|
|
||||||
MaxTokenLength = StringToks[0].getLength();
|
|
||||||
SizeBound = StringToks[0].getLength()-2; // -2 for "".
|
|
||||||
AnyWide = StringToks[0].getKind() == tok::wide_string_literal;
|
|
||||||
|
|
||||||
hadError = false;
|
|
||||||
|
|
||||||
// Implement Translation Phase #6: concatenation of string literals
|
|
||||||
/// (C99 5.1.1.2p1). The common case is only one string fragment.
|
|
||||||
for (unsigned i = 1; i != NumStringToks; ++i) {
|
|
||||||
// The string could be shorter than this if it needs cleaning, but this is a
|
|
||||||
// reasonable bound, which is all we need.
|
|
||||||
SizeBound += StringToks[i].getLength()-2; // -2 for "".
|
|
||||||
|
|
||||||
// Remember maximum string piece length.
|
|
||||||
if (StringToks[i].getLength() > MaxTokenLength)
|
|
||||||
MaxTokenLength = StringToks[i].getLength();
|
|
||||||
|
|
||||||
// Remember if we see any wide strings.
|
|
||||||
AnyWide |= StringToks[i].getKind() == tok::wide_string_literal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Include space for the null terminator.
|
|
||||||
++SizeBound;
|
|
||||||
|
|
||||||
// TODO: K&R warning: "traditional C rejects string constant concatenation"
|
|
||||||
|
|
||||||
// Get the width in bytes of wchar_t. If no wchar_t strings are used, do not
|
|
||||||
// query the target. As such, wchar_tByteWidth is only valid if AnyWide=true.
|
|
||||||
wchar_tByteWidth = ~0U;
|
|
||||||
if (AnyWide) {
|
|
||||||
wchar_tByteWidth = Target.getWCharWidth(StringToks[0].getLocation());
|
|
||||||
assert((wchar_tByteWidth & 7) == 0 && "Assumes wchar_t is byte multiple!");
|
|
||||||
wchar_tByteWidth /= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The output buffer size needs to be large enough to hold wide characters.
|
|
||||||
// This is a worst-case assumption which basically corresponds to L"" "long".
|
|
||||||
if (AnyWide)
|
|
||||||
SizeBound *= wchar_tByteWidth;
|
|
||||||
|
|
||||||
// Size the temporary buffer to hold the result string data.
|
|
||||||
ResultBuf.resize(SizeBound);
|
|
||||||
|
|
||||||
// Likewise, but for each string piece.
|
|
||||||
llvm::SmallString<512> TokenBuf;
|
|
||||||
TokenBuf.resize(MaxTokenLength);
|
|
||||||
|
|
||||||
// Loop over all the strings, getting their spelling, and expanding them to
|
|
||||||
// wide strings as appropriate.
|
|
||||||
ResultPtr = &ResultBuf[0]; // Next byte to fill in.
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = NumStringToks; i != e; ++i) {
|
|
||||||
const char *ThisTokBuf = &TokenBuf[0];
|
|
||||||
// Get the spelling of the token, which eliminates trigraphs, etc. We know
|
|
||||||
// that ThisTokBuf points to a buffer that is big enough for the whole token
|
|
||||||
// and 'spelled' tokens can only shrink.
|
|
||||||
unsigned ThisTokLen = PP.getSpelling(StringToks[i], ThisTokBuf);
|
|
||||||
const char *ThisTokEnd = ThisTokBuf+ThisTokLen-1; // Skip end quote.
|
|
||||||
|
|
||||||
// TODO: Input character set mapping support.
|
|
||||||
|
|
||||||
// Skip L marker for wide strings.
|
|
||||||
bool ThisIsWide = false;
|
|
||||||
if (ThisTokBuf[0] == 'L') {
|
|
||||||
++ThisTokBuf;
|
|
||||||
ThisIsWide = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(ThisTokBuf[0] == '"' && "Expected quote, lexer broken?");
|
|
||||||
++ThisTokBuf;
|
|
||||||
|
|
||||||
while (ThisTokBuf != ThisTokEnd) {
|
|
||||||
// Is this a span of non-escape characters?
|
|
||||||
if (ThisTokBuf[0] != '\\') {
|
|
||||||
const char *InStart = ThisTokBuf;
|
|
||||||
do {
|
|
||||||
++ThisTokBuf;
|
|
||||||
} while (ThisTokBuf != ThisTokEnd && ThisTokBuf[0] != '\\');
|
|
||||||
|
|
||||||
// Copy the character span over.
|
|
||||||
unsigned Len = ThisTokBuf-InStart;
|
|
||||||
if (!AnyWide) {
|
|
||||||
memcpy(ResultPtr, InStart, Len);
|
|
||||||
ResultPtr += Len;
|
|
||||||
} else {
|
|
||||||
// Note: our internal rep of wide char tokens is always little-endian.
|
|
||||||
for (; Len; --Len, ++InStart) {
|
|
||||||
*ResultPtr++ = InStart[0];
|
|
||||||
// Add zeros at the end.
|
|
||||||
for (unsigned i = 1, e = wchar_tByteWidth; i != e; ++i)
|
|
||||||
*ResultPtr++ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, this is an escape character. Process it.
|
|
||||||
unsigned ResultChar = ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError,
|
|
||||||
StringToks[i].getLocation(),
|
|
||||||
ThisIsWide, PP);
|
|
||||||
|
|
||||||
// Note: our internal rep of wide char tokens is always little-endian.
|
|
||||||
*ResultPtr++ = ResultChar & 0xFF;
|
|
||||||
|
|
||||||
if (AnyWide) {
|
|
||||||
for (unsigned i = 1, e = wchar_tByteWidth; i != e; ++i)
|
|
||||||
*ResultPtr++ = ResultChar >> i*8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add zero terminator.
|
|
||||||
*ResultPtr = 0;
|
|
||||||
if (AnyWide) {
|
|
||||||
for (unsigned i = 1, e = wchar_tByteWidth; i != e; ++i)
|
|
||||||
*ResultPtr++ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,647 +0,0 @@
|
|||||||
//===--- MacroExpander.cpp - Lex from a macro expansion -------------------===//
|
|
||||||
//
|
|
||||||
// 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 MacroExpander interface.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Lex/MacroExpander.h"
|
|
||||||
#include "clang/Lex/MacroInfo.h"
|
|
||||||
#include "clang/Lex/Preprocessor.h"
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "llvm/ADT/SmallVector.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// MacroArgs Implementation
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// MacroArgs ctor function - This destroys the vector passed in.
|
|
||||||
MacroArgs *MacroArgs::create(const MacroInfo *MI,
|
|
||||||
const Token *UnexpArgTokens,
|
|
||||||
unsigned NumToks, bool VarargsElided) {
|
|
||||||
assert(MI->isFunctionLike() &&
|
|
||||||
"Can't have args for an object-like macro!");
|
|
||||||
|
|
||||||
// Allocate memory for the MacroArgs object with the lexer tokens at the end.
|
|
||||||
MacroArgs *Result = (MacroArgs*)malloc(sizeof(MacroArgs) +
|
|
||||||
NumToks*sizeof(Token));
|
|
||||||
// Construct the macroargs object.
|
|
||||||
new (Result) MacroArgs(NumToks, VarargsElided);
|
|
||||||
|
|
||||||
// Copy the actual unexpanded tokens to immediately after the result ptr.
|
|
||||||
if (NumToks)
|
|
||||||
memcpy(const_cast<Token*>(Result->getUnexpArgument(0)),
|
|
||||||
UnexpArgTokens, NumToks*sizeof(Token));
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// destroy - Destroy and deallocate the memory for this object.
|
|
||||||
///
|
|
||||||
void MacroArgs::destroy() {
|
|
||||||
// Run the dtor to deallocate the vectors.
|
|
||||||
this->~MacroArgs();
|
|
||||||
// Release the memory for the object.
|
|
||||||
free(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// getArgLength - Given a pointer to an expanded or unexpanded argument,
|
|
||||||
/// return the number of tokens, not counting the EOF, that make up the
|
|
||||||
/// argument.
|
|
||||||
unsigned MacroArgs::getArgLength(const Token *ArgPtr) {
|
|
||||||
unsigned NumArgTokens = 0;
|
|
||||||
for (; ArgPtr->getKind() != tok::eof; ++ArgPtr)
|
|
||||||
++NumArgTokens;
|
|
||||||
return NumArgTokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// getUnexpArgument - Return the unexpanded tokens for the specified formal.
|
|
||||||
///
|
|
||||||
const Token *MacroArgs::getUnexpArgument(unsigned Arg) const {
|
|
||||||
// The unexpanded argument tokens start immediately after the MacroArgs object
|
|
||||||
// in memory.
|
|
||||||
const Token *Start = (const Token *)(this+1);
|
|
||||||
const Token *Result = Start;
|
|
||||||
// Scan to find Arg.
|
|
||||||
for (; Arg; ++Result) {
|
|
||||||
assert(Result < Start+NumUnexpArgTokens && "Invalid arg #");
|
|
||||||
if (Result->getKind() == tok::eof)
|
|
||||||
--Arg;
|
|
||||||
}
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// ArgNeedsPreexpansion - If we can prove that the argument won't be affected
|
|
||||||
/// by pre-expansion, return false. Otherwise, conservatively return true.
|
|
||||||
bool MacroArgs::ArgNeedsPreexpansion(const Token *ArgTok) const {
|
|
||||||
// If there are no identifiers in the argument list, or if the identifiers are
|
|
||||||
// known to not be macros, pre-expansion won't modify it.
|
|
||||||
for (; ArgTok->getKind() != tok::eof; ++ArgTok)
|
|
||||||
if (IdentifierInfo *II = ArgTok->getIdentifierInfo()) {
|
|
||||||
if (II->getMacroInfo() && II->getMacroInfo()->isEnabled())
|
|
||||||
// Return true even though the macro could be a function-like macro
|
|
||||||
// without a following '(' token.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getPreExpArgument - Return the pre-expanded form of the specified
|
|
||||||
/// argument.
|
|
||||||
const std::vector<Token> &
|
|
||||||
MacroArgs::getPreExpArgument(unsigned Arg, Preprocessor &PP) {
|
|
||||||
assert(Arg < NumUnexpArgTokens && "Invalid argument number!");
|
|
||||||
|
|
||||||
// If we have already computed this, return it.
|
|
||||||
if (PreExpArgTokens.empty())
|
|
||||||
PreExpArgTokens.resize(NumUnexpArgTokens);
|
|
||||||
|
|
||||||
std::vector<Token> &Result = PreExpArgTokens[Arg];
|
|
||||||
if (!Result.empty()) return Result;
|
|
||||||
|
|
||||||
const Token *AT = getUnexpArgument(Arg);
|
|
||||||
unsigned NumToks = getArgLength(AT)+1; // Include the EOF.
|
|
||||||
|
|
||||||
// Otherwise, we have to pre-expand this argument, populating Result. To do
|
|
||||||
// this, we set up a fake MacroExpander to lex from the unexpanded argument
|
|
||||||
// list. With this installed, we lex expanded tokens until we hit the EOF
|
|
||||||
// token at the end of the unexp list.
|
|
||||||
PP.EnterTokenStream(AT, NumToks);
|
|
||||||
|
|
||||||
// Lex all of the macro-expanded tokens into Result.
|
|
||||||
do {
|
|
||||||
Result.push_back(Token());
|
|
||||||
PP.Lex(Result.back());
|
|
||||||
} while (Result.back().getKind() != tok::eof);
|
|
||||||
|
|
||||||
// Pop the token stream off the top of the stack. We know that the internal
|
|
||||||
// pointer inside of it is to the "end" of the token stream, but the stack
|
|
||||||
// will not otherwise be popped until the next token is lexed. The problem is
|
|
||||||
// that the token may be lexed sometime after the vector of tokens itself is
|
|
||||||
// destroyed, which would be badness.
|
|
||||||
PP.RemoveTopOfLexerStack();
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of
|
|
||||||
/// tokens into the literal string token that should be produced by the C #
|
|
||||||
/// preprocessor operator.
|
|
||||||
///
|
|
||||||
static Token StringifyArgument(const Token *ArgToks,
|
|
||||||
Preprocessor &PP, bool Charify = false) {
|
|
||||||
Token Tok;
|
|
||||||
Tok.startToken();
|
|
||||||
Tok.setKind(tok::string_literal);
|
|
||||||
|
|
||||||
const Token *ArgTokStart = ArgToks;
|
|
||||||
|
|
||||||
// Stringify all the tokens.
|
|
||||||
std::string Result = "\"";
|
|
||||||
// FIXME: Optimize this loop to not use std::strings.
|
|
||||||
bool isFirst = true;
|
|
||||||
for (; ArgToks->getKind() != tok::eof; ++ArgToks) {
|
|
||||||
const Token &Tok = *ArgToks;
|
|
||||||
if (!isFirst && (Tok.hasLeadingSpace() || Tok.isAtStartOfLine()))
|
|
||||||
Result += ' ';
|
|
||||||
isFirst = false;
|
|
||||||
|
|
||||||
// If this is a string or character constant, escape the token as specified
|
|
||||||
// by 6.10.3.2p2.
|
|
||||||
if (Tok.getKind() == tok::string_literal || // "foo"
|
|
||||||
Tok.getKind() == tok::wide_string_literal || // L"foo"
|
|
||||||
Tok.getKind() == tok::char_constant) { // 'x' and L'x'.
|
|
||||||
Result += Lexer::Stringify(PP.getSpelling(Tok));
|
|
||||||
} else {
|
|
||||||
// Otherwise, just append the token.
|
|
||||||
Result += PP.getSpelling(Tok);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the last character of the string is a \, and if it isn't escaped, this
|
|
||||||
// is an invalid string literal, diagnose it as specified in C99.
|
|
||||||
if (Result[Result.size()-1] == '\\') {
|
|
||||||
// Count the number of consequtive \ characters. If even, then they are
|
|
||||||
// just escaped backslashes, otherwise it's an error.
|
|
||||||
unsigned FirstNonSlash = Result.size()-2;
|
|
||||||
// Guaranteed to find the starting " if nothing else.
|
|
||||||
while (Result[FirstNonSlash] == '\\')
|
|
||||||
--FirstNonSlash;
|
|
||||||
if ((Result.size()-1-FirstNonSlash) & 1) {
|
|
||||||
// Diagnose errors for things like: #define F(X) #X / F(\)
|
|
||||||
PP.Diag(ArgToks[-1], diag::pp_invalid_string_literal);
|
|
||||||
Result.erase(Result.end()-1); // remove one of the \'s.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Result += '"';
|
|
||||||
|
|
||||||
// If this is the charify operation and the result is not a legal character
|
|
||||||
// constant, diagnose it.
|
|
||||||
if (Charify) {
|
|
||||||
// First step, turn double quotes into single quotes:
|
|
||||||
Result[0] = '\'';
|
|
||||||
Result[Result.size()-1] = '\'';
|
|
||||||
|
|
||||||
// Check for bogus character.
|
|
||||||
bool isBad = false;
|
|
||||||
if (Result.size() == 3) {
|
|
||||||
isBad = Result[1] == '\''; // ''' is not legal. '\' already fixed above.
|
|
||||||
} else {
|
|
||||||
isBad = (Result.size() != 4 || Result[1] != '\\'); // Not '\x'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBad) {
|
|
||||||
PP.Diag(ArgTokStart[0], diag::err_invalid_character_to_charify);
|
|
||||||
Result = "' '"; // Use something arbitrary, but legal.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Tok.setLength(Result.size());
|
|
||||||
Tok.setLocation(PP.CreateString(&Result[0], Result.size()));
|
|
||||||
return Tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getStringifiedArgument - Compute, cache, and return the specified argument
|
|
||||||
/// that has been 'stringified' as required by the # operator.
|
|
||||||
const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
|
|
||||||
Preprocessor &PP) {
|
|
||||||
assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!");
|
|
||||||
if (StringifiedArgs.empty()) {
|
|
||||||
StringifiedArgs.resize(getNumArguments());
|
|
||||||
memset(&StringifiedArgs[0], 0,
|
|
||||||
sizeof(StringifiedArgs[0])*getNumArguments());
|
|
||||||
}
|
|
||||||
if (StringifiedArgs[ArgNo].getKind() != tok::string_literal)
|
|
||||||
StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP);
|
|
||||||
return StringifiedArgs[ArgNo];
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// MacroExpander Implementation
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// Create a macro expander for the specified macro with the specified actual
|
|
||||||
/// arguments. Note that this ctor takes ownership of the ActualArgs pointer.
|
|
||||||
void MacroExpander::Init(Token &Tok, MacroArgs *Actuals) {
|
|
||||||
// If the client is reusing a macro expander, make sure to free any memory
|
|
||||||
// associated with it.
|
|
||||||
destroy();
|
|
||||||
|
|
||||||
Macro = Tok.getIdentifierInfo()->getMacroInfo();
|
|
||||||
ActualArgs = Actuals;
|
|
||||||
CurToken = 0;
|
|
||||||
InstantiateLoc = Tok.getLocation();
|
|
||||||
AtStartOfLine = Tok.isAtStartOfLine();
|
|
||||||
HasLeadingSpace = Tok.hasLeadingSpace();
|
|
||||||
MacroTokens = &*Macro->tokens_begin();
|
|
||||||
OwnsMacroTokens = false;
|
|
||||||
NumMacroTokens = Macro->tokens_end()-Macro->tokens_begin();
|
|
||||||
|
|
||||||
// If this is a function-like macro, expand the arguments and change
|
|
||||||
// MacroTokens to point to the expanded tokens.
|
|
||||||
if (Macro->isFunctionLike() && Macro->getNumArgs())
|
|
||||||
ExpandFunctionArguments();
|
|
||||||
|
|
||||||
// Mark the macro as currently disabled, so that it is not recursively
|
|
||||||
// expanded. The macro must be disabled only after argument pre-expansion of
|
|
||||||
// function-like macro arguments occurs.
|
|
||||||
Macro->DisableMacro();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Create a macro expander for the specified token stream. This does not
|
|
||||||
/// take ownership of the specified token vector.
|
|
||||||
void MacroExpander::Init(const Token *TokArray, unsigned NumToks) {
|
|
||||||
// If the client is reusing a macro expander, make sure to free any memory
|
|
||||||
// associated with it.
|
|
||||||
destroy();
|
|
||||||
|
|
||||||
Macro = 0;
|
|
||||||
ActualArgs = 0;
|
|
||||||
MacroTokens = TokArray;
|
|
||||||
OwnsMacroTokens = false;
|
|
||||||
NumMacroTokens = NumToks;
|
|
||||||
CurToken = 0;
|
|
||||||
InstantiateLoc = SourceLocation();
|
|
||||||
AtStartOfLine = false;
|
|
||||||
HasLeadingSpace = false;
|
|
||||||
|
|
||||||
// Set HasLeadingSpace/AtStartOfLine so that the first token will be
|
|
||||||
// returned unmodified.
|
|
||||||
if (NumToks != 0) {
|
|
||||||
AtStartOfLine = TokArray[0].isAtStartOfLine();
|
|
||||||
HasLeadingSpace = TokArray[0].hasLeadingSpace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MacroExpander::destroy() {
|
|
||||||
// If this was a function-like macro that actually uses its arguments, delete
|
|
||||||
// the expanded tokens.
|
|
||||||
if (OwnsMacroTokens) {
|
|
||||||
delete [] MacroTokens;
|
|
||||||
MacroTokens = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// MacroExpander owns its formal arguments.
|
|
||||||
if (ActualArgs) ActualArgs->destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Expand the arguments of a function-like macro so that we can quickly
|
|
||||||
/// return preexpanded tokens from MacroTokens.
|
|
||||||
void MacroExpander::ExpandFunctionArguments() {
|
|
||||||
llvm::SmallVector<Token, 128> ResultToks;
|
|
||||||
|
|
||||||
// Loop through the MacroTokens tokens, expanding them into ResultToks. Keep
|
|
||||||
// track of whether we change anything. If not, no need to keep them. If so,
|
|
||||||
// we install the newly expanded sequence as MacroTokens.
|
|
||||||
bool MadeChange = false;
|
|
||||||
|
|
||||||
// NextTokGetsSpace - When this is true, the next token appended to the
|
|
||||||
// output list will get a leading space, regardless of whether it had one to
|
|
||||||
// begin with or not. This is used for placemarker support.
|
|
||||||
bool NextTokGetsSpace = false;
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = NumMacroTokens; i != e; ++i) {
|
|
||||||
// If we found the stringify operator, get the argument stringified. The
|
|
||||||
// preprocessor already verified that the following token is a macro name
|
|
||||||
// when the #define was parsed.
|
|
||||||
const Token &CurTok = MacroTokens[i];
|
|
||||||
if (CurTok.getKind() == tok::hash || CurTok.getKind() == tok::hashat) {
|
|
||||||
int ArgNo = Macro->getArgumentNum(MacroTokens[i+1].getIdentifierInfo());
|
|
||||||
assert(ArgNo != -1 && "Token following # is not an argument?");
|
|
||||||
|
|
||||||
Token Res;
|
|
||||||
if (CurTok.getKind() == tok::hash) // Stringify
|
|
||||||
Res = ActualArgs->getStringifiedArgument(ArgNo, PP);
|
|
||||||
else {
|
|
||||||
// 'charify': don't bother caching these.
|
|
||||||
Res = StringifyArgument(ActualArgs->getUnexpArgument(ArgNo), PP, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The stringified/charified string leading space flag gets set to match
|
|
||||||
// the #/#@ operator.
|
|
||||||
if (CurTok.hasLeadingSpace() || NextTokGetsSpace)
|
|
||||||
Res.setFlag(Token::LeadingSpace);
|
|
||||||
|
|
||||||
ResultToks.push_back(Res);
|
|
||||||
MadeChange = true;
|
|
||||||
++i; // Skip arg name.
|
|
||||||
NextTokGetsSpace = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, if this is not an argument token, just add the token to the
|
|
||||||
// output buffer.
|
|
||||||
IdentifierInfo *II = CurTok.getIdentifierInfo();
|
|
||||||
int ArgNo = II ? Macro->getArgumentNum(II) : -1;
|
|
||||||
if (ArgNo == -1) {
|
|
||||||
// This isn't an argument, just add it.
|
|
||||||
ResultToks.push_back(CurTok);
|
|
||||||
|
|
||||||
if (NextTokGetsSpace) {
|
|
||||||
ResultToks.back().setFlag(Token::LeadingSpace);
|
|
||||||
NextTokGetsSpace = false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// An argument is expanded somehow, the result is different than the
|
|
||||||
// input.
|
|
||||||
MadeChange = true;
|
|
||||||
|
|
||||||
// Otherwise, this is a use of the argument. Find out if there is a paste
|
|
||||||
// (##) operator before or after the argument.
|
|
||||||
bool PasteBefore =
|
|
||||||
!ResultToks.empty() && ResultToks.back().getKind() == tok::hashhash;
|
|
||||||
bool PasteAfter = i+1 != e && MacroTokens[i+1].getKind() == tok::hashhash;
|
|
||||||
|
|
||||||
// If it is not the LHS/RHS of a ## operator, we must pre-expand the
|
|
||||||
// argument and substitute the expanded tokens into the result. This is
|
|
||||||
// C99 6.10.3.1p1.
|
|
||||||
if (!PasteBefore && !PasteAfter) {
|
|
||||||
const Token *ResultArgToks;
|
|
||||||
|
|
||||||
// Only preexpand the argument if it could possibly need it. This
|
|
||||||
// avoids some work in common cases.
|
|
||||||
const Token *ArgTok = ActualArgs->getUnexpArgument(ArgNo);
|
|
||||||
if (ActualArgs->ArgNeedsPreexpansion(ArgTok))
|
|
||||||
ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, PP)[0];
|
|
||||||
else
|
|
||||||
ResultArgToks = ArgTok; // Use non-preexpanded tokens.
|
|
||||||
|
|
||||||
// If the arg token expanded into anything, append it.
|
|
||||||
if (ResultArgToks->getKind() != tok::eof) {
|
|
||||||
unsigned FirstResult = ResultToks.size();
|
|
||||||
unsigned NumToks = MacroArgs::getArgLength(ResultArgToks);
|
|
||||||
ResultToks.append(ResultArgToks, ResultArgToks+NumToks);
|
|
||||||
|
|
||||||
// If any tokens were substituted from the argument, the whitespace
|
|
||||||
// before the first token should match the whitespace of the arg
|
|
||||||
// identifier.
|
|
||||||
ResultToks[FirstResult].setFlagValue(Token::LeadingSpace,
|
|
||||||
CurTok.hasLeadingSpace() ||
|
|
||||||
NextTokGetsSpace);
|
|
||||||
NextTokGetsSpace = false;
|
|
||||||
} else {
|
|
||||||
// If this is an empty argument, and if there was whitespace before the
|
|
||||||
// formal token, make sure the next token gets whitespace before it.
|
|
||||||
NextTokGetsSpace = CurTok.hasLeadingSpace();
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Okay, we have a token that is either the LHS or RHS of a paste (##)
|
|
||||||
// argument. It gets substituted as its non-pre-expanded tokens.
|
|
||||||
const Token *ArgToks = ActualArgs->getUnexpArgument(ArgNo);
|
|
||||||
unsigned NumToks = MacroArgs::getArgLength(ArgToks);
|
|
||||||
if (NumToks) { // Not an empty argument?
|
|
||||||
ResultToks.append(ArgToks, ArgToks+NumToks);
|
|
||||||
|
|
||||||
// If the next token was supposed to get leading whitespace, ensure it has
|
|
||||||
// it now.
|
|
||||||
if (NextTokGetsSpace) {
|
|
||||||
ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace);
|
|
||||||
NextTokGetsSpace = false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If an empty argument is on the LHS or RHS of a paste, the standard (C99
|
|
||||||
// 6.10.3.3p2,3) calls for a bunch of placemarker stuff to occur. We
|
|
||||||
// implement this by eating ## operators when a LHS or RHS expands to
|
|
||||||
// empty.
|
|
||||||
NextTokGetsSpace |= CurTok.hasLeadingSpace();
|
|
||||||
if (PasteAfter) {
|
|
||||||
// Discard the argument token and skip (don't copy to the expansion
|
|
||||||
// buffer) the paste operator after it.
|
|
||||||
NextTokGetsSpace |= MacroTokens[i+1].hasLeadingSpace();
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is on the RHS of a paste operator, we've already copied the
|
|
||||||
// paste operator to the ResultToks list. Remove it.
|
|
||||||
assert(PasteBefore && ResultToks.back().getKind() == tok::hashhash);
|
|
||||||
NextTokGetsSpace |= ResultToks.back().hasLeadingSpace();
|
|
||||||
ResultToks.pop_back();
|
|
||||||
|
|
||||||
// If this is the __VA_ARGS__ token, and if the argument wasn't provided,
|
|
||||||
// and if the macro had at least one real argument, and if the token before
|
|
||||||
// the ## was a comma, remove the comma.
|
|
||||||
if ((unsigned)ArgNo == Macro->getNumArgs()-1 && // is __VA_ARGS__
|
|
||||||
ActualArgs->isVarargsElidedUse() && // Argument elided.
|
|
||||||
!ResultToks.empty() && ResultToks.back().getKind() == tok::comma) {
|
|
||||||
// Never add a space, even if the comma, ##, or arg had a space.
|
|
||||||
NextTokGetsSpace = false;
|
|
||||||
ResultToks.pop_back();
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If anything changed, install this as the new MacroTokens list.
|
|
||||||
if (MadeChange) {
|
|
||||||
// This is deleted in the dtor.
|
|
||||||
NumMacroTokens = ResultToks.size();
|
|
||||||
Token *Res = new Token[ResultToks.size()];
|
|
||||||
if (NumMacroTokens)
|
|
||||||
memcpy(Res, &ResultToks[0], NumMacroTokens*sizeof(Token));
|
|
||||||
MacroTokens = Res;
|
|
||||||
OwnsMacroTokens = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lex - Lex and return a token from this macro stream.
|
|
||||||
///
|
|
||||||
void MacroExpander::Lex(Token &Tok) {
|
|
||||||
// Lexing off the end of the macro, pop this macro off the expansion stack.
|
|
||||||
if (isAtEnd()) {
|
|
||||||
// If this is a macro (not a token stream), mark the macro enabled now
|
|
||||||
// that it is no longer being expanded.
|
|
||||||
if (Macro) Macro->EnableMacro();
|
|
||||||
|
|
||||||
// Pop this context off the preprocessors lexer stack and get the next
|
|
||||||
// token. This will delete "this" so remember the PP instance var.
|
|
||||||
Preprocessor &PPCache = PP;
|
|
||||||
if (PP.HandleEndOfMacro(Tok))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// HandleEndOfMacro may not return a token. If it doesn't, lex whatever is
|
|
||||||
// next.
|
|
||||||
return PPCache.Lex(Tok);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is the first token of the expanded result, we inherit spacing
|
|
||||||
// properties later.
|
|
||||||
bool isFirstToken = CurToken == 0;
|
|
||||||
|
|
||||||
// Get the next token to return.
|
|
||||||
Tok = MacroTokens[CurToken++];
|
|
||||||
|
|
||||||
// If this token is followed by a token paste (##) operator, paste the tokens!
|
|
||||||
if (!isAtEnd() && MacroTokens[CurToken].getKind() == tok::hashhash)
|
|
||||||
PasteTokens(Tok);
|
|
||||||
|
|
||||||
// The token's current location indicate where the token was lexed from. We
|
|
||||||
// need this information to compute the spelling of the token, but any
|
|
||||||
// diagnostics for the expanded token should appear as if they came from
|
|
||||||
// InstantiationLoc. Pull this information together into a new SourceLocation
|
|
||||||
// that captures all of this.
|
|
||||||
if (InstantiateLoc.isValid()) { // Don't do this for token streams.
|
|
||||||
SourceManager &SrcMgr = PP.getSourceManager();
|
|
||||||
Tok.setLocation(SrcMgr.getInstantiationLoc(Tok.getLocation(),
|
|
||||||
InstantiateLoc));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is the first token, set the lexical properties of the token to
|
|
||||||
// match the lexical properties of the macro identifier.
|
|
||||||
if (isFirstToken) {
|
|
||||||
Tok.setFlagValue(Token::StartOfLine , AtStartOfLine);
|
|
||||||
Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle recursive expansion!
|
|
||||||
if (Tok.getIdentifierInfo())
|
|
||||||
return PP.HandleIdentifier(Tok);
|
|
||||||
|
|
||||||
// Otherwise, return a normal token.
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ##
|
|
||||||
/// operator. Read the ## and RHS, and paste the LHS/RHS together. If there
|
|
||||||
/// are is another ## after it, chomp it iteratively. Return the result as Tok.
|
|
||||||
void MacroExpander::PasteTokens(Token &Tok) {
|
|
||||||
llvm::SmallVector<char, 128> Buffer;
|
|
||||||
do {
|
|
||||||
// Consume the ## operator.
|
|
||||||
SourceLocation PasteOpLoc = MacroTokens[CurToken].getLocation();
|
|
||||||
++CurToken;
|
|
||||||
assert(!isAtEnd() && "No token on the RHS of a paste operator!");
|
|
||||||
|
|
||||||
// Get the RHS token.
|
|
||||||
const Token &RHS = MacroTokens[CurToken];
|
|
||||||
|
|
||||||
bool isInvalid = false;
|
|
||||||
|
|
||||||
// Allocate space for the result token. This is guaranteed to be enough for
|
|
||||||
// the two tokens and a null terminator.
|
|
||||||
Buffer.resize(Tok.getLength() + RHS.getLength() + 1);
|
|
||||||
|
|
||||||
// Get the spelling of the LHS token in Buffer.
|
|
||||||
const char *BufPtr = &Buffer[0];
|
|
||||||
unsigned LHSLen = PP.getSpelling(Tok, BufPtr);
|
|
||||||
if (BufPtr != &Buffer[0]) // Really, we want the chars in Buffer!
|
|
||||||
memcpy(&Buffer[0], BufPtr, LHSLen);
|
|
||||||
|
|
||||||
BufPtr = &Buffer[LHSLen];
|
|
||||||
unsigned RHSLen = PP.getSpelling(RHS, BufPtr);
|
|
||||||
if (BufPtr != &Buffer[LHSLen]) // Really, we want the chars in Buffer!
|
|
||||||
memcpy(&Buffer[LHSLen], BufPtr, RHSLen);
|
|
||||||
|
|
||||||
// Add null terminator.
|
|
||||||
Buffer[LHSLen+RHSLen] = '\0';
|
|
||||||
|
|
||||||
// Trim excess space.
|
|
||||||
Buffer.resize(LHSLen+RHSLen+1);
|
|
||||||
|
|
||||||
// Plop the pasted result (including the trailing newline and null) into a
|
|
||||||
// scratch buffer where we can lex it.
|
|
||||||
SourceLocation ResultTokLoc = PP.CreateString(&Buffer[0], Buffer.size());
|
|
||||||
|
|
||||||
// Lex the resultant pasted token into Result.
|
|
||||||
Token Result;
|
|
||||||
|
|
||||||
// Avoid testing /*, as the lexer would think it is the start of a comment
|
|
||||||
// and emit an error that it is unterminated.
|
|
||||||
if (Tok.getKind() == tok::slash && RHS.getKind() == tok::star) {
|
|
||||||
isInvalid = true;
|
|
||||||
} else if (Tok.getKind() == tok::identifier &&
|
|
||||||
RHS.getKind() == tok::identifier) {
|
|
||||||
// Common paste case: identifier+identifier = identifier. Avoid creating
|
|
||||||
// a lexer and other overhead.
|
|
||||||
PP.IncrementPasteCounter(true);
|
|
||||||
Result.startToken();
|
|
||||||
Result.setKind(tok::identifier);
|
|
||||||
Result.setLocation(ResultTokLoc);
|
|
||||||
Result.setLength(LHSLen+RHSLen);
|
|
||||||
} else {
|
|
||||||
PP.IncrementPasteCounter(false);
|
|
||||||
|
|
||||||
// Make a lexer to lex this string from.
|
|
||||||
SourceManager &SourceMgr = PP.getSourceManager();
|
|
||||||
const char *ResultStrData = SourceMgr.getCharacterData(ResultTokLoc);
|
|
||||||
|
|
||||||
// Make a lexer object so that we lex and expand the paste result.
|
|
||||||
Lexer *TL = new Lexer(ResultTokLoc, PP, ResultStrData,
|
|
||||||
ResultStrData+LHSLen+RHSLen /*don't include null*/);
|
|
||||||
|
|
||||||
// Lex a token in raw mode. This way it won't look up identifiers
|
|
||||||
// automatically, lexing off the end will return an eof token, and
|
|
||||||
// warnings are disabled. This returns true if the result token is the
|
|
||||||
// entire buffer.
|
|
||||||
bool IsComplete = TL->LexRawToken(Result);
|
|
||||||
|
|
||||||
// If we got an EOF token, we didn't form even ONE token. For example, we
|
|
||||||
// did "/ ## /" to get "//".
|
|
||||||
IsComplete &= Result.getKind() != tok::eof;
|
|
||||||
isInvalid = !IsComplete;
|
|
||||||
|
|
||||||
// We're now done with the temporary lexer.
|
|
||||||
delete TL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If pasting the two tokens didn't form a full new token, this is an error.
|
|
||||||
// This occurs with "x ## +" and other stuff. Return with Tok unmodified
|
|
||||||
// and with RHS as the next token to lex.
|
|
||||||
if (isInvalid) {
|
|
||||||
// If not in assembler language mode.
|
|
||||||
PP.Diag(PasteOpLoc, diag::err_pp_bad_paste,
|
|
||||||
std::string(Buffer.begin(), Buffer.end()-1));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Turn ## into 'other' to avoid # ## # from looking like a paste operator.
|
|
||||||
if (Result.getKind() == tok::hashhash)
|
|
||||||
Result.setKind(tok::unknown);
|
|
||||||
// FIXME: Turn __VARRGS__ into "not a token"?
|
|
||||||
|
|
||||||
// Transfer properties of the LHS over the the Result.
|
|
||||||
Result.setFlagValue(Token::StartOfLine , Tok.isAtStartOfLine());
|
|
||||||
Result.setFlagValue(Token::LeadingSpace, Tok.hasLeadingSpace());
|
|
||||||
|
|
||||||
// Finally, replace LHS with the result, consume the RHS, and iterate.
|
|
||||||
++CurToken;
|
|
||||||
Tok = Result;
|
|
||||||
} while (!isAtEnd() && MacroTokens[CurToken].getKind() == tok::hashhash);
|
|
||||||
|
|
||||||
// Now that we got the result token, it will be subject to expansion. Since
|
|
||||||
// token pasting re-lexes the result token in raw mode, identifier information
|
|
||||||
// isn't looked up. As such, if the result is an identifier, look up id info.
|
|
||||||
if (Tok.getKind() == tok::identifier) {
|
|
||||||
// Look up the identifier info for the token. We disabled identifier lookup
|
|
||||||
// by saying we're skipping contents, so we need to do this manually.
|
|
||||||
Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// isNextTokenLParen - If the next token lexed will pop this macro off the
|
|
||||||
/// expansion stack, return 2. If the next unexpanded token is a '(', return
|
|
||||||
/// 1, otherwise return 0.
|
|
||||||
unsigned MacroExpander::isNextTokenLParen() const {
|
|
||||||
// Out of tokens?
|
|
||||||
if (isAtEnd())
|
|
||||||
return 2;
|
|
||||||
return MacroTokens[CurToken].getKind() == tok::l_paren;
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
//===--- MacroInfo.cpp - Information about #defined identifiers -----------===//
|
|
||||||
//
|
|
||||||
// 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 MacroInfo interface.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Lex/MacroInfo.h"
|
|
||||||
#include "clang/Lex/Preprocessor.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
|
|
||||||
IsFunctionLike = false;
|
|
||||||
IsC99Varargs = false;
|
|
||||||
IsGNUVarargs = false;
|
|
||||||
IsBuiltinMacro = false;
|
|
||||||
IsTargetSpecific = false;
|
|
||||||
IsDisabled = false;
|
|
||||||
IsUsed = true;
|
|
||||||
|
|
||||||
ArgumentList = 0;
|
|
||||||
NumArguments = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// isIdenticalTo - Return true if the specified macro definition is equal to
|
|
||||||
/// this macro in spelling, arguments, and whitespace. This is used to emit
|
|
||||||
/// duplicate definition warnings. This implements the rules in C99 6.10.3.
|
|
||||||
///
|
|
||||||
/// Note that this intentionally does not check isTargetSpecific for matching.
|
|
||||||
///
|
|
||||||
bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
|
|
||||||
// Check # tokens in replacement, number of args, and various flags all match.
|
|
||||||
if (ReplacementTokens.size() != Other.ReplacementTokens.size() ||
|
|
||||||
getNumArgs() != Other.getNumArgs() ||
|
|
||||||
isFunctionLike() != Other.isFunctionLike() ||
|
|
||||||
isC99Varargs() != Other.isC99Varargs() ||
|
|
||||||
isGNUVarargs() != Other.isGNUVarargs())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check arguments.
|
|
||||||
for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end();
|
|
||||||
I != E; ++I, ++OI)
|
|
||||||
if (*I != *OI) return false;
|
|
||||||
|
|
||||||
// Check all the tokens.
|
|
||||||
for (unsigned i = 0, e = ReplacementTokens.size(); i != e; ++i) {
|
|
||||||
const Token &A = ReplacementTokens[i];
|
|
||||||
const Token &B = Other.ReplacementTokens[i];
|
|
||||||
if (A.getKind() != B.getKind() ||
|
|
||||||
A.isAtStartOfLine() != B.isAtStartOfLine() ||
|
|
||||||
A.hasLeadingSpace() != B.hasLeadingSpace())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// If this is an identifier, it is easy.
|
|
||||||
if (A.getIdentifierInfo() || B.getIdentifierInfo()) {
|
|
||||||
if (A.getIdentifierInfo() != B.getIdentifierInfo())
|
|
||||||
return false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, check the spelling.
|
|
||||||
if (PP.getSpelling(A) != PP.getSpelling(B))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
##===- clang/Lex/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 Lexer library for the C-Language front-end.
|
|
||||||
#
|
|
||||||
##===----------------------------------------------------------------------===##
|
|
||||||
|
|
||||||
LEVEL = ../../..
|
|
||||||
include $(LEVEL)/Makefile.config
|
|
||||||
|
|
||||||
LIBRARYNAME := clangLex
|
|
||||||
BUILD_ARCHIVE = 1
|
|
||||||
CXXFLAGS = -fno-rtti
|
|
||||||
|
|
||||||
ifeq ($(ARCH),PowerPC)
|
|
||||||
CXXFLAGS += -maltivec
|
|
||||||
endif
|
|
||||||
|
|
||||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.common
|
|
||||||
|
|
||||||
@@ -1,659 +0,0 @@
|
|||||||
//===--- PPExpressions.cpp - Preprocessor Expression Evaluation -----------===//
|
|
||||||
//
|
|
||||||
// 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 Preprocessor::EvaluateDirectiveExpression method,
|
|
||||||
// which parses and evaluates integer constant expressions for #if directives.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// FIXME: implement testing for #assert's.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Lex/Preprocessor.h"
|
|
||||||
#include "clang/Lex/MacroInfo.h"
|
|
||||||
#include "clang/Lex/LiteralSupport.h"
|
|
||||||
#include "clang/Basic/TargetInfo.h"
|
|
||||||
#include "clang/Basic/TokenKinds.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "llvm/ADT/APSInt.h"
|
|
||||||
#include "llvm/ADT/SmallString.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
static bool EvaluateDirectiveSubExpr(llvm::APSInt &LHS, unsigned MinPrec,
|
|
||||||
Token &PeekTok, bool ValueLive,
|
|
||||||
Preprocessor &PP);
|
|
||||||
|
|
||||||
/// DefinedTracker - This struct is used while parsing expressions to keep track
|
|
||||||
/// of whether !defined(X) has been seen.
|
|
||||||
///
|
|
||||||
/// With this simple scheme, we handle the basic forms:
|
|
||||||
/// !defined(X) and !defined X
|
|
||||||
/// but we also trivially handle (silly) stuff like:
|
|
||||||
/// !!!defined(X) and +!defined(X) and !+!+!defined(X) and !(defined(X)).
|
|
||||||
struct DefinedTracker {
|
|
||||||
/// Each time a Value is evaluated, it returns information about whether the
|
|
||||||
/// parsed value is of the form defined(X), !defined(X) or is something else.
|
|
||||||
enum TrackerState {
|
|
||||||
DefinedMacro, // defined(X)
|
|
||||||
NotDefinedMacro, // !defined(X)
|
|
||||||
Unknown // Something else.
|
|
||||||
} State;
|
|
||||||
/// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this
|
|
||||||
/// indicates the macro that was checked.
|
|
||||||
IdentifierInfo *TheMacro;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// EvaluateValue - Evaluate the token PeekTok (and any others needed) and
|
|
||||||
/// return the computed value in Result. Return true if there was an error
|
|
||||||
/// parsing. This function also returns information about the form of the
|
|
||||||
/// expression in DT. See above for information on what DT means.
|
|
||||||
///
|
|
||||||
/// If ValueLive is false, then this value is being evaluated in a context where
|
|
||||||
/// the result is not used. As such, avoid diagnostics that relate to
|
|
||||||
/// evaluation.
|
|
||||||
static bool EvaluateValue(llvm::APSInt &Result, Token &PeekTok,
|
|
||||||
DefinedTracker &DT, bool ValueLive,
|
|
||||||
Preprocessor &PP) {
|
|
||||||
Result = 0;
|
|
||||||
DT.State = DefinedTracker::Unknown;
|
|
||||||
|
|
||||||
// If this token's spelling is a pp-identifier, check to see if it is
|
|
||||||
// 'defined' or if it is a macro. Note that we check here because many
|
|
||||||
// keywords are pp-identifiers, so we can't check the kind.
|
|
||||||
if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) {
|
|
||||||
// If this identifier isn't 'defined' and it wasn't macro expanded, it turns
|
|
||||||
// into a simple 0, unless it is the C++ keyword "true", in which case it
|
|
||||||
// turns into "1".
|
|
||||||
if (II->getPPKeywordID() != tok::pp_defined) {
|
|
||||||
Result = II->getTokenID() == tok::kw_true;
|
|
||||||
Result.setIsUnsigned(false); // "0" is signed intmax_t 0.
|
|
||||||
PP.LexNonComment(PeekTok);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle "defined X" and "defined(X)".
|
|
||||||
|
|
||||||
// Get the next token, don't expand it.
|
|
||||||
PP.LexUnexpandedToken(PeekTok);
|
|
||||||
|
|
||||||
// Two options, it can either be a pp-identifier or a (.
|
|
||||||
bool InParens = false;
|
|
||||||
if (PeekTok.getKind() == tok::l_paren) {
|
|
||||||
// Found a paren, remember we saw it and skip it.
|
|
||||||
InParens = true;
|
|
||||||
PP.LexUnexpandedToken(PeekTok);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we don't have a pp-identifier now, this is an error.
|
|
||||||
if ((II = PeekTok.getIdentifierInfo()) == 0) {
|
|
||||||
PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, we got an identifier, is it defined to something?
|
|
||||||
Result = II->getMacroInfo() != 0;
|
|
||||||
Result.setIsUnsigned(false); // Result is signed intmax_t.
|
|
||||||
|
|
||||||
// If there is a macro, mark it used.
|
|
||||||
if (Result != 0 && ValueLive) {
|
|
||||||
II->getMacroInfo()->setIsUsed(true);
|
|
||||||
|
|
||||||
// If this is the first use of a target-specific macro, warn about it.
|
|
||||||
if (II->getMacroInfo()->isTargetSpecific()) {
|
|
||||||
// Don't warn on second use.
|
|
||||||
II->getMacroInfo()->setIsTargetSpecific(false);
|
|
||||||
PP.getTargetInfo().DiagnoseNonPortability(PeekTok.getLocation(),
|
|
||||||
diag::port_target_macro_use);
|
|
||||||
}
|
|
||||||
} else if (ValueLive) {
|
|
||||||
// Use of a target-specific macro for some other target? If so, warn.
|
|
||||||
if (II->isOtherTargetMacro()) {
|
|
||||||
II->setIsOtherTargetMacro(false); // Don't warn on second use.
|
|
||||||
PP.getTargetInfo().DiagnoseNonPortability(PeekTok.getLocation(),
|
|
||||||
diag::port_target_macro_use);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume identifier.
|
|
||||||
PP.LexNonComment(PeekTok);
|
|
||||||
|
|
||||||
// If we are in parens, ensure we have a trailing ).
|
|
||||||
if (InParens) {
|
|
||||||
if (PeekTok.getKind() != tok::r_paren) {
|
|
||||||
PP.Diag(PeekTok, diag::err_pp_missing_rparen);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Consume the ).
|
|
||||||
PP.LexNonComment(PeekTok);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success, remember that we saw defined(X).
|
|
||||||
DT.State = DefinedTracker::DefinedMacro;
|
|
||||||
DT.TheMacro = II;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (PeekTok.getKind()) {
|
|
||||||
default: // Non-value token.
|
|
||||||
PP.Diag(PeekTok, diag::err_pp_expr_bad_token);
|
|
||||||
return true;
|
|
||||||
case tok::eom:
|
|
||||||
case tok::r_paren:
|
|
||||||
// If there is no expression, report and exit.
|
|
||||||
PP.Diag(PeekTok, diag::err_pp_expected_value_in_expr);
|
|
||||||
return true;
|
|
||||||
case tok::numeric_constant: {
|
|
||||||
llvm::SmallString<64> IntegerBuffer;
|
|
||||||
IntegerBuffer.resize(PeekTok.getLength());
|
|
||||||
const char *ThisTokBegin = &IntegerBuffer[0];
|
|
||||||
unsigned ActualLength = PP.getSpelling(PeekTok, ThisTokBegin);
|
|
||||||
NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
|
|
||||||
PeekTok.getLocation(), PP);
|
|
||||||
if (Literal.hadError)
|
|
||||||
return true; // a diagnostic was already reported.
|
|
||||||
|
|
||||||
if (Literal.isFloatingLiteral() || Literal.isImaginary) {
|
|
||||||
PP.Diag(PeekTok, diag::err_pp_illegal_floating_literal);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
assert(Literal.isIntegerLiteral() && "Unknown ppnumber");
|
|
||||||
|
|
||||||
// long long is a C99 feature.
|
|
||||||
if (!PP.getLangOptions().C99 && !PP.getLangOptions().CPlusPlus0x
|
|
||||||
&& Literal.isLongLong)
|
|
||||||
PP.Diag(PeekTok, diag::ext_longlong);
|
|
||||||
|
|
||||||
// Parse the integer literal into Result.
|
|
||||||
if (Literal.GetIntegerValue(Result)) {
|
|
||||||
// Overflow parsing integer literal.
|
|
||||||
if (ValueLive) PP.Diag(PeekTok, diag::warn_integer_too_large);
|
|
||||||
Result.setIsUnsigned(true);
|
|
||||||
} else {
|
|
||||||
// Set the signedness of the result to match whether there was a U suffix
|
|
||||||
// or not.
|
|
||||||
Result.setIsUnsigned(Literal.isUnsigned);
|
|
||||||
|
|
||||||
// Detect overflow based on whether the value is signed. If signed
|
|
||||||
// and if the value is too large, emit a warning "integer constant is so
|
|
||||||
// large that it is unsigned" e.g. on 12345678901234567890 where intmax_t
|
|
||||||
// is 64-bits.
|
|
||||||
if (!Literal.isUnsigned && Result.isNegative()) {
|
|
||||||
if (ValueLive)PP.Diag(PeekTok, diag::warn_integer_too_large_for_signed);
|
|
||||||
Result.setIsUnsigned(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume the token.
|
|
||||||
PP.LexNonComment(PeekTok);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case tok::char_constant: { // 'x'
|
|
||||||
llvm::SmallString<32> CharBuffer;
|
|
||||||
CharBuffer.resize(PeekTok.getLength());
|
|
||||||
const char *ThisTokBegin = &CharBuffer[0];
|
|
||||||
unsigned ActualLength = PP.getSpelling(PeekTok, ThisTokBegin);
|
|
||||||
CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
|
|
||||||
PeekTok.getLocation(), PP);
|
|
||||||
if (Literal.hadError())
|
|
||||||
return true; // A diagnostic was already emitted.
|
|
||||||
|
|
||||||
// Character literals are always int or wchar_t, expand to intmax_t.
|
|
||||||
TargetInfo &TI = PP.getTargetInfo();
|
|
||||||
unsigned NumBits;
|
|
||||||
if (Literal.isWide())
|
|
||||||
NumBits = TI.getWCharWidth(PeekTok.getLocation());
|
|
||||||
else
|
|
||||||
NumBits = TI.getCharWidth(PeekTok.getLocation());
|
|
||||||
|
|
||||||
// Set the width.
|
|
||||||
llvm::APSInt Val(NumBits);
|
|
||||||
// Set the value.
|
|
||||||
Val = Literal.getValue();
|
|
||||||
// Set the signedness.
|
|
||||||
Val.setIsUnsigned(!TI.isCharSigned(PeekTok.getLocation()));
|
|
||||||
|
|
||||||
if (Result.getBitWidth() > Val.getBitWidth()) {
|
|
||||||
if (Val.isSigned())
|
|
||||||
Result = Val.sext(Result.getBitWidth());
|
|
||||||
else
|
|
||||||
Result = Val.zext(Result.getBitWidth());
|
|
||||||
Result.setIsUnsigned(Val.isUnsigned());
|
|
||||||
} else {
|
|
||||||
assert(Result.getBitWidth() == Val.getBitWidth() &&
|
|
||||||
"intmax_t smaller than char/wchar_t?");
|
|
||||||
Result = Val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume the token.
|
|
||||||
PP.LexNonComment(PeekTok);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case tok::l_paren:
|
|
||||||
PP.LexNonComment(PeekTok); // Eat the (.
|
|
||||||
// Parse the value and if there are any binary operators involved, parse
|
|
||||||
// them.
|
|
||||||
if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
|
|
||||||
|
|
||||||
// If this is a silly value like (X), which doesn't need parens, check for
|
|
||||||
// !(defined X).
|
|
||||||
if (PeekTok.getKind() == tok::r_paren) {
|
|
||||||
// Just use DT unmodified as our result.
|
|
||||||
} else {
|
|
||||||
if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (PeekTok.getKind() != tok::r_paren) {
|
|
||||||
PP.Diag(PeekTok, diag::err_pp_expected_rparen);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
DT.State = DefinedTracker::Unknown;
|
|
||||||
}
|
|
||||||
PP.LexNonComment(PeekTok); // Eat the ).
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case tok::plus:
|
|
||||||
// Unary plus doesn't modify the value.
|
|
||||||
PP.LexNonComment(PeekTok);
|
|
||||||
return EvaluateValue(Result, PeekTok, DT, ValueLive, PP);
|
|
||||||
case tok::minus: {
|
|
||||||
SourceLocation Loc = PeekTok.getLocation();
|
|
||||||
PP.LexNonComment(PeekTok);
|
|
||||||
if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
|
|
||||||
// C99 6.5.3.3p3: The sign of the result matches the sign of the operand.
|
|
||||||
Result = -Result;
|
|
||||||
|
|
||||||
bool Overflow = false;
|
|
||||||
if (Result.isUnsigned())
|
|
||||||
Overflow = !Result.isPositive();
|
|
||||||
else if (Result.isMinSignedValue())
|
|
||||||
Overflow = true; // -MININT is the only thing that overflows.
|
|
||||||
|
|
||||||
// If this operator is live and overflowed, report the issue.
|
|
||||||
if (Overflow && ValueLive)
|
|
||||||
PP.Diag(Loc, diag::warn_pp_expr_overflow);
|
|
||||||
|
|
||||||
DT.State = DefinedTracker::Unknown;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
case tok::tilde:
|
|
||||||
PP.LexNonComment(PeekTok);
|
|
||||||
if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
|
|
||||||
// C99 6.5.3.3p4: The sign of the result matches the sign of the operand.
|
|
||||||
Result = ~Result;
|
|
||||||
DT.State = DefinedTracker::Unknown;
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case tok::exclaim:
|
|
||||||
PP.LexNonComment(PeekTok);
|
|
||||||
if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
|
|
||||||
Result = !Result;
|
|
||||||
// C99 6.5.3.3p5: The sign of the result is 'int', aka it is signed.
|
|
||||||
Result.setIsUnsigned(false);
|
|
||||||
|
|
||||||
if (DT.State == DefinedTracker::DefinedMacro)
|
|
||||||
DT.State = DefinedTracker::NotDefinedMacro;
|
|
||||||
else if (DT.State == DefinedTracker::NotDefinedMacro)
|
|
||||||
DT.State = DefinedTracker::DefinedMacro;
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// FIXME: Handle #assert
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// getPrecedence - Return the precedence of the specified binary operator
|
|
||||||
/// token. This returns:
|
|
||||||
/// ~0 - Invalid token.
|
|
||||||
/// 14 - *,/,%
|
|
||||||
/// 13 - -,+
|
|
||||||
/// 12 - <<,>>
|
|
||||||
/// 11 - >=, <=, >, <
|
|
||||||
/// 10 - ==, !=
|
|
||||||
/// 9 - &
|
|
||||||
/// 8 - ^
|
|
||||||
/// 7 - |
|
|
||||||
/// 6 - &&
|
|
||||||
/// 5 - ||
|
|
||||||
/// 4 - ?
|
|
||||||
/// 3 - :
|
|
||||||
/// 0 - eom, )
|
|
||||||
static unsigned getPrecedence(tok::TokenKind Kind) {
|
|
||||||
switch (Kind) {
|
|
||||||
default: return ~0U;
|
|
||||||
case tok::percent:
|
|
||||||
case tok::slash:
|
|
||||||
case tok::star: return 14;
|
|
||||||
case tok::plus:
|
|
||||||
case tok::minus: return 13;
|
|
||||||
case tok::lessless:
|
|
||||||
case tok::greatergreater: return 12;
|
|
||||||
case tok::lessequal:
|
|
||||||
case tok::less:
|
|
||||||
case tok::greaterequal:
|
|
||||||
case tok::greater: return 11;
|
|
||||||
case tok::exclaimequal:
|
|
||||||
case tok::equalequal: return 10;
|
|
||||||
case tok::amp: return 9;
|
|
||||||
case tok::caret: return 8;
|
|
||||||
case tok::pipe: return 7;
|
|
||||||
case tok::ampamp: return 6;
|
|
||||||
case tok::pipepipe: return 5;
|
|
||||||
case tok::question: return 4;
|
|
||||||
case tok::colon: return 3;
|
|
||||||
case tok::comma: return 2;
|
|
||||||
case tok::r_paren: return 0; // Lowest priority, end of expr.
|
|
||||||
case tok::eom: return 0; // Lowest priority, end of macro.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// EvaluateDirectiveSubExpr - Evaluate the subexpression whose first token is
|
|
||||||
/// PeekTok, and whose precedence is PeekPrec.
|
|
||||||
///
|
|
||||||
/// If ValueLive is false, then this value is being evaluated in a context where
|
|
||||||
/// the result is not used. As such, avoid diagnostics that relate to
|
|
||||||
/// evaluation.
|
|
||||||
static bool EvaluateDirectiveSubExpr(llvm::APSInt &LHS, unsigned MinPrec,
|
|
||||||
Token &PeekTok, bool ValueLive,
|
|
||||||
Preprocessor &PP) {
|
|
||||||
unsigned PeekPrec = getPrecedence(PeekTok.getKind());
|
|
||||||
// If this token isn't valid, report the error.
|
|
||||||
if (PeekPrec == ~0U) {
|
|
||||||
PP.Diag(PeekTok, diag::err_pp_expr_bad_token);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
// If this token has a lower precedence than we are allowed to parse, return
|
|
||||||
// it so that higher levels of the recursion can parse it.
|
|
||||||
if (PeekPrec < MinPrec)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
tok::TokenKind Operator = PeekTok.getKind();
|
|
||||||
|
|
||||||
// If this is a short-circuiting operator, see if the RHS of the operator is
|
|
||||||
// dead. Note that this cannot just clobber ValueLive. Consider
|
|
||||||
// "0 && 1 ? 4 : 1 / 0", which is parsed as "(0 && 1) ? 4 : (1 / 0)". In
|
|
||||||
// this example, the RHS of the && being dead does not make the rest of the
|
|
||||||
// expr dead.
|
|
||||||
bool RHSIsLive;
|
|
||||||
if (Operator == tok::ampamp && LHS == 0)
|
|
||||||
RHSIsLive = false; // RHS of "0 && x" is dead.
|
|
||||||
else if (Operator == tok::pipepipe && LHS != 0)
|
|
||||||
RHSIsLive = false; // RHS of "1 || x" is dead.
|
|
||||||
else if (Operator == tok::question && LHS == 0)
|
|
||||||
RHSIsLive = false; // RHS (x) of "0 ? x : y" is dead.
|
|
||||||
else
|
|
||||||
RHSIsLive = ValueLive;
|
|
||||||
|
|
||||||
// Consume the operator, saving the operator token for error reporting.
|
|
||||||
Token OpToken = PeekTok;
|
|
||||||
PP.LexNonComment(PeekTok);
|
|
||||||
|
|
||||||
llvm::APSInt RHS(LHS.getBitWidth());
|
|
||||||
// Parse the RHS of the operator.
|
|
||||||
DefinedTracker DT;
|
|
||||||
if (EvaluateValue(RHS, PeekTok, DT, RHSIsLive, PP)) return true;
|
|
||||||
|
|
||||||
// Remember the precedence of this operator and get the precedence of the
|
|
||||||
// operator immediately to the right of the RHS.
|
|
||||||
unsigned ThisPrec = PeekPrec;
|
|
||||||
PeekPrec = getPrecedence(PeekTok.getKind());
|
|
||||||
|
|
||||||
// If this token isn't valid, report the error.
|
|
||||||
if (PeekPrec == ~0U) {
|
|
||||||
PP.Diag(PeekTok, diag::err_pp_expr_bad_token);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isRightAssoc = Operator == tok::question;
|
|
||||||
|
|
||||||
// Get the precedence of the operator to the right of the RHS. If it binds
|
|
||||||
// more tightly with RHS than we do, evaluate it completely first.
|
|
||||||
if (ThisPrec < PeekPrec ||
|
|
||||||
(ThisPrec == PeekPrec && isRightAssoc)) {
|
|
||||||
if (EvaluateDirectiveSubExpr(RHS, ThisPrec+1, PeekTok, RHSIsLive, PP))
|
|
||||||
return true;
|
|
||||||
PeekPrec = getPrecedence(PeekTok.getKind());
|
|
||||||
}
|
|
||||||
assert(PeekPrec <= ThisPrec && "Recursion didn't work!");
|
|
||||||
|
|
||||||
// Usual arithmetic conversions (C99 6.3.1.8p1): result is unsigned if
|
|
||||||
// either operand is unsigned. Don't do this for x and y in "x ? y : z".
|
|
||||||
llvm::APSInt Res(LHS.getBitWidth());
|
|
||||||
if (Operator != tok::question) {
|
|
||||||
Res.setIsUnsigned(LHS.isUnsigned()|RHS.isUnsigned());
|
|
||||||
// If this just promoted something from signed to unsigned, and if the
|
|
||||||
// value was negative, warn about it.
|
|
||||||
if (ValueLive && Res.isUnsigned()) {
|
|
||||||
if (!LHS.isUnsigned() && LHS.isNegative())
|
|
||||||
PP.Diag(OpToken, diag::warn_pp_convert_lhs_to_positive,
|
|
||||||
LHS.toStringSigned() + " to " + LHS.toStringUnsigned());
|
|
||||||
if (!RHS.isUnsigned() && RHS.isNegative())
|
|
||||||
PP.Diag(OpToken, diag::warn_pp_convert_rhs_to_positive,
|
|
||||||
RHS.toStringSigned() + " to " + RHS.toStringUnsigned());
|
|
||||||
}
|
|
||||||
LHS.setIsUnsigned(Res.isUnsigned());
|
|
||||||
RHS.setIsUnsigned(Res.isUnsigned());
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: All of these should detect and report overflow??
|
|
||||||
bool Overflow = false;
|
|
||||||
switch (Operator) {
|
|
||||||
default: assert(0 && "Unknown operator token!");
|
|
||||||
case tok::percent:
|
|
||||||
if (RHS == 0) {
|
|
||||||
if (ValueLive) PP.Diag(OpToken, diag::err_pp_remainder_by_zero);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Res = LHS % RHS;
|
|
||||||
break;
|
|
||||||
case tok::slash:
|
|
||||||
if (RHS == 0) {
|
|
||||||
if (ValueLive) PP.Diag(OpToken, diag::err_pp_division_by_zero);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Res = LHS / RHS;
|
|
||||||
if (LHS.isSigned())
|
|
||||||
Overflow = LHS.isMinSignedValue() && RHS.isAllOnesValue(); // MININT/-1
|
|
||||||
break;
|
|
||||||
case tok::star:
|
|
||||||
Res = LHS * RHS;
|
|
||||||
if (LHS != 0 && RHS != 0)
|
|
||||||
Overflow = Res/RHS != LHS || Res/LHS != RHS;
|
|
||||||
break;
|
|
||||||
case tok::lessless: {
|
|
||||||
// Determine whether overflow is about to happen.
|
|
||||||
unsigned ShAmt = static_cast<unsigned>(RHS.getLimitedValue());
|
|
||||||
if (ShAmt >= LHS.getBitWidth())
|
|
||||||
Overflow = true, ShAmt = LHS.getBitWidth()-1;
|
|
||||||
else if (LHS.isUnsigned())
|
|
||||||
Overflow = ShAmt > LHS.countLeadingZeros();
|
|
||||||
else if (LHS.isPositive())
|
|
||||||
Overflow = ShAmt >= LHS.countLeadingZeros(); // Don't allow sign change.
|
|
||||||
else
|
|
||||||
Overflow = ShAmt >= LHS.countLeadingOnes();
|
|
||||||
|
|
||||||
Res = LHS << ShAmt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case tok::greatergreater: {
|
|
||||||
// Determine whether overflow is about to happen.
|
|
||||||
unsigned ShAmt = static_cast<unsigned>(RHS.getLimitedValue());
|
|
||||||
if (ShAmt >= LHS.getBitWidth())
|
|
||||||
Overflow = true, ShAmt = LHS.getBitWidth()-1;
|
|
||||||
Res = LHS >> ShAmt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case tok::plus:
|
|
||||||
Res = LHS + RHS;
|
|
||||||
if (LHS.isUnsigned())
|
|
||||||
Overflow = Res.ult(LHS);
|
|
||||||
else if (LHS.isPositive() == RHS.isPositive() &&
|
|
||||||
Res.isPositive() != LHS.isPositive())
|
|
||||||
Overflow = true; // Overflow for signed addition.
|
|
||||||
break;
|
|
||||||
case tok::minus:
|
|
||||||
Res = LHS - RHS;
|
|
||||||
if (LHS.isUnsigned())
|
|
||||||
Overflow = Res.ugt(LHS);
|
|
||||||
else if (LHS.isPositive() != RHS.isPositive() &&
|
|
||||||
Res.isPositive() != LHS.isPositive())
|
|
||||||
Overflow = true; // Overflow for signed subtraction.
|
|
||||||
break;
|
|
||||||
case tok::lessequal:
|
|
||||||
Res = LHS <= RHS;
|
|
||||||
Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed)
|
|
||||||
break;
|
|
||||||
case tok::less:
|
|
||||||
Res = LHS < RHS;
|
|
||||||
Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed)
|
|
||||||
break;
|
|
||||||
case tok::greaterequal:
|
|
||||||
Res = LHS >= RHS;
|
|
||||||
Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed)
|
|
||||||
break;
|
|
||||||
case tok::greater:
|
|
||||||
Res = LHS > RHS;
|
|
||||||
Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed)
|
|
||||||
break;
|
|
||||||
case tok::exclaimequal:
|
|
||||||
Res = LHS != RHS;
|
|
||||||
Res.setIsUnsigned(false); // C99 6.5.9p3, result is always int (signed)
|
|
||||||
break;
|
|
||||||
case tok::equalequal:
|
|
||||||
Res = LHS == RHS;
|
|
||||||
Res.setIsUnsigned(false); // C99 6.5.9p3, result is always int (signed)
|
|
||||||
break;
|
|
||||||
case tok::amp:
|
|
||||||
Res = LHS & RHS;
|
|
||||||
break;
|
|
||||||
case tok::caret:
|
|
||||||
Res = LHS ^ RHS;
|
|
||||||
break;
|
|
||||||
case tok::pipe:
|
|
||||||
Res = LHS | RHS;
|
|
||||||
break;
|
|
||||||
case tok::ampamp:
|
|
||||||
Res = (LHS != 0 && RHS != 0);
|
|
||||||
Res.setIsUnsigned(false); // C99 6.5.13p3, result is always int (signed)
|
|
||||||
break;
|
|
||||||
case tok::pipepipe:
|
|
||||||
Res = (LHS != 0 || RHS != 0);
|
|
||||||
Res.setIsUnsigned(false); // C99 6.5.14p3, result is always int (signed)
|
|
||||||
break;
|
|
||||||
case tok::comma:
|
|
||||||
PP.Diag(OpToken, diag::ext_pp_comma_expr);
|
|
||||||
Res = RHS; // LHS = LHS,RHS -> RHS.
|
|
||||||
break;
|
|
||||||
case tok::question: {
|
|
||||||
// Parse the : part of the expression.
|
|
||||||
if (PeekTok.getKind() != tok::colon) {
|
|
||||||
PP.Diag(OpToken, diag::err_pp_question_without_colon);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Consume the :.
|
|
||||||
PP.LexNonComment(PeekTok);
|
|
||||||
|
|
||||||
// Evaluate the value after the :.
|
|
||||||
bool AfterColonLive = ValueLive && LHS == 0;
|
|
||||||
llvm::APSInt AfterColonVal(LHS.getBitWidth());
|
|
||||||
DefinedTracker DT;
|
|
||||||
if (EvaluateValue(AfterColonVal, PeekTok, DT, AfterColonLive, PP))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Parse anything after the : RHS that has a higher precedence than ?.
|
|
||||||
if (EvaluateDirectiveSubExpr(AfterColonVal, ThisPrec+1,
|
|
||||||
PeekTok, AfterColonLive, PP))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Now that we have the condition, the LHS and the RHS of the :, evaluate.
|
|
||||||
Res = LHS != 0 ? RHS : AfterColonVal;
|
|
||||||
|
|
||||||
// Usual arithmetic conversions (C99 6.3.1.8p1): result is unsigned if
|
|
||||||
// either operand is unsigned.
|
|
||||||
Res.setIsUnsigned(RHS.isUnsigned() | AfterColonVal.isUnsigned());
|
|
||||||
|
|
||||||
// Figure out the precedence of the token after the : part.
|
|
||||||
PeekPrec = getPrecedence(PeekTok.getKind());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case tok::colon:
|
|
||||||
// Don't allow :'s to float around without being part of ?: exprs.
|
|
||||||
PP.Diag(OpToken, diag::err_pp_colon_without_question);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this operator is live and overflowed, report the issue.
|
|
||||||
if (Overflow && ValueLive)
|
|
||||||
PP.Diag(OpToken, diag::warn_pp_expr_overflow);
|
|
||||||
|
|
||||||
// Put the result back into 'LHS' for our next iteration.
|
|
||||||
LHS = Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EvaluateDirectiveExpression - Evaluate an integer constant expression that
|
|
||||||
/// may occur after a #if or #elif directive. If the expression is equivalent
|
|
||||||
/// to "!defined(X)" return X in IfNDefMacro.
|
|
||||||
bool Preprocessor::
|
|
||||||
EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
|
|
||||||
// Peek ahead one token.
|
|
||||||
Token Tok;
|
|
||||||
Lex(Tok);
|
|
||||||
|
|
||||||
// C99 6.10.1p3 - All expressions are evaluated as intmax_t or uintmax_t.
|
|
||||||
unsigned BitWidth = getTargetInfo().getIntMaxTWidth(Tok.getLocation());
|
|
||||||
llvm::APSInt ResVal(BitWidth);
|
|
||||||
DefinedTracker DT;
|
|
||||||
if (EvaluateValue(ResVal, Tok, DT, true, *this)) {
|
|
||||||
// Parse error, skip the rest of the macro line.
|
|
||||||
if (Tok.getKind() != tok::eom)
|
|
||||||
DiscardUntilEndOfDirective();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are at the end of the expression after just parsing a value, there
|
|
||||||
// must be no (unparenthesized) binary operators involved, so we can exit
|
|
||||||
// directly.
|
|
||||||
if (Tok.getKind() == tok::eom) {
|
|
||||||
// If the expression we parsed was of the form !defined(macro), return the
|
|
||||||
// macro in IfNDefMacro.
|
|
||||||
if (DT.State == DefinedTracker::NotDefinedMacro)
|
|
||||||
IfNDefMacro = DT.TheMacro;
|
|
||||||
|
|
||||||
return ResVal != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, we must have a binary operator (e.g. "#if 1 < 2"), so parse the
|
|
||||||
// operator and the stuff after it.
|
|
||||||
if (EvaluateDirectiveSubExpr(ResVal, 1, Tok, true, *this)) {
|
|
||||||
// Parse error, skip the rest of the macro line.
|
|
||||||
if (Tok.getKind() != tok::eom)
|
|
||||||
DiscardUntilEndOfDirective();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we aren't at the tok::eom token, something bad happened, like an extra
|
|
||||||
// ')' token.
|
|
||||||
if (Tok.getKind() != tok::eom) {
|
|
||||||
Diag(Tok, diag::err_pp_expected_eol);
|
|
||||||
DiscardUntilEndOfDirective();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResVal != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,367 +0,0 @@
|
|||||||
//===--- Pragma.cpp - Pragma registration and handling --------------------===//
|
|
||||||
//
|
|
||||||
// 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 PragmaHandler/PragmaTable interfaces and implements
|
|
||||||
// pragma related methods of the Preprocessor class.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Lex/Pragma.h"
|
|
||||||
#include "clang/Lex/PPCallbacks.h"
|
|
||||||
#include "clang/Lex/HeaderSearch.h"
|
|
||||||
#include "clang/Lex/Preprocessor.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "clang/Basic/FileManager.h"
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
#include "llvm/ADT/SmallVector.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
// Out-of-line destructor to provide a home for the class.
|
|
||||||
PragmaHandler::~PragmaHandler() {
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// PragmaNamespace Implementation.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
|
|
||||||
PragmaNamespace::~PragmaNamespace() {
|
|
||||||
for (unsigned i = 0, e = Handlers.size(); i != e; ++i)
|
|
||||||
delete Handlers[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// FindHandler - Check to see if there is already a handler for the
|
|
||||||
/// specified name. If not, return the handler for the null identifier if it
|
|
||||||
/// exists, otherwise return null. If IgnoreNull is true (the default) then
|
|
||||||
/// the null handler isn't returned on failure to match.
|
|
||||||
PragmaHandler *PragmaNamespace::FindHandler(const IdentifierInfo *Name,
|
|
||||||
bool IgnoreNull) const {
|
|
||||||
PragmaHandler *NullHandler = 0;
|
|
||||||
for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
|
|
||||||
if (Handlers[i]->getName() == Name)
|
|
||||||
return Handlers[i];
|
|
||||||
|
|
||||||
if (Handlers[i]->getName() == 0)
|
|
||||||
NullHandler = Handlers[i];
|
|
||||||
}
|
|
||||||
return IgnoreNull ? 0 : NullHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PragmaNamespace::HandlePragma(Preprocessor &PP, Token &Tok) {
|
|
||||||
// Read the 'namespace' that the directive is in, e.g. STDC. Do not macro
|
|
||||||
// expand it, the user can have a STDC #define, that should not affect this.
|
|
||||||
PP.LexUnexpandedToken(Tok);
|
|
||||||
|
|
||||||
// Get the handler for this token. If there is no handler, ignore the pragma.
|
|
||||||
PragmaHandler *Handler = FindHandler(Tok.getIdentifierInfo(), false);
|
|
||||||
if (Handler == 0) return;
|
|
||||||
|
|
||||||
// Otherwise, pass it down.
|
|
||||||
Handler->HandlePragma(PP, Tok);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Preprocessor Pragma Directive Handling.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// HandlePragmaDirective - The "#pragma" directive has been parsed. Lex the
|
|
||||||
/// rest of the pragma, passing it to the registered pragma handlers.
|
|
||||||
void Preprocessor::HandlePragmaDirective() {
|
|
||||||
++NumPragma;
|
|
||||||
|
|
||||||
// Invoke the first level of pragma handlers which reads the namespace id.
|
|
||||||
Token Tok;
|
|
||||||
PragmaHandlers->HandlePragma(*this, Tok);
|
|
||||||
|
|
||||||
// If the pragma handler didn't read the rest of the line, consume it now.
|
|
||||||
if (CurLexer->ParsingPreprocessorDirective)
|
|
||||||
DiscardUntilEndOfDirective();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then
|
|
||||||
/// return the first token after the directive. The _Pragma token has just
|
|
||||||
/// been read into 'Tok'.
|
|
||||||
void Preprocessor::Handle_Pragma(Token &Tok) {
|
|
||||||
// Remember the pragma token location.
|
|
||||||
SourceLocation PragmaLoc = Tok.getLocation();
|
|
||||||
|
|
||||||
// Read the '('.
|
|
||||||
Lex(Tok);
|
|
||||||
if (Tok.getKind() != tok::l_paren)
|
|
||||||
return Diag(PragmaLoc, diag::err__Pragma_malformed);
|
|
||||||
|
|
||||||
// Read the '"..."'.
|
|
||||||
Lex(Tok);
|
|
||||||
if (Tok.getKind() != tok::string_literal &&
|
|
||||||
Tok.getKind() != tok::wide_string_literal)
|
|
||||||
return Diag(PragmaLoc, diag::err__Pragma_malformed);
|
|
||||||
|
|
||||||
// Remember the string.
|
|
||||||
std::string StrVal = getSpelling(Tok);
|
|
||||||
SourceLocation StrLoc = Tok.getLocation();
|
|
||||||
|
|
||||||
// Read the ')'.
|
|
||||||
Lex(Tok);
|
|
||||||
if (Tok.getKind() != tok::r_paren)
|
|
||||||
return Diag(PragmaLoc, diag::err__Pragma_malformed);
|
|
||||||
|
|
||||||
// The _Pragma is lexically sound. Destringize according to C99 6.10.9.1.
|
|
||||||
if (StrVal[0] == 'L') // Remove L prefix.
|
|
||||||
StrVal.erase(StrVal.begin());
|
|
||||||
assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' &&
|
|
||||||
"Invalid string token!");
|
|
||||||
|
|
||||||
// Remove the front quote, replacing it with a space, so that the pragma
|
|
||||||
// contents appear to have a space before them.
|
|
||||||
StrVal[0] = ' ';
|
|
||||||
|
|
||||||
// Replace the terminating quote with a \n\0.
|
|
||||||
StrVal[StrVal.size()-1] = '\n';
|
|
||||||
StrVal += '\0';
|
|
||||||
|
|
||||||
// Remove escaped quotes and escapes.
|
|
||||||
for (unsigned i = 0, e = StrVal.size(); i != e-1; ++i) {
|
|
||||||
if (StrVal[i] == '\\' &&
|
|
||||||
(StrVal[i+1] == '\\' || StrVal[i+1] == '"')) {
|
|
||||||
// \\ -> '\' and \" -> '"'.
|
|
||||||
StrVal.erase(StrVal.begin()+i);
|
|
||||||
--e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plop the string (including the newline and trailing null) into a buffer
|
|
||||||
// where we can lex it.
|
|
||||||
SourceLocation TokLoc = CreateString(&StrVal[0], StrVal.size(), StrLoc);
|
|
||||||
const char *StrData = SourceMgr.getCharacterData(TokLoc);
|
|
||||||
|
|
||||||
// Make and enter a lexer object so that we lex and expand the tokens just
|
|
||||||
// like any others.
|
|
||||||
Lexer *TL = new Lexer(TokLoc, *this,
|
|
||||||
StrData, StrData+StrVal.size()-1 /* no null */);
|
|
||||||
|
|
||||||
// Ensure that the lexer thinks it is inside a directive, so that end \n will
|
|
||||||
// return an EOM token.
|
|
||||||
TL->ParsingPreprocessorDirective = true;
|
|
||||||
|
|
||||||
// This lexer really is for _Pragma.
|
|
||||||
TL->Is_PragmaLexer = true;
|
|
||||||
|
|
||||||
EnterSourceFileWithLexer(TL, 0);
|
|
||||||
|
|
||||||
// With everything set up, lex this as a #pragma directive.
|
|
||||||
HandlePragmaDirective();
|
|
||||||
|
|
||||||
// Finally, return whatever came after the pragma directive.
|
|
||||||
return Lex(Tok);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// HandlePragmaOnce - Handle #pragma once. OnceTok is the 'once'.
|
|
||||||
///
|
|
||||||
void Preprocessor::HandlePragmaOnce(Token &OnceTok) {
|
|
||||||
if (isInPrimaryFile()) {
|
|
||||||
Diag(OnceTok, diag::pp_pragma_once_in_main_file);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current file lexer we're looking at. Ignore _Pragma 'files' etc.
|
|
||||||
SourceLocation FileLoc = getCurrentFileLexer()->getFileLoc();
|
|
||||||
|
|
||||||
// Mark the file as a once-only file now.
|
|
||||||
HeaderInfo.MarkFileIncludeOnce(SourceMgr.getFileEntryForLoc(FileLoc));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// HandlePragmaPoison - Handle #pragma GCC poison. PoisonTok is the 'poison'.
|
|
||||||
///
|
|
||||||
void Preprocessor::HandlePragmaPoison(Token &PoisonTok) {
|
|
||||||
Token Tok;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
// Read the next token to poison. While doing this, pretend that we are
|
|
||||||
// skipping while reading the identifier to poison.
|
|
||||||
// This avoids errors on code like:
|
|
||||||
// #pragma GCC poison X
|
|
||||||
// #pragma GCC poison X
|
|
||||||
if (CurLexer) CurLexer->LexingRawMode = true;
|
|
||||||
LexUnexpandedToken(Tok);
|
|
||||||
if (CurLexer) CurLexer->LexingRawMode = false;
|
|
||||||
|
|
||||||
// If we reached the end of line, we're done.
|
|
||||||
if (Tok.getKind() == tok::eom) return;
|
|
||||||
|
|
||||||
// Can only poison identifiers.
|
|
||||||
if (Tok.getKind() != tok::identifier) {
|
|
||||||
Diag(Tok, diag::err_pp_invalid_poison);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look up the identifier info for the token. We disabled identifier lookup
|
|
||||||
// by saying we're skipping contents, so we need to do this manually.
|
|
||||||
IdentifierInfo *II = LookUpIdentifierInfo(Tok);
|
|
||||||
|
|
||||||
// Already poisoned.
|
|
||||||
if (II->isPoisoned()) continue;
|
|
||||||
|
|
||||||
// If this is a macro identifier, emit a warning.
|
|
||||||
if (II->getMacroInfo())
|
|
||||||
Diag(Tok, diag::pp_poisoning_existing_macro);
|
|
||||||
|
|
||||||
// Finally, poison it!
|
|
||||||
II->setIsPoisoned();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// HandlePragmaSystemHeader - Implement #pragma GCC system_header. We know
|
|
||||||
/// that the whole directive has been parsed.
|
|
||||||
void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
|
|
||||||
if (isInPrimaryFile()) {
|
|
||||||
Diag(SysHeaderTok, diag::pp_pragma_sysheader_in_main_file);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current file lexer we're looking at. Ignore _Pragma 'files' etc.
|
|
||||||
Lexer *TheLexer = getCurrentFileLexer();
|
|
||||||
|
|
||||||
// Mark the file as a system header.
|
|
||||||
const FileEntry *File = SourceMgr.getFileEntryForLoc(TheLexer->getFileLoc());
|
|
||||||
HeaderInfo.MarkFileSystemHeader(File);
|
|
||||||
|
|
||||||
// Notify the client, if desired, that we are in a new source file.
|
|
||||||
if (Callbacks)
|
|
||||||
Callbacks->FileChanged(TheLexer->getSourceLocation(TheLexer->BufferPtr),
|
|
||||||
PPCallbacks::SystemHeaderPragma,
|
|
||||||
DirectoryLookup::SystemHeaderDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// HandlePragmaDependency - Handle #pragma GCC dependency "foo" blah.
|
|
||||||
///
|
|
||||||
void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
|
|
||||||
Token FilenameTok;
|
|
||||||
CurLexer->LexIncludeFilename(FilenameTok);
|
|
||||||
|
|
||||||
// If the token kind is EOM, the error has already been diagnosed.
|
|
||||||
if (FilenameTok.getKind() == tok::eom)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Reserve a buffer to get the spelling.
|
|
||||||
llvm::SmallVector<char, 128> FilenameBuffer;
|
|
||||||
FilenameBuffer.resize(FilenameTok.getLength());
|
|
||||||
|
|
||||||
const char *FilenameStart = &FilenameBuffer[0];
|
|
||||||
unsigned Len = getSpelling(FilenameTok, FilenameStart);
|
|
||||||
const char *FilenameEnd = FilenameStart+Len;
|
|
||||||
bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(),
|
|
||||||
FilenameStart, FilenameEnd);
|
|
||||||
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
|
|
||||||
// error.
|
|
||||||
if (FilenameStart == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Search include directories for this file.
|
|
||||||
const DirectoryLookup *CurDir;
|
|
||||||
const FileEntry *File = LookupFile(FilenameStart, FilenameEnd,
|
|
||||||
isAngled, 0, CurDir);
|
|
||||||
if (File == 0)
|
|
||||||
return Diag(FilenameTok, diag::err_pp_file_not_found,
|
|
||||||
std::string(FilenameStart, FilenameEnd));
|
|
||||||
|
|
||||||
SourceLocation FileLoc = getCurrentFileLexer()->getFileLoc();
|
|
||||||
const FileEntry *CurFile = SourceMgr.getFileEntryForLoc(FileLoc);
|
|
||||||
|
|
||||||
// If this file is older than the file it depends on, emit a diagnostic.
|
|
||||||
if (CurFile && CurFile->getModificationTime() < File->getModificationTime()) {
|
|
||||||
// Lex tokens at the end of the message and include them in the message.
|
|
||||||
std::string Message;
|
|
||||||
Lex(DependencyTok);
|
|
||||||
while (DependencyTok.getKind() != tok::eom) {
|
|
||||||
Message += getSpelling(DependencyTok) + " ";
|
|
||||||
Lex(DependencyTok);
|
|
||||||
}
|
|
||||||
|
|
||||||
Message.erase(Message.end()-1);
|
|
||||||
Diag(FilenameTok, diag::pp_out_of_date_dependency, Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
|
|
||||||
/// If 'Namespace' is non-null, then it is a token required to exist on the
|
|
||||||
/// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
|
|
||||||
void Preprocessor::AddPragmaHandler(const char *Namespace,
|
|
||||||
PragmaHandler *Handler) {
|
|
||||||
PragmaNamespace *InsertNS = PragmaHandlers;
|
|
||||||
|
|
||||||
// If this is specified to be in a namespace, step down into it.
|
|
||||||
if (Namespace) {
|
|
||||||
IdentifierInfo *NSID = getIdentifierInfo(Namespace);
|
|
||||||
|
|
||||||
// If there is already a pragma handler with the name of this namespace,
|
|
||||||
// we either have an error (directive with the same name as a namespace) or
|
|
||||||
// we already have the namespace to insert into.
|
|
||||||
if (PragmaHandler *Existing = PragmaHandlers->FindHandler(NSID)) {
|
|
||||||
InsertNS = Existing->getIfNamespace();
|
|
||||||
assert(InsertNS != 0 && "Cannot have a pragma namespace and pragma"
|
|
||||||
" handler with the same name!");
|
|
||||||
} else {
|
|
||||||
// Otherwise, this namespace doesn't exist yet, create and insert the
|
|
||||||
// handler for it.
|
|
||||||
InsertNS = new PragmaNamespace(NSID);
|
|
||||||
PragmaHandlers->AddPragma(InsertNS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check to make sure we don't already have a pragma for this identifier.
|
|
||||||
assert(!InsertNS->FindHandler(Handler->getName()) &&
|
|
||||||
"Pragma handler already exists for this identifier!");
|
|
||||||
InsertNS->AddPragma(Handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
struct PragmaOnceHandler : public PragmaHandler {
|
|
||||||
PragmaOnceHandler(const IdentifierInfo *OnceID) : PragmaHandler(OnceID) {}
|
|
||||||
virtual void HandlePragma(Preprocessor &PP, Token &OnceTok) {
|
|
||||||
PP.CheckEndOfDirective("#pragma once");
|
|
||||||
PP.HandlePragmaOnce(OnceTok);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PragmaPoisonHandler : public PragmaHandler {
|
|
||||||
PragmaPoisonHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
|
|
||||||
virtual void HandlePragma(Preprocessor &PP, Token &PoisonTok) {
|
|
||||||
PP.HandlePragmaPoison(PoisonTok);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PragmaSystemHeaderHandler : public PragmaHandler {
|
|
||||||
PragmaSystemHeaderHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
|
|
||||||
virtual void HandlePragma(Preprocessor &PP, Token &SHToken) {
|
|
||||||
PP.HandlePragmaSystemHeader(SHToken);
|
|
||||||
PP.CheckEndOfDirective("#pragma");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
struct PragmaDependencyHandler : public PragmaHandler {
|
|
||||||
PragmaDependencyHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
|
|
||||||
virtual void HandlePragma(Preprocessor &PP, Token &DepToken) {
|
|
||||||
PP.HandlePragmaDependency(DepToken);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
|
|
||||||
/// RegisterBuiltinPragmas - Install the standard preprocessor pragmas:
|
|
||||||
/// #pragma GCC poison/system_header/dependency and #pragma once.
|
|
||||||
void Preprocessor::RegisterBuiltinPragmas() {
|
|
||||||
AddPragmaHandler(0, new PragmaOnceHandler(getIdentifierInfo("once")));
|
|
||||||
AddPragmaHandler("GCC", new PragmaPoisonHandler(getIdentifierInfo("poison")));
|
|
||||||
AddPragmaHandler("GCC", new PragmaSystemHeaderHandler(
|
|
||||||
getIdentifierInfo("system_header")));
|
|
||||||
AddPragmaHandler("GCC", new PragmaDependencyHandler(
|
|
||||||
getIdentifierInfo("dependency")));
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,71 +0,0 @@
|
|||||||
//===--- ScratchBuffer.cpp - Scratch space for forming tokens -------------===//
|
|
||||||
//
|
|
||||||
// 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 ScratchBuffer interface.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Lex/ScratchBuffer.h"
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
// ScratchBufSize - The size of each chunk of scratch memory. Slightly less
|
|
||||||
//than a page, almost certainly enough for anything. :)
|
|
||||||
static const unsigned ScratchBufSize = 4060;
|
|
||||||
|
|
||||||
ScratchBuffer::ScratchBuffer(SourceManager &SM) : SourceMgr(SM), CurBuffer(0) {
|
|
||||||
// Set BytesUsed so that the first call to getToken will require an alloc.
|
|
||||||
BytesUsed = ScratchBufSize;
|
|
||||||
FileID = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getToken - Splat the specified text into a temporary MemoryBuffer and
|
|
||||||
/// return a SourceLocation that refers to the token. This is just like the
|
|
||||||
/// method below, but returns a location that indicates the physloc of the
|
|
||||||
/// token.
|
|
||||||
SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len) {
|
|
||||||
if (BytesUsed+Len > ScratchBufSize)
|
|
||||||
AllocScratchBuffer(Len);
|
|
||||||
|
|
||||||
// Copy the token data into the buffer.
|
|
||||||
memcpy(CurBuffer+BytesUsed, Buf, Len);
|
|
||||||
|
|
||||||
// Remember that we used these bytes.
|
|
||||||
BytesUsed += Len;
|
|
||||||
|
|
||||||
assert(BytesUsed-Len < (1 << SourceLocation::FilePosBits) &&
|
|
||||||
"Out of range file position!");
|
|
||||||
|
|
||||||
return SourceLocation::getFileLoc(FileID, BytesUsed-Len);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// getToken - Splat the specified text into a temporary MemoryBuffer and
|
|
||||||
/// return a SourceLocation that refers to the token. The SourceLoc value
|
|
||||||
/// gives a virtual location that the token will appear to be from.
|
|
||||||
SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len,
|
|
||||||
SourceLocation SourceLoc) {
|
|
||||||
// Map the physloc to the specified sourceloc.
|
|
||||||
return SourceMgr.getInstantiationLoc(getToken(Buf, Len), SourceLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScratchBuffer::AllocScratchBuffer(unsigned RequestLen) {
|
|
||||||
// Only pay attention to the requested length if it is larger than our default
|
|
||||||
// page size. If it is, we allocate an entire chunk for it. This is to
|
|
||||||
// support gigantic tokens, which almost certainly won't happen. :)
|
|
||||||
if (RequestLen < ScratchBufSize)
|
|
||||||
RequestLen = ScratchBufSize;
|
|
||||||
|
|
||||||
llvm::MemoryBuffer *Buf =
|
|
||||||
llvm::MemoryBuffer::getNewMemBuffer(RequestLen, "<scratch space>");
|
|
||||||
FileID = SourceMgr.createFileIDForMemBuffer(Buf);
|
|
||||||
CurBuffer = const_cast<char*>(Buf->getBufferStart());
|
|
||||||
BytesUsed = 0;
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
LEVEL = ../..
|
|
||||||
DIRS := Basic Lex Parse AST Sema CodeGen Analysis Driver
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.common
|
|
||||||
|
|
||||||
test::
|
|
||||||
cd test; $(MAKE)
|
|
||||||
|
|
||||||
clean::
|
|
||||||
@rm -rf build
|
|
||||||
@rm -rf `find test -name Output`
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# This file provides information for llvm-top
|
|
||||||
DepModule: llvm
|
|
||||||
ConfigCmd:
|
|
||||||
ConfigTest:
|
|
||||||
BuildCmd:
|
|
||||||
219
clang/NOTES.txt
219
clang/NOTES.txt
@@ -1,219 +0,0 @@
|
|||||||
//===---------------------------------------------------------------------===//
|
|
||||||
// Random Notes
|
|
||||||
//===---------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
C90/C99/C++ Comparisons:
|
|
||||||
http://david.tribble.com/text/cdiffs.htm
|
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
|
||||||
Extensions:
|
|
||||||
|
|
||||||
* "#define_target X Y"
|
|
||||||
This preprocessor directive works exactly the same was as #define, but it
|
|
||||||
notes that 'X' is a target-specific preprocessor directive. When used, a
|
|
||||||
diagnostic is emitted indicating that the translation unit is non-portable.
|
|
||||||
|
|
||||||
If a target-define is #undef'd before use, no diagnostic is emitted. If 'X'
|
|
||||||
were previously a normal #define macro, the macro is tainted. If 'X' is
|
|
||||||
subsequently #defined as a non-target-specific define, the taint bit is
|
|
||||||
cleared.
|
|
||||||
|
|
||||||
* "#define_other_target X"
|
|
||||||
The preprocessor directive takes a single identifier argument. It notes
|
|
||||||
that this identifier is a target-specific #define for some target other than
|
|
||||||
the current one. Use of this identifier will result in a diagnostic.
|
|
||||||
|
|
||||||
If 'X' is later #undef'd or #define'd, the taint bit is cleared. If 'X' is
|
|
||||||
already defined, X is marked as a target-specific define.
|
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
To time GCC preprocessing speed without output, use:
|
|
||||||
"time gcc -MM file"
|
|
||||||
This is similar to -Eonly.
|
|
||||||
|
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
C++ Template Instantiation benchmark:
|
|
||||||
http://users.rcn.com/abrahams/instantiation_speed/index.html
|
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
TODO: File Manager Speedup:
|
|
||||||
|
|
||||||
We currently do a lot of stat'ing for files that don't exist, particularly
|
|
||||||
when lots of -I paths exist (e.g. see the <iostream> example, check for
|
|
||||||
failures in stat in FileManager::getFile). It would be far better to make
|
|
||||||
the following changes:
|
|
||||||
1. FileEntry contains a sys::Path instead of a std::string for Name.
|
|
||||||
2. sys::Path contains timestamp and size, lazily computed. Eliminate from
|
|
||||||
FileEntry.
|
|
||||||
3. File UIDs are created on request, not when files are opened.
|
|
||||||
These changes make it possible to efficiently have FileEntry objects for
|
|
||||||
files that exist on the file system, but have not been used yet.
|
|
||||||
|
|
||||||
Once this is done:
|
|
||||||
1. DirectoryEntry gets a boolean value "has read entries". When false, not
|
|
||||||
all entries in the directory are in the file mgr, when true, they are.
|
|
||||||
2. Instead of stat'ing the file in FileManager::getFile, check to see if
|
|
||||||
the dir has been read. If so, fail immediately, if not, read the dir,
|
|
||||||
then retry.
|
|
||||||
3. Reading the dir uses the getdirentries syscall, creating an FileEntry
|
|
||||||
for all files found.
|
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
TODO: Fast #Import:
|
|
||||||
|
|
||||||
* Get frameworks that don't use #import to do so, e.g.
|
|
||||||
DirectoryService, AudioToolbox, CoreFoundation, etc. Why not using #import?
|
|
||||||
Because they work in C mode? C has #import.
|
|
||||||
* Have the lexer return a token for #import instead of handling it itself.
|
|
||||||
- Create a new preprocessor object with no external state (no -D/U options
|
|
||||||
from the command line, etc). Alternatively, keep track of exactly which
|
|
||||||
external state is used by a #import: declare it somehow.
|
|
||||||
* When having reading a #import file, keep track of whether we have (and/or
|
|
||||||
which) seen any "configuration" macros. Various cases:
|
|
||||||
- Uses of target args (__POWERPC__, __i386): Header has to be parsed
|
|
||||||
multiple times, per-target. What about #ifndef checks? How do we know?
|
|
||||||
- "Configuration" preprocessor macros not defined: POWERPC, etc. What about
|
|
||||||
things like __STDC__ etc? What is and what isn't allowed.
|
|
||||||
* Special handling for "umbrella" headers, which just contain #import stmts:
|
|
||||||
- Cocoa.h/AppKit.h - Contain pointers to digests instead of entire digests
|
|
||||||
themselves? Foundation.h isn't pure umbrella!
|
|
||||||
* Frameworks digests:
|
|
||||||
- Can put "digest" of a framework-worth of headers into the framework
|
|
||||||
itself. To open AppKit, just mmap
|
|
||||||
/System/Library/Frameworks/AppKit.framework/"digest", which provides a
|
|
||||||
symbol table in a well defined format. Lazily unstream stuff that is
|
|
||||||
needed. Contains declarations, macros, and debug information.
|
|
||||||
- System frameworks ship with digests. How do we handle configuration
|
|
||||||
information? How do we handle stuff like:
|
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2
|
|
||||||
which guards a bunch of decls? Should there be a couple of default
|
|
||||||
configs, then have the UI fall back to building/caching its own?
|
|
||||||
- GUI automatically builds digests when UI is idle, both of system
|
|
||||||
frameworks if they aren't not available in the right config, and of app
|
|
||||||
frameworks.
|
|
||||||
- GUI builds dependence graph of frameworks/digests based on #imports. If a
|
|
||||||
digest is out date, dependent digests are automatically invalidated.
|
|
||||||
|
|
||||||
* New constraints on #import for objc-v3:
|
|
||||||
- #imported file must not define non-inline function bodies.
|
|
||||||
- Alternatively, they can, and these bodies get compiled/linked *once*
|
|
||||||
per app into a dylib. What about building user dylibs?
|
|
||||||
- Restrictions on ObjC grammar: can't #import the body of a for stmt or fn.
|
|
||||||
- Compiler must detect and reject these cases.
|
|
||||||
- #defines defined within a #import have two behaviors:
|
|
||||||
- By default, they escape the header. These macros *cannot* be #undef'd
|
|
||||||
by other code: this is enforced by the front-end.
|
|
||||||
- Optionally, user can specify what macros escape (whitelist) or can use
|
|
||||||
#undef.
|
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
TODO: New language feature: Configuration queries:
|
|
||||||
- Instead of #ifdef __POWERPC__, use "if (strcmp(`cpu`, __POWERPC__))", or
|
|
||||||
some other, better, syntax.
|
|
||||||
- Use it to increase the number of "architecture-clean" #import'd files,
|
|
||||||
allowing a single index to be used for all fat slices.
|
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
The 'portability' model in clang is sufficient to catch translation units (or
|
|
||||||
their parts) that are not portable, but it doesn't help if the system headers
|
|
||||||
are non-portable and not fixed. An alternative model that would be easy to use
|
|
||||||
is a 'tainting' scheme. Consider:
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
OSHostByteOrder(void) {
|
|
||||||
#if defined(__LITTLE_ENDIAN__)
|
|
||||||
return OSLittleEndian;
|
|
||||||
#elif defined(__BIG_ENDIAN__)
|
|
||||||
return OSBigEndian;
|
|
||||||
#else
|
|
||||||
return OSUnknownByteOrder;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
It would be trivial to mark 'OSHostByteOrder' as being non-portable (tainted)
|
|
||||||
instead of marking the entire translation unit. Then, if OSHostByteOrder is
|
|
||||||
never called/used by the current translation unit, the t-u wouldn't be marked
|
|
||||||
non-portable. However, there is no good way to handle stuff like:
|
|
||||||
|
|
||||||
extern int X, Y;
|
|
||||||
|
|
||||||
#ifndef __POWERPC__
|
|
||||||
#define X Y
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int bar() { return X; }
|
|
||||||
|
|
||||||
When compiling for powerpc, the #define is skipped, so it doesn't know that bar
|
|
||||||
uses a #define that is set on some other target. In practice, limited cases
|
|
||||||
could be handled by scanning the skipped region of a #if, but the fully general
|
|
||||||
case cannot be implemented efficiently. In this case, for example, the #define
|
|
||||||
in the protected region could be turned into either a #define_target or
|
|
||||||
#define_other_target as appropriate. The harder case is code like this (from
|
|
||||||
OSByteOrder.h):
|
|
||||||
|
|
||||||
#if (defined(__ppc__) || defined(__ppc64__))
|
|
||||||
#include <libkern/ppc/OSByteOrder.h>
|
|
||||||
#elif (defined(__i386__) || defined(__x86_64__))
|
|
||||||
#include <libkern/i386/OSByteOrder.h>
|
|
||||||
#else
|
|
||||||
#include <libkern/machine/OSByteOrder.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
The realistic way to fix this is by having an initial #ifdef __llvm__ that
|
|
||||||
defines its contents in terms of the llvm bswap intrinsics. Other things should
|
|
||||||
be handled on a case-by-case basis.
|
|
||||||
|
|
||||||
|
|
||||||
We probably have to do something smarter like this in the future. The C++ header
|
|
||||||
<limits> contains a lot of code like this:
|
|
||||||
|
|
||||||
static const int digits10 = __LDBL_DIG__;
|
|
||||||
static const int min_exponent = __LDBL_MIN_EXP__;
|
|
||||||
static const int min_exponent10 = __LDBL_MIN_10_EXP__;
|
|
||||||
static const float_denorm_style has_denorm
|
|
||||||
= bool(__LDBL_DENORM_MIN__) ? denorm_present : denorm_absent;
|
|
||||||
|
|
||||||
... since this isn't being used in an #ifdef, it should be easy enough to taint
|
|
||||||
the decl for these ivars.
|
|
||||||
|
|
||||||
|
|
||||||
/usr/include/sys/cdefs.h contains stuff like this:
|
|
||||||
|
|
||||||
#if defined(__ppc__)
|
|
||||||
# if defined(__LDBL_MANT_DIG__) && defined(__DBL_MANT_DIG__) && \
|
|
||||||
__LDBL_MANT_DIG__ > __DBL_MANT_DIG__
|
|
||||||
# if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0 < 1040
|
|
||||||
# define __DARWIN_LDBL_COMPAT(x) __asm("_" __STRING(x) "$LDBLStub")
|
|
||||||
# else
|
|
||||||
# define __DARWIN_LDBL_COMPAT(x) __asm("_" __STRING(x) "$LDBL128")
|
|
||||||
# endif
|
|
||||||
# define __DARWIN_LDBL_COMPAT2(x) __asm("_" __STRING(x) "$LDBL128")
|
|
||||||
# define __DARWIN_LONG_DOUBLE_IS_DOUBLE 0
|
|
||||||
# else
|
|
||||||
# define __DARWIN_LDBL_COMPAT(x) /* nothing */
|
|
||||||
# define __DARWIN_LDBL_COMPAT2(x) /* nothing */
|
|
||||||
# define __DARWIN_LONG_DOUBLE_IS_DOUBLE 1
|
|
||||||
# endif
|
|
||||||
#elif defined(__i386__) || defined(__ppc64__) || defined(__x86_64__)
|
|
||||||
# define __DARWIN_LDBL_COMPAT(x) /* nothing */
|
|
||||||
# define __DARWIN_LDBL_COMPAT2(x) /* nothing */
|
|
||||||
# define __DARWIN_LONG_DOUBLE_IS_DOUBLE 0
|
|
||||||
#else
|
|
||||||
# error Unknown architecture
|
|
||||||
#endif
|
|
||||||
|
|
||||||
An ideal way to solve this issue is to mark __DARWIN_LDBL_COMPAT /
|
|
||||||
__DARWIN_LDBL_COMPAT2 / __DARWIN_LONG_DOUBLE_IS_DOUBLE as being non-portable
|
|
||||||
because they depend on non-portable macros. In practice though, this may end
|
|
||||||
up being a serious problem: every use of printf will mark the translation unit
|
|
||||||
non-portable if targetting ppc32 and something else.
|
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
//===--- AttributeList.cpp --------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Steve Naroff and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file defines the AttributeList class implementation
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Parse/AttributeList.h"
|
|
||||||
#include "clang/Lex/IdentifierTable.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc,
|
|
||||||
IdentifierInfo *pName, SourceLocation pLoc,
|
|
||||||
Action::ExprTy **elist, unsigned numargs,
|
|
||||||
AttributeList *n)
|
|
||||||
: AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc),
|
|
||||||
NumArgs(numargs), Next(n) {
|
|
||||||
Args = new Action::ExprTy*[numargs];
|
|
||||||
for (unsigned i = 0; i != numargs; ++i)
|
|
||||||
Args[i] = elist[i];
|
|
||||||
}
|
|
||||||
@@ -1,286 +0,0 @@
|
|||||||
//===--- SemaDeclSpec.cpp - Declaration Specifier Semantic Analysis -------===//
|
|
||||||
//
|
|
||||||
// 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 semantic analysis for declaration specifiers.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Parse/DeclSpec.h"
|
|
||||||
#include "clang/Basic/LangOptions.h"
|
|
||||||
#include "clang/Basic/SourceLocation.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
|
|
||||||
///
|
|
||||||
unsigned DeclSpec::getParsedSpecifiers() const {
|
|
||||||
unsigned Res = 0;
|
|
||||||
if (StorageClassSpec != SCS_unspecified ||
|
|
||||||
SCS_thread_specified)
|
|
||||||
Res |= PQ_StorageClassSpecifier;
|
|
||||||
|
|
||||||
if (TypeQualifiers != TQ_unspecified)
|
|
||||||
Res |= PQ_TypeQualifier;
|
|
||||||
|
|
||||||
if (hasTypeSpecifier())
|
|
||||||
Res |= PQ_TypeSpecifier;
|
|
||||||
|
|
||||||
if (FS_inline_specified)
|
|
||||||
Res |= PQ_FunctionSpecifier;
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) {
|
|
||||||
switch (S) {
|
|
||||||
default: assert(0 && "Unknown typespec!");
|
|
||||||
case DeclSpec::SCS_unspecified: return "unspecified";
|
|
||||||
case DeclSpec::SCS_typedef: return "typedef";
|
|
||||||
case DeclSpec::SCS_extern: return "extern";
|
|
||||||
case DeclSpec::SCS_static: return "static";
|
|
||||||
case DeclSpec::SCS_auto: return "auto";
|
|
||||||
case DeclSpec::SCS_register: return "register";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool BadSpecifier(DeclSpec::SCS S, const char *&PrevSpec) {
|
|
||||||
PrevSpec = DeclSpec::getSpecifierName(S);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool BadSpecifier(DeclSpec::TSW W, const char *&PrevSpec) {
|
|
||||||
switch (W) {
|
|
||||||
case DeclSpec::TSW_unspecified: PrevSpec = "unspecified"; break;
|
|
||||||
case DeclSpec::TSW_short: PrevSpec = "short"; break;
|
|
||||||
case DeclSpec::TSW_long: PrevSpec = "long"; break;
|
|
||||||
case DeclSpec::TSW_longlong: PrevSpec = "long long"; break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool BadSpecifier(DeclSpec::TSC C, const char *&PrevSpec) {
|
|
||||||
switch (C) {
|
|
||||||
case DeclSpec::TSC_unspecified: PrevSpec = "unspecified"; break;
|
|
||||||
case DeclSpec::TSC_imaginary: PrevSpec = "imaginary"; break;
|
|
||||||
case DeclSpec::TSC_complex: PrevSpec = "complex"; break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool BadSpecifier(DeclSpec::TSS S, const char *&PrevSpec) {
|
|
||||||
switch (S) {
|
|
||||||
case DeclSpec::TSS_unspecified: PrevSpec = "unspecified"; break;
|
|
||||||
case DeclSpec::TSS_signed: PrevSpec = "signed"; break;
|
|
||||||
case DeclSpec::TSS_unsigned: PrevSpec = "unsigned"; break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
|
|
||||||
switch (T) {
|
|
||||||
default: assert(0 && "Unknown typespec!");
|
|
||||||
case DeclSpec::TST_unspecified: return "unspecified";
|
|
||||||
case DeclSpec::TST_void: return "void";
|
|
||||||
case DeclSpec::TST_char: return "char";
|
|
||||||
case DeclSpec::TST_int: return "int";
|
|
||||||
case DeclSpec::TST_float: return "float";
|
|
||||||
case DeclSpec::TST_double: return "double";
|
|
||||||
case DeclSpec::TST_bool: return "_Bool";
|
|
||||||
case DeclSpec::TST_decimal32: return "_Decimal32";
|
|
||||||
case DeclSpec::TST_decimal64: return "_Decimal64";
|
|
||||||
case DeclSpec::TST_decimal128: return "_Decimal128";
|
|
||||||
case DeclSpec::TST_enum: return "enum";
|
|
||||||
case DeclSpec::TST_union: return "union";
|
|
||||||
case DeclSpec::TST_struct: return "struct";
|
|
||||||
case DeclSpec::TST_typedef: return "typedef";
|
|
||||||
case DeclSpec::TST_typeofType:
|
|
||||||
case DeclSpec::TST_typeofExpr: return "typeof";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool BadSpecifier(DeclSpec::TST T, const char *&PrevSpec) {
|
|
||||||
PrevSpec = DeclSpec::getSpecifierName(T);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool BadSpecifier(DeclSpec::TQ T, const char *&PrevSpec) {
|
|
||||||
switch (T) {
|
|
||||||
case DeclSpec::TQ_unspecified: PrevSpec = "unspecified"; break;
|
|
||||||
case DeclSpec::TQ_const: PrevSpec = "const"; break;
|
|
||||||
case DeclSpec::TQ_restrict: PrevSpec = "restrict"; break;
|
|
||||||
case DeclSpec::TQ_volatile: PrevSpec = "volatile"; break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
|
|
||||||
const char *&PrevSpec) {
|
|
||||||
if (StorageClassSpec != SCS_unspecified)
|
|
||||||
return BadSpecifier(StorageClassSpec, PrevSpec);
|
|
||||||
StorageClassSpec = S;
|
|
||||||
StorageClassSpecLoc = Loc;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc,
|
|
||||||
const char *&PrevSpec) {
|
|
||||||
if (SCS_thread_specified) {
|
|
||||||
PrevSpec = "__thread";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
SCS_thread_specified = true;
|
|
||||||
SCS_threadLoc = Loc;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// These methods set the specified attribute of the DeclSpec, but return true
|
|
||||||
/// and ignore the request if invalid (e.g. "extern" then "auto" is
|
|
||||||
/// specified).
|
|
||||||
bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc,
|
|
||||||
const char *&PrevSpec) {
|
|
||||||
if (TypeSpecWidth != TSW_unspecified &&
|
|
||||||
// Allow turning long -> long long.
|
|
||||||
(W != TSW_longlong || TypeSpecWidth != TSW_long))
|
|
||||||
return BadSpecifier(TypeSpecWidth, PrevSpec);
|
|
||||||
TypeSpecWidth = W;
|
|
||||||
TSWLoc = Loc;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc,
|
|
||||||
const char *&PrevSpec) {
|
|
||||||
if (TypeSpecComplex != TSC_unspecified)
|
|
||||||
return BadSpecifier(TypeSpecComplex, PrevSpec);
|
|
||||||
TypeSpecComplex = C;
|
|
||||||
TSCLoc = Loc;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc,
|
|
||||||
const char *&PrevSpec) {
|
|
||||||
if (TypeSpecSign != TSS_unspecified)
|
|
||||||
return BadSpecifier(TypeSpecSign, PrevSpec);
|
|
||||||
TypeSpecSign = S;
|
|
||||||
TSSLoc = Loc;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
|
|
||||||
const char *&PrevSpec, void *Rep) {
|
|
||||||
if (TypeSpecType != TST_unspecified)
|
|
||||||
return BadSpecifier(TypeSpecType, PrevSpec);
|
|
||||||
TypeSpecType = T;
|
|
||||||
TypeRep = Rep;
|
|
||||||
TSTLoc = Loc;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
|
|
||||||
const LangOptions &Lang) {
|
|
||||||
// Duplicates turn into warnings pre-C99.
|
|
||||||
if ((TypeQualifiers & T) && !Lang.C99)
|
|
||||||
return BadSpecifier(T, PrevSpec);
|
|
||||||
TypeQualifiers |= T;
|
|
||||||
|
|
||||||
switch (T) {
|
|
||||||
default: assert(0 && "Unknown type qualifier!");
|
|
||||||
case TQ_const: TQ_constLoc = Loc; break;
|
|
||||||
case TQ_restrict: TQ_restrictLoc = Loc; break;
|
|
||||||
case TQ_volatile: TQ_volatileLoc = Loc; break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec){
|
|
||||||
// 'inline inline' is ok.
|
|
||||||
FS_inline_specified = true;
|
|
||||||
FS_inlineLoc = Loc;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Finish - This does final analysis of the declspec, rejecting things like
|
|
||||||
/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
|
|
||||||
/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
|
|
||||||
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
|
|
||||||
void DeclSpec::Finish(Diagnostic &D, const LangOptions &Lang) {
|
|
||||||
// Check the type specifier components first.
|
|
||||||
|
|
||||||
// signed/unsigned are only valid with int/char.
|
|
||||||
if (TypeSpecSign != TSS_unspecified) {
|
|
||||||
if (TypeSpecType == TST_unspecified)
|
|
||||||
TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int.
|
|
||||||
else if (TypeSpecType != TST_int && TypeSpecType != TST_char) {
|
|
||||||
Diag(D, TSSLoc, diag::err_invalid_sign_spec,
|
|
||||||
getSpecifierName(TypeSpecType));
|
|
||||||
// signed double -> double.
|
|
||||||
TypeSpecSign = TSS_unspecified;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate the width of the type.
|
|
||||||
switch (TypeSpecWidth) {
|
|
||||||
case TSW_unspecified: break;
|
|
||||||
case TSW_short: // short int
|
|
||||||
case TSW_longlong: // long long int
|
|
||||||
if (TypeSpecType == TST_unspecified)
|
|
||||||
TypeSpecType = TST_int; // short -> short int, long long -> long long int.
|
|
||||||
else if (TypeSpecType != TST_int) {
|
|
||||||
Diag(D, TSWLoc,
|
|
||||||
TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec
|
|
||||||
: diag::err_invalid_longlong_spec,
|
|
||||||
getSpecifierName(TypeSpecType));
|
|
||||||
TypeSpecType = TST_int;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TSW_long: // long double, long int
|
|
||||||
if (TypeSpecType == TST_unspecified)
|
|
||||||
TypeSpecType = TST_int; // long -> long int.
|
|
||||||
else if (TypeSpecType != TST_int && TypeSpecType != TST_double) {
|
|
||||||
Diag(D, TSWLoc, diag::err_invalid_long_spec,
|
|
||||||
getSpecifierName(TypeSpecType));
|
|
||||||
TypeSpecType = TST_int;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: if the implementation does not implement _Complex or _Imaginary,
|
|
||||||
// disallow their use. Need information about the backend.
|
|
||||||
if (TypeSpecComplex != TSC_unspecified) {
|
|
||||||
if (TypeSpecType == TST_unspecified) {
|
|
||||||
Diag(D, TSCLoc, diag::ext_plain_complex);
|
|
||||||
TypeSpecType = TST_double; // _Complex -> _Complex double.
|
|
||||||
} else if (TypeSpecType == TST_int || TypeSpecType == TST_char) {
|
|
||||||
// Note that this intentionally doesn't include _Complex _Bool.
|
|
||||||
Diag(D, TSTLoc, diag::ext_integer_complex);
|
|
||||||
} else if (TypeSpecType != TST_float && TypeSpecType != TST_double) {
|
|
||||||
Diag(D, TSCLoc, diag::err_invalid_complex_spec,
|
|
||||||
getSpecifierName(TypeSpecType));
|
|
||||||
TypeSpecComplex = TSC_unspecified;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify __thread.
|
|
||||||
if (SCS_thread_specified) {
|
|
||||||
if (StorageClassSpec == SCS_unspecified) {
|
|
||||||
StorageClassSpec = SCS_extern; // '__thread int' -> 'extern __thread int'
|
|
||||||
} else if (StorageClassSpec != SCS_extern &&
|
|
||||||
StorageClassSpec != SCS_static) {
|
|
||||||
Diag(D, getStorageClassSpecLoc(), diag::err_invalid_thread_spec,
|
|
||||||
getSpecifierName(StorageClassSpec));
|
|
||||||
SCS_thread_specified = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Okay, now we can infer the real type.
|
|
||||||
|
|
||||||
// TODO: return "auto function" and other bad things based on the real type.
|
|
||||||
|
|
||||||
// 'data definition has no type or storage class'?
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
##===- clang/Parse/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 Parser library for the C-Language front-end.
|
|
||||||
#
|
|
||||||
##===----------------------------------------------------------------------===##
|
|
||||||
|
|
||||||
LEVEL = ../../..
|
|
||||||
LIBRARYNAME := clangParse
|
|
||||||
BUILD_ARCHIVE = 1
|
|
||||||
CXXFLAGS = -fno-rtti
|
|
||||||
|
|
||||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.common
|
|
||||||
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
//===--- MinimalAction.cpp - Implement the MinimalAction class ------------===//
|
|
||||||
//
|
|
||||||
// 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 MinimalAction interface.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Parse/Parser.h"
|
|
||||||
#include "clang/Parse/DeclSpec.h"
|
|
||||||
#include "clang/Parse/Scope.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
/// TypeNameInfo - A link exists here for each scope that an identifier is
|
|
||||||
/// defined.
|
|
||||||
struct TypeNameInfo {
|
|
||||||
TypeNameInfo *Prev;
|
|
||||||
bool isTypeName;
|
|
||||||
|
|
||||||
TypeNameInfo(bool istypename, TypeNameInfo *prev) {
|
|
||||||
isTypeName = istypename;
|
|
||||||
Prev = prev;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to
|
|
||||||
/// determine whether the name is a type name (objc class name or typedef) or
|
|
||||||
/// not in this scope.
|
|
||||||
Action::DeclTy *
|
|
||||||
MinimalAction::isTypeName(const IdentifierInfo &II, Scope *S) const {
|
|
||||||
if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>())
|
|
||||||
if (TI->isTypeName)
|
|
||||||
return TI;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseDeclarator - If this is a typedef declarator, we modify the
|
|
||||||
/// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is
|
|
||||||
/// popped.
|
|
||||||
Action::DeclTy *
|
|
||||||
MinimalAction::ParseDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup) {
|
|
||||||
IdentifierInfo *II = D.getIdentifier();
|
|
||||||
|
|
||||||
// If there is no identifier associated with this declarator, bail out.
|
|
||||||
if (II == 0) return 0;
|
|
||||||
|
|
||||||
TypeNameInfo *weCurrentlyHaveTypeInfo = II->getFETokenInfo<TypeNameInfo>();
|
|
||||||
bool isTypeName =
|
|
||||||
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef;
|
|
||||||
|
|
||||||
// this check avoids creating TypeNameInfo objects for the common case.
|
|
||||||
// It does need to handle the uncommon case of shadowing a typedef name with a
|
|
||||||
// non-typedef name. e.g. { typedef int a; a xx; { int a; } }
|
|
||||||
if (weCurrentlyHaveTypeInfo || isTypeName) {
|
|
||||||
TypeNameInfo *TI = new TypeNameInfo(isTypeName, weCurrentlyHaveTypeInfo);
|
|
||||||
|
|
||||||
II->setFETokenInfo(TI);
|
|
||||||
|
|
||||||
// Remember that this needs to be removed when the scope is popped.
|
|
||||||
S->AddDecl(II);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::DeclTy *
|
|
||||||
MinimalAction::ObjcStartClassInterface(SourceLocation AtInterafceLoc,
|
|
||||||
IdentifierInfo *ClassName, SourceLocation ClassLoc,
|
|
||||||
IdentifierInfo *SuperName, SourceLocation SuperLoc,
|
|
||||||
IdentifierInfo **ProtocolNames, unsigned NumProtocols,
|
|
||||||
AttributeList *AttrList) {
|
|
||||||
TypeNameInfo *TI =
|
|
||||||
new TypeNameInfo(1, ClassName->getFETokenInfo<TypeNameInfo>());
|
|
||||||
|
|
||||||
ClassName->setFETokenInfo(TI);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ObjcClassDeclaration -
|
|
||||||
/// Scope will always be top level file scope.
|
|
||||||
Action::DeclTy *
|
|
||||||
MinimalAction::ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc,
|
|
||||||
IdentifierInfo **IdentList, unsigned NumElts) {
|
|
||||||
for (unsigned i = 0; i != NumElts; ++i) {
|
|
||||||
TypeNameInfo *TI =
|
|
||||||
new TypeNameInfo(1, IdentList[i]->getFETokenInfo<TypeNameInfo>());
|
|
||||||
|
|
||||||
IdentList[i]->setFETokenInfo(TI);
|
|
||||||
|
|
||||||
// Remember that this needs to be removed when the scope is popped.
|
|
||||||
S->AddDecl(IdentList[i]);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PopScope - When a scope is popped, if any typedefs are now out-of-scope,
|
|
||||||
/// they are removed from the IdentifierInfo::FETokenInfo field.
|
|
||||||
void MinimalAction::PopScope(SourceLocation Loc, Scope *S) {
|
|
||||||
for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end();
|
|
||||||
I != E; ++I) {
|
|
||||||
IdentifierInfo &II = *static_cast<IdentifierInfo*>(*I);
|
|
||||||
TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>();
|
|
||||||
assert(TI && "This decl didn't get pushed??");
|
|
||||||
|
|
||||||
if (TI) {
|
|
||||||
TypeNameInfo *Next = TI->Prev;
|
|
||||||
delete TI;
|
|
||||||
|
|
||||||
II.setFETokenInfo(Next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
|||||||
//===--- ParseDeclCXX.cpp - C++ Declaration Parsing -----------------------===//
|
|
||||||
//
|
|
||||||
// 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 C++ Declaration portions of the Parser interfaces.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Parse/Parser.h"
|
|
||||||
#include "clang/Parse/Scope.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
/// ParseNamespace - We know that the current token is a namespace keyword. This
|
|
||||||
/// may either be a top level namespace or a block-level namespace alias.
|
|
||||||
///
|
|
||||||
/// namespace-definition: [C++ 7.3: basic.namespace]
|
|
||||||
/// named-namespace-definition
|
|
||||||
/// unnamed-namespace-definition
|
|
||||||
///
|
|
||||||
/// unnamed-namespace-definition:
|
|
||||||
/// 'namespace' attributes[opt] '{' namespace-body '}'
|
|
||||||
///
|
|
||||||
/// named-namespace-definition:
|
|
||||||
/// original-namespace-definition
|
|
||||||
/// extension-namespace-definition
|
|
||||||
///
|
|
||||||
/// original-namespace-definition:
|
|
||||||
/// 'namespace' identifier attributes[opt] '{' namespace-body '}'
|
|
||||||
///
|
|
||||||
/// extension-namespace-definition:
|
|
||||||
/// 'namespace' original-namespace-name '{' namespace-body '}'
|
|
||||||
///
|
|
||||||
/// namespace-alias-definition: [C++ 7.3.2: namespace.alias]
|
|
||||||
/// 'namespace' identifier '=' qualified-namespace-specifier ';'
|
|
||||||
///
|
|
||||||
Parser::DeclTy *Parser::ParseNamespace(unsigned Context) {
|
|
||||||
assert(Tok.getKind() == tok::kw_namespace && "Not a namespace!");
|
|
||||||
SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'.
|
|
||||||
|
|
||||||
SourceLocation IdentLoc;
|
|
||||||
IdentifierInfo *Ident = 0;
|
|
||||||
|
|
||||||
if (Tok.getKind() == tok::identifier) {
|
|
||||||
Ident = Tok.getIdentifierInfo();
|
|
||||||
IdentLoc = ConsumeToken(); // eat the identifier.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read label attributes, if present.
|
|
||||||
DeclTy *AttrList = 0;
|
|
||||||
if (Tok.getKind() == tok::kw___attribute)
|
|
||||||
// FIXME: save these somewhere.
|
|
||||||
AttrList = ParseAttributes();
|
|
||||||
|
|
||||||
if (Tok.getKind() == tok::equal) {
|
|
||||||
// FIXME: Verify no attributes were present.
|
|
||||||
// FIXME: parse this.
|
|
||||||
} else if (Tok.getKind() == tok::l_brace) {
|
|
||||||
SourceLocation LBrace = ConsumeBrace();
|
|
||||||
// FIXME: push a scope, push a namespace decl.
|
|
||||||
|
|
||||||
while (Tok.getKind() != tok::r_brace && Tok.getKind() != tok::eof) {
|
|
||||||
// FIXME capture the decls.
|
|
||||||
ParseExternalDeclaration();
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace);
|
|
||||||
|
|
||||||
// FIXME: act on this.
|
|
||||||
} else {
|
|
||||||
unsigned D = Ident ? diag::err_expected_lbrace :
|
|
||||||
diag::err_expected_ident_lbrace;
|
|
||||||
Diag(Tok.getLocation(), D);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,78 +0,0 @@
|
|||||||
//===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Bill Wendling and is distributed under the
|
|
||||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file implements the Expression parsing implementation for C++.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "clang/Parse/Parser.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
/// ParseCXXCasts - This handles the various ways to cast expressions to another
|
|
||||||
/// type.
|
|
||||||
///
|
|
||||||
/// postfix-expression: [C++ 5.2p1]
|
|
||||||
/// 'dynamic_cast' '<' type-name '>' '(' expression ')'
|
|
||||||
/// 'static_cast' '<' type-name '>' '(' expression ')'
|
|
||||||
/// 'reinterpret_cast' '<' type-name '>' '(' expression ')'
|
|
||||||
/// 'const_cast' '<' type-name '>' '(' expression ')'
|
|
||||||
///
|
|
||||||
Parser::ExprResult Parser::ParseCXXCasts() {
|
|
||||||
tok::TokenKind Kind = Tok.getKind();
|
|
||||||
const char *CastName = 0; // For error messages
|
|
||||||
|
|
||||||
switch (Kind) {
|
|
||||||
default: assert(0 && "Unknown C++ cast!"); abort();
|
|
||||||
case tok::kw_const_cast: CastName = "const_cast"; break;
|
|
||||||
case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break;
|
|
||||||
case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break;
|
|
||||||
case tok::kw_static_cast: CastName = "static_cast"; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLocation OpLoc = ConsumeToken();
|
|
||||||
SourceLocation LAngleBracketLoc = Tok.getLocation();
|
|
||||||
|
|
||||||
if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
|
|
||||||
return ExprResult(true);
|
|
||||||
|
|
||||||
TypeTy *CastTy = ParseTypeName();
|
|
||||||
SourceLocation RAngleBracketLoc = Tok.getLocation();
|
|
||||||
|
|
||||||
if (ExpectAndConsume(tok::greater, diag::err_expected_greater)) {
|
|
||||||
Diag(LAngleBracketLoc, diag::err_matching, "<");
|
|
||||||
return ExprResult(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::l_paren) {
|
|
||||||
Diag(Tok, diag::err_expected_lparen_after, CastName);
|
|
||||||
return ExprResult(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExprResult Result = ParseSimpleParenExpression(RParenLoc);
|
|
||||||
|
|
||||||
if (!Result.isInvalid)
|
|
||||||
Result = Actions.ParseCXXCasts(OpLoc, Kind,
|
|
||||||
LAngleBracketLoc, CastTy, RAngleBracketLoc,
|
|
||||||
LParenLoc, Result.Val, RParenLoc);
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseCXXBoolLiteral - This handles the C++ Boolean literals.
|
|
||||||
///
|
|
||||||
/// boolean-literal: [C++ 2.13.5]
|
|
||||||
/// 'true'
|
|
||||||
/// 'false'
|
|
||||||
Parser::ExprResult Parser::ParseCXXBoolLiteral() {
|
|
||||||
tok::TokenKind Kind = Tok.getKind();
|
|
||||||
return Actions.ParseCXXBoolLiteral(ConsumeToken(), Kind);
|
|
||||||
}
|
|
||||||
@@ -1,199 +0,0 @@
|
|||||||
//===--- ParseInit.cpp - Initializer Parsing ------------------------------===//
|
|
||||||
//
|
|
||||||
// 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 initializer parsing as specified by C99 6.7.8.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Parse/Parser.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "llvm/ADT/SmallString.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
|
|
||||||
/// MayBeDesignationStart - Return true if this token might be the start of a
|
|
||||||
/// designator.
|
|
||||||
static bool MayBeDesignationStart(tok::TokenKind K) {
|
|
||||||
switch (K) {
|
|
||||||
default: return false;
|
|
||||||
case tok::period: // designator: '.' identifier
|
|
||||||
case tok::l_square: // designator: array-designator
|
|
||||||
case tok::identifier: // designation: identifier ':'
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
|
|
||||||
/// checking to see if the token stream starts with a designator.
|
|
||||||
///
|
|
||||||
/// designation:
|
|
||||||
/// designator-list '='
|
|
||||||
/// [GNU] array-designator
|
|
||||||
/// [GNU] identifier ':'
|
|
||||||
///
|
|
||||||
/// designator-list:
|
|
||||||
/// designator
|
|
||||||
/// designator-list designator
|
|
||||||
///
|
|
||||||
/// designator:
|
|
||||||
/// array-designator
|
|
||||||
/// '.' identifier
|
|
||||||
///
|
|
||||||
/// array-designator:
|
|
||||||
/// '[' constant-expression ']'
|
|
||||||
/// [GNU] '[' constant-expression '...' constant-expression ']'
|
|
||||||
///
|
|
||||||
/// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an
|
|
||||||
/// initializer. We need to consider this case when parsing array designators.
|
|
||||||
///
|
|
||||||
Parser::ExprResult Parser::ParseInitializerWithPotentialDesignator() {
|
|
||||||
// Parse each designator in the designator list until we find an initializer.
|
|
||||||
while (1) {
|
|
||||||
switch (Tok.getKind()) {
|
|
||||||
case tok::equal:
|
|
||||||
// We read some number (at least one due to the grammar we implemented)
|
|
||||||
// of designators and found an '=' sign. The following tokens must be
|
|
||||||
// the initializer.
|
|
||||||
ConsumeToken();
|
|
||||||
return ParseInitializer();
|
|
||||||
|
|
||||||
default: {
|
|
||||||
// We read some number (at least one due to the grammar we implemented)
|
|
||||||
// of designators and found something that isn't an = or an initializer.
|
|
||||||
// If we have exactly one array designator [TODO CHECK], this is the GNU
|
|
||||||
// 'designation: array-designator' extension. Otherwise, it is a parse
|
|
||||||
// error.
|
|
||||||
SourceLocation Loc = Tok.getLocation();
|
|
||||||
ExprResult Init = ParseInitializer();
|
|
||||||
if (Init.isInvalid) return Init;
|
|
||||||
|
|
||||||
Diag(Tok, diag::ext_gnu_missing_equal_designator);
|
|
||||||
return Init;
|
|
||||||
}
|
|
||||||
case tok::period:
|
|
||||||
// designator: '.' identifier
|
|
||||||
ConsumeToken();
|
|
||||||
if (ExpectAndConsume(tok::identifier, diag::err_expected_ident))
|
|
||||||
return ExprResult(true);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case tok::l_square: {
|
|
||||||
// array-designator: '[' constant-expression ']'
|
|
||||||
// array-designator: '[' constant-expression '...' constant-expression ']'
|
|
||||||
SourceLocation StartLoc = ConsumeBracket();
|
|
||||||
|
|
||||||
ExprResult Idx = ParseConstantExpression();
|
|
||||||
if (Idx.isInvalid) {
|
|
||||||
SkipUntil(tok::r_square);
|
|
||||||
return Idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the gnu array range extension.
|
|
||||||
if (Tok.getKind() == tok::ellipsis) {
|
|
||||||
Diag(Tok, diag::ext_gnu_array_range);
|
|
||||||
ConsumeToken();
|
|
||||||
|
|
||||||
ExprResult RHS = ParseConstantExpression();
|
|
||||||
if (RHS.isInvalid) {
|
|
||||||
SkipUntil(tok::r_square);
|
|
||||||
return RHS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MatchRHSPunctuation(tok::r_square, StartLoc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case tok::identifier: {
|
|
||||||
// Due to the GNU "designation: identifier ':'" extension, we don't know
|
|
||||||
// whether something starting with an identifier is an
|
|
||||||
// assignment-expression or if it is an old-style structure field
|
|
||||||
// designator.
|
|
||||||
// TODO: Check that this is the first designator.
|
|
||||||
Token Ident = Tok;
|
|
||||||
ConsumeToken();
|
|
||||||
|
|
||||||
// If this is the gross GNU extension, handle it now.
|
|
||||||
if (Tok.getKind() == tok::colon) {
|
|
||||||
Diag(Ident, diag::ext_gnu_old_style_field_designator);
|
|
||||||
ConsumeToken();
|
|
||||||
return ParseInitializer();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, we just consumed the first token of an expression. Parse
|
|
||||||
// the rest of it now.
|
|
||||||
return ParseAssignmentExprWithLeadingIdentifier(Ident);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// ParseInitializer
|
|
||||||
/// initializer: [C99 6.7.8]
|
|
||||||
/// assignment-expression
|
|
||||||
/// '{' initializer-list '}'
|
|
||||||
/// '{' initializer-list ',' '}'
|
|
||||||
/// [GNU] '{' '}'
|
|
||||||
///
|
|
||||||
/// initializer-list:
|
|
||||||
/// designation[opt] initializer
|
|
||||||
/// initializer-list ',' designation[opt] initializer
|
|
||||||
///
|
|
||||||
Parser::ExprResult Parser::ParseInitializer() {
|
|
||||||
if (Tok.getKind() != tok::l_brace)
|
|
||||||
return ParseAssignmentExpression();
|
|
||||||
|
|
||||||
SourceLocation LBraceLoc = ConsumeBrace();
|
|
||||||
|
|
||||||
// We support empty initializers, but tell the user that they aren't using
|
|
||||||
// C99-clean code.
|
|
||||||
if (Tok.getKind() == tok::r_brace) {
|
|
||||||
Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
|
|
||||||
// Match the '}'.
|
|
||||||
return Actions.ParseInitList(LBraceLoc, 0, 0, ConsumeBrace());
|
|
||||||
}
|
|
||||||
llvm::SmallVector<ExprTy*, 8> InitExprs;
|
|
||||||
bool InitExprsOk = true;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
// Parse: designation[opt] initializer
|
|
||||||
|
|
||||||
// If we know that this cannot be a designation, just parse the nested
|
|
||||||
// initializer directly.
|
|
||||||
ExprResult SubElt;
|
|
||||||
if (!MayBeDesignationStart(Tok.getKind()))
|
|
||||||
SubElt = ParseInitializer();
|
|
||||||
else
|
|
||||||
SubElt = ParseInitializerWithPotentialDesignator();
|
|
||||||
|
|
||||||
// If we couldn't parse the subelement, bail out.
|
|
||||||
if (SubElt.isInvalid) {
|
|
||||||
InitExprsOk = false;
|
|
||||||
SkipUntil(tok::r_brace);
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
InitExprs.push_back(SubElt.Val);
|
|
||||||
|
|
||||||
// If we don't have a comma continued list, we're done.
|
|
||||||
if (Tok.getKind() != tok::comma) break;
|
|
||||||
|
|
||||||
// FIXME: save comma locations.
|
|
||||||
ConsumeToken();
|
|
||||||
|
|
||||||
// Handle trailing comma.
|
|
||||||
if (Tok.getKind() == tok::r_brace) break;
|
|
||||||
}
|
|
||||||
if (InitExprsOk && Tok.getKind() == tok::r_brace)
|
|
||||||
return Actions.ParseInitList(LBraceLoc, &InitExprs[0], InitExprs.size(),
|
|
||||||
ConsumeBrace());
|
|
||||||
// Match the '}'.
|
|
||||||
MatchRHSPunctuation(tok::r_brace, LBraceLoc);
|
|
||||||
return ExprResult(true); // an error occurred.
|
|
||||||
}
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,978 +0,0 @@
|
|||||||
//===--- ParseStmt.cpp - Statement and Block Parser -----------------------===//
|
|
||||||
//
|
|
||||||
// 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 Statement and Block portions of the Parser
|
|
||||||
// interface.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Parse/Parser.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "clang/Parse/DeclSpec.h"
|
|
||||||
#include "clang/Parse/Scope.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// C99 6.8: Statements and Blocks.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// ParseStatementOrDeclaration - Read 'statement' or 'declaration'.
|
|
||||||
/// StatementOrDeclaration:
|
|
||||||
/// statement
|
|
||||||
/// declaration
|
|
||||||
///
|
|
||||||
/// statement:
|
|
||||||
/// labeled-statement
|
|
||||||
/// compound-statement
|
|
||||||
/// expression-statement
|
|
||||||
/// selection-statement
|
|
||||||
/// iteration-statement
|
|
||||||
/// jump-statement
|
|
||||||
/// [OBC] objc-throw-statement [TODO]
|
|
||||||
/// [OBC] objc-try-catch-statement [TODO]
|
|
||||||
/// [OBC] objc-synchronized-statement [TODO]
|
|
||||||
/// [GNU] asm-statement
|
|
||||||
/// [OMP] openmp-construct [TODO]
|
|
||||||
///
|
|
||||||
/// labeled-statement:
|
|
||||||
/// identifier ':' statement
|
|
||||||
/// 'case' constant-expression ':' statement
|
|
||||||
/// 'default' ':' statement
|
|
||||||
///
|
|
||||||
/// selection-statement:
|
|
||||||
/// if-statement
|
|
||||||
/// switch-statement
|
|
||||||
///
|
|
||||||
/// iteration-statement:
|
|
||||||
/// while-statement
|
|
||||||
/// do-statement
|
|
||||||
/// for-statement
|
|
||||||
///
|
|
||||||
/// expression-statement:
|
|
||||||
/// expression[opt] ';'
|
|
||||||
///
|
|
||||||
/// jump-statement:
|
|
||||||
/// 'goto' identifier ';'
|
|
||||||
/// 'continue' ';'
|
|
||||||
/// 'break' ';'
|
|
||||||
/// 'return' expression[opt] ';'
|
|
||||||
/// [GNU] 'goto' '*' expression ';'
|
|
||||||
///
|
|
||||||
/// [OBC] objc-throw-statement: [TODO]
|
|
||||||
/// [OBC] '@' 'throw' expression ';' [TODO]
|
|
||||||
/// [OBC] '@' 'throw' ';' [TODO]
|
|
||||||
///
|
|
||||||
Parser::StmtResult Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
|
|
||||||
const char *SemiError = 0;
|
|
||||||
Parser::StmtResult Res;
|
|
||||||
|
|
||||||
// Cases in this switch statement should fall through if the parser expects
|
|
||||||
// the token to end in a semicolon (in which case SemiError should be set),
|
|
||||||
// or they directly 'return;' if not.
|
|
||||||
switch (Tok.getKind()) {
|
|
||||||
case tok::identifier: // C99 6.8.1: labeled-statement
|
|
||||||
// identifier ':' statement
|
|
||||||
// declaration (if !OnlyStatement)
|
|
||||||
// expression[opt] ';'
|
|
||||||
return ParseIdentifierStatement(OnlyStatement);
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (!OnlyStatement && isDeclarationSpecifier()) {
|
|
||||||
return Actions.ParseDeclStmt(ParseDeclaration(Declarator::BlockContext));
|
|
||||||
} else if (Tok.getKind() == tok::r_brace) {
|
|
||||||
Diag(Tok, diag::err_expected_statement);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// expression[opt] ';'
|
|
||||||
ExprResult Res = ParseExpression();
|
|
||||||
if (Res.isInvalid) {
|
|
||||||
// If the expression is invalid, skip ahead to the next semicolon. Not
|
|
||||||
// doing this opens us up to the possibility of infinite loops if
|
|
||||||
// ParseExpression does not consume any tokens.
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Otherwise, eat the semicolon.
|
|
||||||
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
|
|
||||||
return Actions.ParseExprStmt(Res.Val);
|
|
||||||
}
|
|
||||||
|
|
||||||
case tok::kw_case: // C99 6.8.1: labeled-statement
|
|
||||||
return ParseCaseStatement();
|
|
||||||
case tok::kw_default: // C99 6.8.1: labeled-statement
|
|
||||||
return ParseDefaultStatement();
|
|
||||||
|
|
||||||
case tok::l_brace: // C99 6.8.2: compound-statement
|
|
||||||
return ParseCompoundStatement();
|
|
||||||
case tok::semi: // C99 6.8.3p3: expression[opt] ';'
|
|
||||||
return Actions.ParseNullStmt(ConsumeToken());
|
|
||||||
|
|
||||||
case tok::kw_if: // C99 6.8.4.1: if-statement
|
|
||||||
return ParseIfStatement();
|
|
||||||
case tok::kw_switch: // C99 6.8.4.2: switch-statement
|
|
||||||
return ParseSwitchStatement();
|
|
||||||
|
|
||||||
case tok::kw_while: // C99 6.8.5.1: while-statement
|
|
||||||
return ParseWhileStatement();
|
|
||||||
case tok::kw_do: // C99 6.8.5.2: do-statement
|
|
||||||
Res = ParseDoStatement();
|
|
||||||
SemiError = "do/while loop";
|
|
||||||
break;
|
|
||||||
case tok::kw_for: // C99 6.8.5.3: for-statement
|
|
||||||
return ParseForStatement();
|
|
||||||
|
|
||||||
case tok::kw_goto: // C99 6.8.6.1: goto-statement
|
|
||||||
Res = ParseGotoStatement();
|
|
||||||
SemiError = "goto statement";
|
|
||||||
break;
|
|
||||||
case tok::kw_continue: // C99 6.8.6.2: continue-statement
|
|
||||||
Res = ParseContinueStatement();
|
|
||||||
SemiError = "continue statement";
|
|
||||||
break;
|
|
||||||
case tok::kw_break: // C99 6.8.6.3: break-statement
|
|
||||||
Res = ParseBreakStatement();
|
|
||||||
SemiError = "break statement";
|
|
||||||
break;
|
|
||||||
case tok::kw_return: // C99 6.8.6.4: return-statement
|
|
||||||
Res = ParseReturnStatement();
|
|
||||||
SemiError = "return statement";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case tok::kw_asm:
|
|
||||||
Res = ParseAsmStatement();
|
|
||||||
SemiError = "asm statement";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we reached this code, the statement must end in a semicolon.
|
|
||||||
if (Tok.getKind() == tok::semi) {
|
|
||||||
ConsumeToken();
|
|
||||||
} else {
|
|
||||||
Diag(Tok, diag::err_expected_semi_after, SemiError);
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
}
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseIdentifierStatement - Because we don't have two-token lookahead, we
|
|
||||||
/// have a bit of a quandry here. Reading the identifier is necessary to see if
|
|
||||||
/// there is a ':' after it. If there is, this is a label, regardless of what
|
|
||||||
/// else the identifier can mean. If not, this is either part of a declaration
|
|
||||||
/// (if the identifier is a type-name) or part of an expression.
|
|
||||||
///
|
|
||||||
/// labeled-statement:
|
|
||||||
/// identifier ':' statement
|
|
||||||
/// [GNU] identifier ':' attributes[opt] statement
|
|
||||||
/// declaration (if !OnlyStatement)
|
|
||||||
/// expression[opt] ';'
|
|
||||||
///
|
|
||||||
Parser::StmtResult Parser::ParseIdentifierStatement(bool OnlyStatement) {
|
|
||||||
assert(Tok.getKind() == tok::identifier && Tok.getIdentifierInfo() &&
|
|
||||||
"Not an identifier!");
|
|
||||||
|
|
||||||
Token IdentTok = Tok; // Save the whole token.
|
|
||||||
ConsumeToken(); // eat the identifier.
|
|
||||||
|
|
||||||
// identifier ':' statement
|
|
||||||
if (Tok.getKind() == tok::colon) {
|
|
||||||
SourceLocation ColonLoc = ConsumeToken();
|
|
||||||
|
|
||||||
// Read label attributes, if present.
|
|
||||||
DeclTy *AttrList = 0;
|
|
||||||
if (Tok.getKind() == tok::kw___attribute)
|
|
||||||
// TODO: save these somewhere.
|
|
||||||
AttrList = ParseAttributes();
|
|
||||||
|
|
||||||
StmtResult SubStmt = ParseStatement();
|
|
||||||
|
|
||||||
// Broken substmt shouldn't prevent the label from being added to the AST.
|
|
||||||
if (SubStmt.isInvalid)
|
|
||||||
SubStmt = Actions.ParseNullStmt(ColonLoc);
|
|
||||||
|
|
||||||
return Actions.ParseLabelStmt(IdentTok.getLocation(),
|
|
||||||
IdentTok.getIdentifierInfo(),
|
|
||||||
ColonLoc, SubStmt.Val);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check to see if this is a declaration.
|
|
||||||
void *TypeRep;
|
|
||||||
if (!OnlyStatement &&
|
|
||||||
(TypeRep = Actions.isTypeName(*IdentTok.getIdentifierInfo(), CurScope))) {
|
|
||||||
// Handle this. Warn/disable if in middle of block and !C99.
|
|
||||||
DeclSpec DS;
|
|
||||||
|
|
||||||
// Add the typedef name to the start of the decl-specs.
|
|
||||||
const char *PrevSpec = 0;
|
|
||||||
int isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef,
|
|
||||||
IdentTok.getLocation(), PrevSpec,
|
|
||||||
TypeRep);
|
|
||||||
assert(!isInvalid && "First declspec can't be invalid!");
|
|
||||||
|
|
||||||
// ParseDeclarationSpecifiers will continue from there.
|
|
||||||
ParseDeclarationSpecifiers(DS);
|
|
||||||
|
|
||||||
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
|
|
||||||
// declaration-specifiers init-declarator-list[opt] ';'
|
|
||||||
if (Tok.getKind() == tok::semi) {
|
|
||||||
// TODO: emit error on 'int;' or 'const enum foo;'.
|
|
||||||
// if (!DS.isMissingDeclaratorOk()) Diag(...);
|
|
||||||
|
|
||||||
ConsumeToken();
|
|
||||||
// FIXME: Return this as a type decl.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse all the declarators.
|
|
||||||
Declarator DeclaratorInfo(DS, Declarator::BlockContext);
|
|
||||||
ParseDeclarator(DeclaratorInfo);
|
|
||||||
|
|
||||||
DeclTy *Decl = ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
|
|
||||||
return Decl ? Actions.ParseDeclStmt(Decl) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, this is an expression. Seed it with II and parse it.
|
|
||||||
ExprResult Res = ParseExpressionWithLeadingIdentifier(IdentTok);
|
|
||||||
if (Res.isInvalid) {
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
return true;
|
|
||||||
} else if (Tok.getKind() != tok::semi) {
|
|
||||||
Diag(Tok, diag::err_expected_semi_after, "expression");
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
ConsumeToken();
|
|
||||||
// Convert expr to a stmt.
|
|
||||||
return Actions.ParseExprStmt(Res.Val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseCaseStatement
|
|
||||||
/// labeled-statement:
|
|
||||||
/// 'case' constant-expression ':' statement
|
|
||||||
/// [GNU] 'case' constant-expression '...' constant-expression ':' statement
|
|
||||||
///
|
|
||||||
/// Note that this does not parse the 'statement' at the end.
|
|
||||||
///
|
|
||||||
Parser::StmtResult Parser::ParseCaseStatement() {
|
|
||||||
assert(Tok.getKind() == tok::kw_case && "Not a case stmt!");
|
|
||||||
SourceLocation CaseLoc = ConsumeToken(); // eat the 'case'.
|
|
||||||
|
|
||||||
ExprResult LHS = ParseConstantExpression();
|
|
||||||
if (LHS.isInvalid) {
|
|
||||||
SkipUntil(tok::colon);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GNU case range extension.
|
|
||||||
SourceLocation DotDotDotLoc;
|
|
||||||
ExprTy *RHSVal = 0;
|
|
||||||
if (Tok.getKind() == tok::ellipsis) {
|
|
||||||
Diag(Tok, diag::ext_gnu_case_range);
|
|
||||||
DotDotDotLoc = ConsumeToken();
|
|
||||||
|
|
||||||
ExprResult RHS = ParseConstantExpression();
|
|
||||||
if (RHS.isInvalid) {
|
|
||||||
SkipUntil(tok::colon);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
RHSVal = RHS.Val;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::colon) {
|
|
||||||
Diag(Tok, diag::err_expected_colon_after, "'case'");
|
|
||||||
SkipUntil(tok::colon);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLocation ColonLoc = ConsumeToken();
|
|
||||||
|
|
||||||
// Diagnose the common error "switch (X) { case 4: }", which is not valid.
|
|
||||||
if (Tok.getKind() == tok::r_brace) {
|
|
||||||
Diag(Tok, diag::err_label_end_of_compound_statement);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
StmtResult SubStmt = ParseStatement();
|
|
||||||
|
|
||||||
// Broken substmt shouldn't prevent the case from being added to the AST.
|
|
||||||
if (SubStmt.isInvalid)
|
|
||||||
SubStmt = Actions.ParseNullStmt(ColonLoc);
|
|
||||||
|
|
||||||
return Actions.ParseCaseStmt(CaseLoc, LHS.Val, DotDotDotLoc, RHSVal, ColonLoc,
|
|
||||||
SubStmt.Val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseDefaultStatement
|
|
||||||
/// labeled-statement:
|
|
||||||
/// 'default' ':' statement
|
|
||||||
/// Note that this does not parse the 'statement' at the end.
|
|
||||||
///
|
|
||||||
Parser::StmtResult Parser::ParseDefaultStatement() {
|
|
||||||
assert(Tok.getKind() == tok::kw_default && "Not a default stmt!");
|
|
||||||
SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'.
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::colon) {
|
|
||||||
Diag(Tok, diag::err_expected_colon_after, "'default'");
|
|
||||||
SkipUntil(tok::colon);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLocation ColonLoc = ConsumeToken();
|
|
||||||
|
|
||||||
// Diagnose the common error "switch (X) {... default: }", which is not valid.
|
|
||||||
if (Tok.getKind() == tok::r_brace) {
|
|
||||||
Diag(Tok, diag::err_label_end_of_compound_statement);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
StmtResult SubStmt = ParseStatement();
|
|
||||||
if (SubStmt.isInvalid)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return Actions.ParseDefaultStmt(DefaultLoc, ColonLoc, SubStmt.Val, CurScope);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// ParseCompoundStatement - Parse a "{}" block.
|
|
||||||
///
|
|
||||||
/// compound-statement: [C99 6.8.2]
|
|
||||||
/// { block-item-list[opt] }
|
|
||||||
/// [GNU] { label-declarations block-item-list } [TODO]
|
|
||||||
///
|
|
||||||
/// block-item-list:
|
|
||||||
/// block-item
|
|
||||||
/// block-item-list block-item
|
|
||||||
///
|
|
||||||
/// block-item:
|
|
||||||
/// declaration
|
|
||||||
/// [GNU] '__extension__' declaration
|
|
||||||
/// statement
|
|
||||||
/// [OMP] openmp-directive [TODO]
|
|
||||||
///
|
|
||||||
/// [GNU] label-declarations:
|
|
||||||
/// [GNU] label-declaration
|
|
||||||
/// [GNU] label-declarations label-declaration
|
|
||||||
///
|
|
||||||
/// [GNU] label-declaration:
|
|
||||||
/// [GNU] '__label__' identifier-list ';'
|
|
||||||
///
|
|
||||||
/// [OMP] openmp-directive: [TODO]
|
|
||||||
/// [OMP] barrier-directive
|
|
||||||
/// [OMP] flush-directive
|
|
||||||
///
|
|
||||||
Parser::StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
|
|
||||||
assert(Tok.getKind() == tok::l_brace && "Not a compount stmt!");
|
|
||||||
|
|
||||||
// Enter a scope to hold everything within the compound stmt. Compound
|
|
||||||
// statements can always hold declarations.
|
|
||||||
EnterScope(Scope::DeclScope);
|
|
||||||
|
|
||||||
// Parse the statements in the body.
|
|
||||||
StmtResult Body = ParseCompoundStatementBody(isStmtExpr);
|
|
||||||
|
|
||||||
ExitScope();
|
|
||||||
return Body;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the
|
|
||||||
/// ParseCompoundStmt action. This expects the '{' to be the current token, and
|
|
||||||
/// consume the '}' at the end of the block. It does not manipulate the scope
|
|
||||||
/// stack.
|
|
||||||
Parser::StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
|
|
||||||
SourceLocation LBraceLoc = ConsumeBrace(); // eat the '{'.
|
|
||||||
|
|
||||||
// TODO: "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are
|
|
||||||
// only allowed at the start of a compound stmt regardless of the language.
|
|
||||||
|
|
||||||
llvm::SmallVector<StmtTy*, 32> Stmts;
|
|
||||||
while (Tok.getKind() != tok::r_brace && Tok.getKind() != tok::eof) {
|
|
||||||
StmtResult R;
|
|
||||||
if (Tok.getKind() != tok::kw___extension__) {
|
|
||||||
R = ParseStatementOrDeclaration(false);
|
|
||||||
} else {
|
|
||||||
// __extension__ can start declarations and it can also be a unary
|
|
||||||
// operator for expressions. Consume multiple __extension__ markers here
|
|
||||||
// until we can determine which is which.
|
|
||||||
SourceLocation ExtLoc = ConsumeToken();
|
|
||||||
while (Tok.getKind() == tok::kw___extension__)
|
|
||||||
ConsumeToken();
|
|
||||||
|
|
||||||
// If this is the start of a declaration, parse it as such.
|
|
||||||
if (isDeclarationSpecifier()) {
|
|
||||||
// FIXME: Save the __extension__ on the decl as a node somehow.
|
|
||||||
// FIXME: disable extwarns.
|
|
||||||
R = Actions.ParseDeclStmt(ParseDeclaration(Declarator::BlockContext));
|
|
||||||
} else {
|
|
||||||
// Otherwise this was a unary __extension__ marker. Parse the
|
|
||||||
// subexpression and add the __extension__ unary op.
|
|
||||||
// FIXME: disable extwarns.
|
|
||||||
ExprResult Res = ParseCastExpression(false);
|
|
||||||
if (Res.isInvalid) {
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the __extension__ node to the AST.
|
|
||||||
Res = Actions.ParseUnaryOp(ExtLoc, tok::kw___extension__, Res.Val);
|
|
||||||
if (Res.isInvalid)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Eat the semicolon at the end of stmt and convert the expr into a stmt.
|
|
||||||
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
|
|
||||||
R = Actions.ParseExprStmt(Res.Val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!R.isInvalid && R.Val)
|
|
||||||
Stmts.push_back(R.Val);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We broke out of the while loop because we found a '}' or EOF.
|
|
||||||
if (Tok.getKind() != tok::r_brace) {
|
|
||||||
Diag(Tok, diag::err_expected_rbrace);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLocation RBraceLoc = ConsumeBrace();
|
|
||||||
return Actions.ParseCompoundStmt(LBraceLoc, RBraceLoc,
|
|
||||||
&Stmts[0], Stmts.size(), isStmtExpr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseIfStatement
|
|
||||||
/// if-statement: [C99 6.8.4.1]
|
|
||||||
/// 'if' '(' expression ')' statement
|
|
||||||
/// 'if' '(' expression ')' statement 'else' statement
|
|
||||||
///
|
|
||||||
Parser::StmtResult Parser::ParseIfStatement() {
|
|
||||||
assert(Tok.getKind() == tok::kw_if && "Not an if stmt!");
|
|
||||||
SourceLocation IfLoc = ConsumeToken(); // eat the 'if'.
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::l_paren) {
|
|
||||||
Diag(Tok, diag::err_expected_lparen_after, "if");
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// C99 6.8.4p3 - In C99, the if statement is a block. This is not
|
|
||||||
// the case for C90.
|
|
||||||
if (getLang().C99)
|
|
||||||
EnterScope(Scope::DeclScope);
|
|
||||||
|
|
||||||
// Parse the condition.
|
|
||||||
ExprResult CondExp = ParseSimpleParenExpression();
|
|
||||||
if (CondExp.isInvalid) {
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
if (getLang().C99)
|
|
||||||
ExitScope();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
|
|
||||||
// there is no compound stmt. C90 does not have this clause. We only do this
|
|
||||||
// if the body isn't a compound statement to avoid push/pop in common cases.
|
|
||||||
bool NeedsInnerScope = getLang().C99 && Tok.getKind() != tok::l_brace;
|
|
||||||
if (NeedsInnerScope) EnterScope(Scope::DeclScope);
|
|
||||||
|
|
||||||
// Read the if condition.
|
|
||||||
StmtResult CondStmt = ParseStatement();
|
|
||||||
|
|
||||||
// Broken substmt shouldn't prevent the label from being added to the AST.
|
|
||||||
if (CondStmt.isInvalid)
|
|
||||||
CondStmt = Actions.ParseNullStmt(Tok.getLocation());
|
|
||||||
|
|
||||||
// Pop the 'if' scope if needed.
|
|
||||||
if (NeedsInnerScope) ExitScope();
|
|
||||||
|
|
||||||
// If it has an else, parse it.
|
|
||||||
SourceLocation ElseLoc;
|
|
||||||
StmtResult ElseStmt(false);
|
|
||||||
if (Tok.getKind() == tok::kw_else) {
|
|
||||||
ElseLoc = ConsumeToken();
|
|
||||||
|
|
||||||
// C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
|
|
||||||
// there is no compound stmt. C90 does not have this clause. We only do
|
|
||||||
// this if the body isn't a compound statement to avoid push/pop in common
|
|
||||||
// cases.
|
|
||||||
NeedsInnerScope = getLang().C99 && Tok.getKind() != tok::l_brace;
|
|
||||||
if (NeedsInnerScope) EnterScope(Scope::DeclScope);
|
|
||||||
|
|
||||||
ElseStmt = ParseStatement();
|
|
||||||
|
|
||||||
// Pop the 'else' scope if needed.
|
|
||||||
if (NeedsInnerScope) ExitScope();
|
|
||||||
|
|
||||||
if (ElseStmt.isInvalid)
|
|
||||||
ElseStmt = Actions.ParseNullStmt(ElseLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getLang().C99)
|
|
||||||
ExitScope();
|
|
||||||
|
|
||||||
return Actions.ParseIfStmt(IfLoc, CondExp.Val, CondStmt.Val,
|
|
||||||
ElseLoc, ElseStmt.Val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseSwitchStatement
|
|
||||||
/// switch-statement:
|
|
||||||
/// 'switch' '(' expression ')' statement
|
|
||||||
Parser::StmtResult Parser::ParseSwitchStatement() {
|
|
||||||
assert(Tok.getKind() == tok::kw_switch && "Not a switch stmt!");
|
|
||||||
SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'.
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::l_paren) {
|
|
||||||
Diag(Tok, diag::err_expected_lparen_after, "switch");
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// C99 6.8.4p3 - In C99, the switch statement is a block. This is
|
|
||||||
// not the case for C90. Start the switch scope.
|
|
||||||
if (getLang().C99)
|
|
||||||
EnterScope(Scope::BreakScope|Scope::DeclScope);
|
|
||||||
else
|
|
||||||
EnterScope(Scope::BreakScope);
|
|
||||||
|
|
||||||
// Parse the condition.
|
|
||||||
ExprResult Cond = ParseSimpleParenExpression();
|
|
||||||
|
|
||||||
if (Cond.isInvalid) {
|
|
||||||
ExitScope();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
StmtResult Switch = Actions.StartSwitchStmt(Cond.Val);
|
|
||||||
|
|
||||||
// C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if
|
|
||||||
// there is no compound stmt. C90 does not have this clause. We only do this
|
|
||||||
// if the body isn't a compound statement to avoid push/pop in common cases.
|
|
||||||
bool NeedsInnerScope = getLang().C99 && Tok.getKind() != tok::l_brace;
|
|
||||||
if (NeedsInnerScope) EnterScope(Scope::DeclScope);
|
|
||||||
|
|
||||||
// Read the body statement.
|
|
||||||
StmtResult Body = ParseStatement();
|
|
||||||
|
|
||||||
// Pop the body scope if needed.
|
|
||||||
if (NeedsInnerScope) ExitScope();
|
|
||||||
|
|
||||||
if (Body.isInvalid) {
|
|
||||||
Body = Actions.ParseNullStmt(Tok.getLocation());
|
|
||||||
// FIXME: Remove the case statement list from the Switch statement.
|
|
||||||
}
|
|
||||||
|
|
||||||
ExitScope();
|
|
||||||
|
|
||||||
return Actions.FinishSwitchStmt(SwitchLoc, Switch.Val, Body.Val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseWhileStatement
|
|
||||||
/// while-statement: [C99 6.8.5.1]
|
|
||||||
/// 'while' '(' expression ')' statement
|
|
||||||
Parser::StmtResult Parser::ParseWhileStatement() {
|
|
||||||
assert(Tok.getKind() == tok::kw_while && "Not a while stmt!");
|
|
||||||
SourceLocation WhileLoc = Tok.getLocation();
|
|
||||||
ConsumeToken(); // eat the 'while'.
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::l_paren) {
|
|
||||||
Diag(Tok, diag::err_expected_lparen_after, "while");
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// C99 6.8.5p5 - In C99, the while statement is a block. This is not
|
|
||||||
// the case for C90. Start the loop scope.
|
|
||||||
if (getLang().C99)
|
|
||||||
EnterScope(Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope);
|
|
||||||
else
|
|
||||||
EnterScope(Scope::BreakScope | Scope::ContinueScope);
|
|
||||||
|
|
||||||
// Parse the condition.
|
|
||||||
ExprResult Cond = ParseSimpleParenExpression();
|
|
||||||
|
|
||||||
// C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
|
|
||||||
// there is no compound stmt. C90 does not have this clause. We only do this
|
|
||||||
// if the body isn't a compound statement to avoid push/pop in common cases.
|
|
||||||
bool NeedsInnerScope = getLang().C99 && Tok.getKind() != tok::l_brace;
|
|
||||||
if (NeedsInnerScope) EnterScope(Scope::DeclScope);
|
|
||||||
|
|
||||||
// Read the body statement.
|
|
||||||
StmtResult Body = ParseStatement();
|
|
||||||
|
|
||||||
// Pop the body scope if needed.
|
|
||||||
if (NeedsInnerScope) ExitScope();
|
|
||||||
|
|
||||||
ExitScope();
|
|
||||||
|
|
||||||
if (Cond.isInvalid || Body.isInvalid) return true;
|
|
||||||
|
|
||||||
return Actions.ParseWhileStmt(WhileLoc, Cond.Val, Body.Val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseDoStatement
|
|
||||||
/// do-statement: [C99 6.8.5.2]
|
|
||||||
/// 'do' statement 'while' '(' expression ')' ';'
|
|
||||||
/// Note: this lets the caller parse the end ';'.
|
|
||||||
Parser::StmtResult Parser::ParseDoStatement() {
|
|
||||||
assert(Tok.getKind() == tok::kw_do && "Not a do stmt!");
|
|
||||||
SourceLocation DoLoc = ConsumeToken(); // eat the 'do'.
|
|
||||||
|
|
||||||
// C99 6.8.5p5 - In C99, the do statement is a block. This is not
|
|
||||||
// the case for C90. Start the loop scope.
|
|
||||||
if (getLang().C99)
|
|
||||||
EnterScope(Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope);
|
|
||||||
else
|
|
||||||
EnterScope(Scope::BreakScope | Scope::ContinueScope);
|
|
||||||
|
|
||||||
// C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
|
|
||||||
// there is no compound stmt. C90 does not have this clause. We only do this
|
|
||||||
// if the body isn't a compound statement to avoid push/pop in common cases.
|
|
||||||
bool NeedsInnerScope = getLang().C99 && Tok.getKind() != tok::l_brace;
|
|
||||||
if (NeedsInnerScope) EnterScope(Scope::DeclScope);
|
|
||||||
|
|
||||||
// Read the body statement.
|
|
||||||
StmtResult Body = ParseStatement();
|
|
||||||
|
|
||||||
// Pop the body scope if needed.
|
|
||||||
if (NeedsInnerScope) ExitScope();
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::kw_while) {
|
|
||||||
ExitScope();
|
|
||||||
Diag(Tok, diag::err_expected_while);
|
|
||||||
Diag(DoLoc, diag::err_matching, "do");
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
SourceLocation WhileLoc = ConsumeToken();
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::l_paren) {
|
|
||||||
ExitScope();
|
|
||||||
Diag(Tok, diag::err_expected_lparen_after, "do/while");
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the condition.
|
|
||||||
ExprResult Cond = ParseSimpleParenExpression();
|
|
||||||
|
|
||||||
ExitScope();
|
|
||||||
|
|
||||||
if (Cond.isInvalid || Body.isInvalid) return true;
|
|
||||||
|
|
||||||
return Actions.ParseDoStmt(DoLoc, Body.Val, WhileLoc, Cond.Val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseForStatement
|
|
||||||
/// for-statement: [C99 6.8.5.3]
|
|
||||||
/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
|
|
||||||
/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
|
|
||||||
Parser::StmtResult Parser::ParseForStatement() {
|
|
||||||
assert(Tok.getKind() == tok::kw_for && "Not a for stmt!");
|
|
||||||
SourceLocation ForLoc = ConsumeToken(); // eat the 'for'.
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::l_paren) {
|
|
||||||
Diag(Tok, diag::err_expected_lparen_after, "for");
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// C99 6.8.5p5 - In C99, the for statement is a block. This is not
|
|
||||||
// the case for C90. Start the loop scope.
|
|
||||||
if (getLang().C99)
|
|
||||||
EnterScope(Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope);
|
|
||||||
else
|
|
||||||
EnterScope(Scope::BreakScope | Scope::ContinueScope);
|
|
||||||
|
|
||||||
SourceLocation LParenLoc = ConsumeParen();
|
|
||||||
ExprResult Value;
|
|
||||||
|
|
||||||
StmtTy *FirstPart = 0;
|
|
||||||
ExprTy *SecondPart = 0;
|
|
||||||
StmtTy *ThirdPart = 0;
|
|
||||||
|
|
||||||
// Parse the first part of the for specifier.
|
|
||||||
if (Tok.getKind() == tok::semi) { // for (;
|
|
||||||
// no first part, eat the ';'.
|
|
||||||
ConsumeToken();
|
|
||||||
} else if (isDeclarationSpecifier()) { // for (int X = 4;
|
|
||||||
// Parse declaration, which eats the ';'.
|
|
||||||
if (!getLang().C99) // Use of C99-style for loops in C90 mode?
|
|
||||||
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
|
|
||||||
DeclTy *aBlockVarDecl = ParseDeclaration(Declarator::ForContext);
|
|
||||||
StmtResult stmtResult = Actions.ParseDeclStmt(aBlockVarDecl);
|
|
||||||
FirstPart = stmtResult.isInvalid ? 0 : stmtResult.Val;
|
|
||||||
} else {
|
|
||||||
Value = ParseExpression();
|
|
||||||
|
|
||||||
// Turn the expression into a stmt.
|
|
||||||
if (!Value.isInvalid) {
|
|
||||||
StmtResult R = Actions.ParseExprStmt(Value.Val);
|
|
||||||
if (!R.isInvalid)
|
|
||||||
FirstPart = R.Val;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Tok.getKind() == tok::semi) {
|
|
||||||
ConsumeToken();
|
|
||||||
} else {
|
|
||||||
if (!Value.isInvalid) Diag(Tok, diag::err_expected_semi_for);
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the second part of the for specifier.
|
|
||||||
if (Tok.getKind() == tok::semi) { // for (...;;
|
|
||||||
// no second part.
|
|
||||||
Value = ExprResult();
|
|
||||||
} else {
|
|
||||||
Value = ParseExpression();
|
|
||||||
if (!Value.isInvalid)
|
|
||||||
SecondPart = Value.Val;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Tok.getKind() == tok::semi) {
|
|
||||||
ConsumeToken();
|
|
||||||
} else {
|
|
||||||
if (!Value.isInvalid) Diag(Tok, diag::err_expected_semi_for);
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the third part of the for specifier.
|
|
||||||
if (Tok.getKind() == tok::r_paren) { // for (...;...;)
|
|
||||||
// no third part.
|
|
||||||
Value = ExprResult();
|
|
||||||
} else {
|
|
||||||
Value = ParseExpression();
|
|
||||||
if (!Value.isInvalid) {
|
|
||||||
// Turn the expression into a stmt.
|
|
||||||
StmtResult R = Actions.ParseExprStmt(Value.Val);
|
|
||||||
if (!R.isInvalid)
|
|
||||||
ThirdPart = R.Val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match the ')'.
|
|
||||||
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
|
||||||
|
|
||||||
// C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
|
|
||||||
// there is no compound stmt. C90 does not have this clause. We only do this
|
|
||||||
// if the body isn't a compound statement to avoid push/pop in common cases.
|
|
||||||
bool NeedsInnerScope = getLang().C99 && Tok.getKind() != tok::l_brace;
|
|
||||||
if (NeedsInnerScope) EnterScope(Scope::DeclScope);
|
|
||||||
|
|
||||||
// Read the body statement.
|
|
||||||
StmtResult Body = ParseStatement();
|
|
||||||
|
|
||||||
// Pop the body scope if needed.
|
|
||||||
if (NeedsInnerScope) ExitScope();
|
|
||||||
|
|
||||||
// Leave the for-scope.
|
|
||||||
ExitScope();
|
|
||||||
|
|
||||||
if (Body.isInvalid)
|
|
||||||
return Body;
|
|
||||||
|
|
||||||
return Actions.ParseForStmt(ForLoc, LParenLoc, FirstPart, SecondPart,
|
|
||||||
ThirdPart, RParenLoc, Body.Val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseGotoStatement
|
|
||||||
/// jump-statement:
|
|
||||||
/// 'goto' identifier ';'
|
|
||||||
/// [GNU] 'goto' '*' expression ';'
|
|
||||||
///
|
|
||||||
/// Note: this lets the caller parse the end ';'.
|
|
||||||
///
|
|
||||||
Parser::StmtResult Parser::ParseGotoStatement() {
|
|
||||||
assert(Tok.getKind() == tok::kw_goto && "Not a goto stmt!");
|
|
||||||
SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'.
|
|
||||||
|
|
||||||
StmtResult Res;
|
|
||||||
if (Tok.getKind() == tok::identifier) {
|
|
||||||
Res = Actions.ParseGotoStmt(GotoLoc, Tok.getLocation(),
|
|
||||||
Tok.getIdentifierInfo());
|
|
||||||
ConsumeToken();
|
|
||||||
} else if (Tok.getKind() == tok::star && !getLang().NoExtensions) {
|
|
||||||
// GNU indirect goto extension.
|
|
||||||
Diag(Tok, diag::ext_gnu_indirect_goto);
|
|
||||||
SourceLocation StarLoc = ConsumeToken();
|
|
||||||
ExprResult R = ParseExpression();
|
|
||||||
if (R.isInvalid) { // Skip to the semicolon, but don't consume it.
|
|
||||||
SkipUntil(tok::semi, false, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Res = Actions.ParseIndirectGotoStmt(GotoLoc, StarLoc, R.Val);
|
|
||||||
} else {
|
|
||||||
Diag(Tok, diag::err_expected_ident);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseContinueStatement
|
|
||||||
/// jump-statement:
|
|
||||||
/// 'continue' ';'
|
|
||||||
///
|
|
||||||
/// Note: this lets the caller parse the end ';'.
|
|
||||||
///
|
|
||||||
Parser::StmtResult Parser::ParseContinueStatement() {
|
|
||||||
SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'.
|
|
||||||
return Actions.ParseContinueStmt(ContinueLoc, CurScope);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseBreakStatement
|
|
||||||
/// jump-statement:
|
|
||||||
/// 'break' ';'
|
|
||||||
///
|
|
||||||
/// Note: this lets the caller parse the end ';'.
|
|
||||||
///
|
|
||||||
Parser::StmtResult Parser::ParseBreakStatement() {
|
|
||||||
SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'.
|
|
||||||
return Actions.ParseBreakStmt(BreakLoc, CurScope);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseReturnStatement
|
|
||||||
/// jump-statement:
|
|
||||||
/// 'return' expression[opt] ';'
|
|
||||||
Parser::StmtResult Parser::ParseReturnStatement() {
|
|
||||||
assert(Tok.getKind() == tok::kw_return && "Not a return stmt!");
|
|
||||||
SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'.
|
|
||||||
|
|
||||||
ExprResult R(0);
|
|
||||||
if (Tok.getKind() != tok::semi) {
|
|
||||||
R = ParseExpression();
|
|
||||||
if (R.isInvalid) { // Skip to the semicolon, but don't consume it.
|
|
||||||
SkipUntil(tok::semi, false, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Actions.ParseReturnStmt(ReturnLoc, R.Val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseAsmStatement - Parse a GNU extended asm statement.
|
|
||||||
/// [GNU] asm-statement:
|
|
||||||
/// 'asm' type-qualifier[opt] '(' asm-argument ')' ';'
|
|
||||||
///
|
|
||||||
/// [GNU] asm-argument:
|
|
||||||
/// asm-string-literal
|
|
||||||
/// asm-string-literal ':' asm-operands[opt]
|
|
||||||
/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
|
|
||||||
/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
|
|
||||||
/// ':' asm-clobbers
|
|
||||||
///
|
|
||||||
/// [GNU] asm-clobbers:
|
|
||||||
/// asm-string-literal
|
|
||||||
/// asm-clobbers ',' asm-string-literal
|
|
||||||
///
|
|
||||||
Parser::StmtResult Parser::ParseAsmStatement() {
|
|
||||||
assert(Tok.getKind() == tok::kw_asm && "Not an asm stmt");
|
|
||||||
ConsumeToken();
|
|
||||||
|
|
||||||
DeclSpec DS;
|
|
||||||
SourceLocation Loc = Tok.getLocation();
|
|
||||||
ParseTypeQualifierListOpt(DS);
|
|
||||||
|
|
||||||
// GNU asms accept, but warn, about type-qualifiers other than volatile.
|
|
||||||
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
|
|
||||||
Diag(Loc, diag::w_asm_qualifier_ignored, "const");
|
|
||||||
if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
|
|
||||||
Diag(Loc, diag::w_asm_qualifier_ignored, "restrict");
|
|
||||||
|
|
||||||
// Remember if this was a volatile asm.
|
|
||||||
//bool isVolatile = DS.TypeQualifiers & DeclSpec::TQ_volatile;
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::l_paren) {
|
|
||||||
Diag(Tok, diag::err_expected_lparen_after, "asm");
|
|
||||||
SkipUntil(tok::r_paren);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Loc = ConsumeParen();
|
|
||||||
|
|
||||||
ParseAsmStringLiteral();
|
|
||||||
|
|
||||||
// Parse Outputs, if present.
|
|
||||||
ParseAsmOperandsOpt();
|
|
||||||
|
|
||||||
// Parse Inputs, if present.
|
|
||||||
ParseAsmOperandsOpt();
|
|
||||||
|
|
||||||
// Parse the clobbers, if present.
|
|
||||||
if (Tok.getKind() == tok::colon) {
|
|
||||||
ConsumeToken();
|
|
||||||
|
|
||||||
if (isTokenStringLiteral()) {
|
|
||||||
// Parse the asm-string list for clobbers.
|
|
||||||
while (1) {
|
|
||||||
ParseAsmStringLiteral();
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::comma) break;
|
|
||||||
ConsumeToken();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MatchRHSPunctuation(tok::r_paren, Loc);
|
|
||||||
|
|
||||||
// FIXME: Implement action for asm parsing.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseAsmOperands - Parse the asm-operands production as used by
|
|
||||||
/// asm-statement. We also parse a leading ':' token. If the leading colon is
|
|
||||||
/// not present, we do not parse anything.
|
|
||||||
///
|
|
||||||
/// [GNU] asm-operands:
|
|
||||||
/// asm-operand
|
|
||||||
/// asm-operands ',' asm-operand
|
|
||||||
///
|
|
||||||
/// [GNU] asm-operand:
|
|
||||||
/// asm-string-literal '(' expression ')'
|
|
||||||
/// '[' identifier ']' asm-string-literal '(' expression ')'
|
|
||||||
///
|
|
||||||
void Parser::ParseAsmOperandsOpt() {
|
|
||||||
// Only do anything if this operand is present.
|
|
||||||
if (Tok.getKind() != tok::colon) return;
|
|
||||||
ConsumeToken();
|
|
||||||
|
|
||||||
// 'asm-operands' isn't present?
|
|
||||||
if (!isTokenStringLiteral() && Tok.getKind() != tok::l_square)
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
// Read the [id] if present.
|
|
||||||
if (Tok.getKind() == tok::l_square) {
|
|
||||||
SourceLocation Loc = ConsumeBracket();
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::identifier) {
|
|
||||||
Diag(Tok, diag::err_expected_ident);
|
|
||||||
SkipUntil(tok::r_paren);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MatchRHSPunctuation(tok::r_square, Loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
ParseAsmStringLiteral();
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::l_paren) {
|
|
||||||
Diag(Tok, diag::err_expected_lparen_after, "asm operand");
|
|
||||||
SkipUntil(tok::r_paren);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the parenthesized expression.
|
|
||||||
ExprResult Res = ParseSimpleParenExpression();
|
|
||||||
if (Res.isInvalid) {
|
|
||||||
SkipUntil(tok::r_paren);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eat the comma and continue parsing if it exists.
|
|
||||||
if (Tok.getKind() != tok::comma) return;
|
|
||||||
ConsumeToken();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,647 +0,0 @@
|
|||||||
//===--- Parser.cpp - C Language Family Parser ----------------------------===//
|
|
||||||
//
|
|
||||||
// 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 Parser interfaces.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Parse/Parser.h"
|
|
||||||
#include "clang/Parse/DeclSpec.h"
|
|
||||||
#include "clang/Parse/Scope.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
Parser::Parser(Preprocessor &pp, Action &actions)
|
|
||||||
: PP(pp), Actions(actions), Diags(PP.getDiagnostics()) {
|
|
||||||
Tok.setKind(tok::eof);
|
|
||||||
CurScope = 0;
|
|
||||||
NumCachedScopes = 0;
|
|
||||||
ParenCount = BracketCount = BraceCount = 0;
|
|
||||||
ObjcImpDecl = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Out-of-line virtual destructor to provide home for Action class.
|
|
||||||
Action::~Action() {}
|
|
||||||
|
|
||||||
|
|
||||||
void Parser::Diag(SourceLocation Loc, unsigned DiagID,
|
|
||||||
const std::string &Msg) {
|
|
||||||
Diags.Report(Loc, DiagID, &Msg, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'),
|
|
||||||
/// this helper function matches and consumes the specified RHS token if
|
|
||||||
/// present. If not present, it emits the specified diagnostic indicating
|
|
||||||
/// that the parser failed to match the RHS of the token at LHSLoc. LHSName
|
|
||||||
/// should be the name of the unmatched LHS token.
|
|
||||||
SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok,
|
|
||||||
SourceLocation LHSLoc) {
|
|
||||||
|
|
||||||
if (Tok.getKind() == RHSTok)
|
|
||||||
return ConsumeAnyToken();
|
|
||||||
|
|
||||||
SourceLocation R = Tok.getLocation();
|
|
||||||
const char *LHSName = "unknown";
|
|
||||||
diag::kind DID = diag::err_parse_error;
|
|
||||||
switch (RHSTok) {
|
|
||||||
default: break;
|
|
||||||
case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break;
|
|
||||||
case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break;
|
|
||||||
case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break;
|
|
||||||
case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break;
|
|
||||||
}
|
|
||||||
Diag(Tok, DID);
|
|
||||||
Diag(LHSLoc, diag::err_matching, LHSName);
|
|
||||||
SkipUntil(RHSTok);
|
|
||||||
return R;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the
|
|
||||||
/// input. If so, it is consumed and false is returned.
|
|
||||||
///
|
|
||||||
/// If the input is malformed, this emits the specified diagnostic. Next, if
|
|
||||||
/// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is
|
|
||||||
/// returned.
|
|
||||||
bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
|
|
||||||
const char *Msg, tok::TokenKind SkipToTok) {
|
|
||||||
if (Tok.getKind() == ExpectedTok) {
|
|
||||||
ConsumeAnyToken();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Diag(Tok, DiagID, Msg);
|
|
||||||
if (SkipToTok != tok::unknown)
|
|
||||||
SkipUntil(SkipToTok);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Error recovery.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// SkipUntil - Read tokens until we get to the specified token, then consume
|
|
||||||
/// it (unless DontConsume is true). Because we cannot guarantee that the
|
|
||||||
/// token will ever occur, this skips to the next token, or to some likely
|
|
||||||
/// good stopping point. If StopAtSemi is true, skipping will stop at a ';'
|
|
||||||
/// character.
|
|
||||||
///
|
|
||||||
/// If SkipUntil finds the specified token, it returns true, otherwise it
|
|
||||||
/// returns false.
|
|
||||||
bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
|
|
||||||
bool StopAtSemi, bool DontConsume) {
|
|
||||||
// We always want this function to skip at least one token if the first token
|
|
||||||
// isn't T and if not at EOF.
|
|
||||||
bool isFirstTokenSkipped = true;
|
|
||||||
while (1) {
|
|
||||||
// If we found one of the tokens, stop and return true.
|
|
||||||
for (unsigned i = 0; i != NumToks; ++i) {
|
|
||||||
if (Tok.getKind() == Toks[i]) {
|
|
||||||
if (DontConsume) {
|
|
||||||
// Noop, don't consume the token.
|
|
||||||
} else {
|
|
||||||
ConsumeAnyToken();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (Tok.getKind()) {
|
|
||||||
case tok::eof:
|
|
||||||
// Ran out of tokens.
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case tok::l_paren:
|
|
||||||
// Recursively skip properly-nested parens.
|
|
||||||
ConsumeParen();
|
|
||||||
SkipUntil(tok::r_paren, false);
|
|
||||||
break;
|
|
||||||
case tok::l_square:
|
|
||||||
// Recursively skip properly-nested square brackets.
|
|
||||||
ConsumeBracket();
|
|
||||||
SkipUntil(tok::r_square, false);
|
|
||||||
break;
|
|
||||||
case tok::l_brace:
|
|
||||||
// Recursively skip properly-nested braces.
|
|
||||||
ConsumeBrace();
|
|
||||||
SkipUntil(tok::r_brace, false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Okay, we found a ']' or '}' or ')', which we think should be balanced.
|
|
||||||
// Since the user wasn't looking for this token (if they were, it would
|
|
||||||
// already be handled), this isn't balanced. If there is a LHS token at a
|
|
||||||
// higher level, we will assume that this matches the unbalanced token
|
|
||||||
// and return it. Otherwise, this is a spurious RHS token, which we skip.
|
|
||||||
case tok::r_paren:
|
|
||||||
if (ParenCount && !isFirstTokenSkipped)
|
|
||||||
return false; // Matches something.
|
|
||||||
ConsumeParen();
|
|
||||||
break;
|
|
||||||
case tok::r_square:
|
|
||||||
if (BracketCount && !isFirstTokenSkipped)
|
|
||||||
return false; // Matches something.
|
|
||||||
ConsumeBracket();
|
|
||||||
break;
|
|
||||||
case tok::r_brace:
|
|
||||||
if (BraceCount && !isFirstTokenSkipped)
|
|
||||||
return false; // Matches something.
|
|
||||||
ConsumeBrace();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case tok::string_literal:
|
|
||||||
case tok::wide_string_literal:
|
|
||||||
ConsumeStringToken();
|
|
||||||
break;
|
|
||||||
case tok::semi:
|
|
||||||
if (StopAtSemi)
|
|
||||||
return false;
|
|
||||||
// FALL THROUGH.
|
|
||||||
default:
|
|
||||||
// Skip this token.
|
|
||||||
ConsumeToken();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
isFirstTokenSkipped = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Scope manipulation
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// EnterScope - Start a new scope.
|
|
||||||
void Parser::EnterScope(unsigned ScopeFlags) {
|
|
||||||
if (NumCachedScopes) {
|
|
||||||
Scope *N = ScopeCache[--NumCachedScopes];
|
|
||||||
N->Init(CurScope, ScopeFlags);
|
|
||||||
CurScope = N;
|
|
||||||
} else {
|
|
||||||
CurScope = new Scope(CurScope, ScopeFlags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ExitScope - Pop a scope off the scope stack.
|
|
||||||
void Parser::ExitScope() {
|
|
||||||
assert(CurScope && "Scope imbalance!");
|
|
||||||
|
|
||||||
// Inform the actions module that this scope is going away.
|
|
||||||
Actions.PopScope(Tok.getLocation(), CurScope);
|
|
||||||
|
|
||||||
Scope *OldScope = CurScope;
|
|
||||||
CurScope = OldScope->getParent();
|
|
||||||
|
|
||||||
if (NumCachedScopes == ScopeCacheSize)
|
|
||||||
delete OldScope;
|
|
||||||
else
|
|
||||||
ScopeCache[NumCachedScopes++] = OldScope;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// C99 6.9: External Definitions.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
Parser::~Parser() {
|
|
||||||
// If we still have scopes active, delete the scope tree.
|
|
||||||
delete CurScope;
|
|
||||||
|
|
||||||
// Free the scope cache.
|
|
||||||
for (unsigned i = 0, e = NumCachedScopes; i != e; ++i)
|
|
||||||
delete ScopeCache[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize - Warm up the parser.
|
|
||||||
///
|
|
||||||
void Parser::Initialize() {
|
|
||||||
// Prime the lexer look-ahead.
|
|
||||||
ConsumeToken();
|
|
||||||
|
|
||||||
// Create the translation unit scope. Install it as the current scope.
|
|
||||||
assert(CurScope == 0 && "A scope is already active?");
|
|
||||||
EnterScope(Scope::DeclScope);
|
|
||||||
|
|
||||||
// Install builtin types.
|
|
||||||
// TODO: Move this someplace more useful.
|
|
||||||
{
|
|
||||||
const char *Dummy;
|
|
||||||
|
|
||||||
//__builtin_va_list
|
|
||||||
DeclSpec DS;
|
|
||||||
bool Error = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, SourceLocation(),
|
|
||||||
Dummy);
|
|
||||||
|
|
||||||
// TODO: add a 'TST_builtin' type?
|
|
||||||
Error |= DS.SetTypeSpecType(DeclSpec::TST_int, SourceLocation(), Dummy);
|
|
||||||
assert(!Error && "Error setting up __builtin_va_list!");
|
|
||||||
|
|
||||||
Declarator D(DS, Declarator::FileContext);
|
|
||||||
D.SetIdentifier(PP.getIdentifierInfo("__builtin_va_list"),SourceLocation());
|
|
||||||
Actions.ParseDeclarator(CurScope, D, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Tok.getKind() == tok::eof &&
|
|
||||||
!getLang().CPlusPlus) // Empty source file is an extension in C
|
|
||||||
Diag(Tok, diag::ext_empty_source_file);
|
|
||||||
|
|
||||||
// Initialization for Objective-C context sensitive keywords recognition.
|
|
||||||
// Referenced in Parser::isObjCTypeQualifier.
|
|
||||||
if (getLang().ObjC1) {
|
|
||||||
ObjcTypeQuals[objc_in] = &PP.getIdentifierTable().get("in");
|
|
||||||
ObjcTypeQuals[objc_out] = &PP.getIdentifierTable().get("out");
|
|
||||||
ObjcTypeQuals[objc_inout] = &PP.getIdentifierTable().get("inout");
|
|
||||||
ObjcTypeQuals[objc_oneway] = &PP.getIdentifierTable().get("oneway");
|
|
||||||
ObjcTypeQuals[objc_bycopy] = &PP.getIdentifierTable().get("bycopy");
|
|
||||||
ObjcTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref");
|
|
||||||
}
|
|
||||||
if (getLang().ObjC2) {
|
|
||||||
ObjcPropertyAttrs[objc_readonly] = &PP.getIdentifierTable().get("readonly");
|
|
||||||
ObjcPropertyAttrs[objc_getter] = &PP.getIdentifierTable().get("getter");
|
|
||||||
ObjcPropertyAttrs[objc_setter] = &PP.getIdentifierTable().get("setter");
|
|
||||||
ObjcPropertyAttrs[objc_assign] = &PP.getIdentifierTable().get("assign");
|
|
||||||
ObjcPropertyAttrs[objc_readwrite] =
|
|
||||||
&PP.getIdentifierTable().get("readwrite");
|
|
||||||
ObjcPropertyAttrs[objc_retain] = &PP.getIdentifierTable().get("retain");
|
|
||||||
ObjcPropertyAttrs[objc_copy] = &PP.getIdentifierTable().get("copy");
|
|
||||||
ObjcPropertyAttrs[objc_nonatomic] =
|
|
||||||
&PP.getIdentifierTable().get("nonatomic");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
|
|
||||||
/// action tells us to. This returns true if the EOF was encountered.
|
|
||||||
bool Parser::ParseTopLevelDecl(DeclTy*& Result) {
|
|
||||||
Result = 0;
|
|
||||||
if (Tok.getKind() == tok::eof) return true;
|
|
||||||
|
|
||||||
Result = ParseExternalDeclaration();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finalize - Shut down the parser.
|
|
||||||
///
|
|
||||||
void Parser::Finalize() {
|
|
||||||
ExitScope();
|
|
||||||
assert(CurScope == 0 && "Scope imbalance!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseTranslationUnit:
|
|
||||||
/// translation-unit: [C99 6.9]
|
|
||||||
/// external-declaration
|
|
||||||
/// translation-unit external-declaration
|
|
||||||
void Parser::ParseTranslationUnit() {
|
|
||||||
Initialize();
|
|
||||||
|
|
||||||
DeclTy *Res;
|
|
||||||
while (!ParseTopLevelDecl(Res))
|
|
||||||
/*parse them all*/;
|
|
||||||
|
|
||||||
Finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseExternalDeclaration:
|
|
||||||
/// external-declaration: [C99 6.9]
|
|
||||||
/// function-definition
|
|
||||||
/// declaration
|
|
||||||
/// [EXT] ';'
|
|
||||||
/// [GNU] asm-definition
|
|
||||||
/// [GNU] __extension__ external-declaration
|
|
||||||
/// [OBJC] objc-class-definition
|
|
||||||
/// [OBJC] objc-class-declaration
|
|
||||||
/// [OBJC] objc-alias-declaration
|
|
||||||
/// [OBJC] objc-protocol-definition
|
|
||||||
/// [OBJC] objc-method-definition
|
|
||||||
/// [OBJC] @end
|
|
||||||
///
|
|
||||||
/// [GNU] asm-definition:
|
|
||||||
/// simple-asm-expr ';'
|
|
||||||
///
|
|
||||||
Parser::DeclTy *Parser::ParseExternalDeclaration() {
|
|
||||||
switch (Tok.getKind()) {
|
|
||||||
case tok::semi:
|
|
||||||
Diag(Tok, diag::ext_top_level_semi);
|
|
||||||
ConsumeToken();
|
|
||||||
// TODO: Invoke action for top-level semicolon.
|
|
||||||
return 0;
|
|
||||||
case tok::kw___extension__: {
|
|
||||||
ConsumeToken();
|
|
||||||
// FIXME: Disable extension warnings.
|
|
||||||
DeclTy *RV = ParseExternalDeclaration();
|
|
||||||
// FIXME: Restore extension warnings.
|
|
||||||
return RV;
|
|
||||||
}
|
|
||||||
case tok::kw_asm:
|
|
||||||
ParseSimpleAsm();
|
|
||||||
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
|
|
||||||
"top-level asm block");
|
|
||||||
// TODO: Invoke action for top-level asm.
|
|
||||||
return 0;
|
|
||||||
case tok::at:
|
|
||||||
// @ is not a legal token unless objc is enabled, no need to check.
|
|
||||||
return ParseObjCAtDirectives();
|
|
||||||
case tok::minus:
|
|
||||||
if (getLang().ObjC1) {
|
|
||||||
ParseObjCInstanceMethodDefinition();
|
|
||||||
} else {
|
|
||||||
Diag(Tok, diag::err_expected_external_declaration);
|
|
||||||
ConsumeToken();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
case tok::plus:
|
|
||||||
if (getLang().ObjC1) {
|
|
||||||
ParseObjCClassMethodDefinition();
|
|
||||||
} else {
|
|
||||||
Diag(Tok, diag::err_expected_external_declaration);
|
|
||||||
ConsumeToken();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
case tok::kw_namespace:
|
|
||||||
case tok::kw_typedef:
|
|
||||||
// A function definition cannot start with a these keywords.
|
|
||||||
return ParseDeclaration(Declarator::FileContext);
|
|
||||||
default:
|
|
||||||
// We can't tell whether this is a function-definition or declaration yet.
|
|
||||||
return ParseDeclarationOrFunctionDefinition();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or
|
|
||||||
/// a declaration. We can't tell which we have until we read up to the
|
|
||||||
/// compound-statement in function-definition.
|
|
||||||
///
|
|
||||||
/// function-definition: [C99 6.9.1]
|
|
||||||
/// declaration-specifiers[opt] declarator declaration-list[opt]
|
|
||||||
/// compound-statement
|
|
||||||
/// declaration: [C99 6.7]
|
|
||||||
/// declaration-specifiers init-declarator-list[opt] ';'
|
|
||||||
/// [!C99] init-declarator-list ';' [TODO: warn in c99 mode]
|
|
||||||
/// [OMP] threadprivate-directive [TODO]
|
|
||||||
///
|
|
||||||
Parser::DeclTy *Parser::ParseDeclarationOrFunctionDefinition() {
|
|
||||||
// Parse the common declaration-specifiers piece.
|
|
||||||
DeclSpec DS;
|
|
||||||
ParseDeclarationSpecifiers(DS);
|
|
||||||
|
|
||||||
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
|
|
||||||
// declaration-specifiers init-declarator-list[opt] ';'
|
|
||||||
if (Tok.getKind() == tok::semi) {
|
|
||||||
ConsumeToken();
|
|
||||||
return Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ObjC2 allows prefix attributes on class interfaces.
|
|
||||||
if (getLang().ObjC2 && Tok.getKind() == tok::at) {
|
|
||||||
SourceLocation AtLoc = ConsumeToken(); // the "@"
|
|
||||||
if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_interface)
|
|
||||||
return ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the first declarator.
|
|
||||||
Declarator DeclaratorInfo(DS, Declarator::FileContext);
|
|
||||||
ParseDeclarator(DeclaratorInfo);
|
|
||||||
// Error parsing the declarator?
|
|
||||||
if (DeclaratorInfo.getIdentifier() == 0) {
|
|
||||||
// If so, skip until the semi-colon or a }.
|
|
||||||
SkipUntil(tok::r_brace, true);
|
|
||||||
if (Tok.getKind() == tok::semi)
|
|
||||||
ConsumeToken();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the declarator is the start of a function definition, handle it.
|
|
||||||
if (Tok.getKind() == tok::equal || // int X()= -> not a function def
|
|
||||||
Tok.getKind() == tok::comma || // int X(), -> not a function def
|
|
||||||
Tok.getKind() == tok::semi || // int X(); -> not a function def
|
|
||||||
Tok.getKind() == tok::kw_asm || // int X() __asm__ -> not a fn def
|
|
||||||
Tok.getKind() == tok::kw___attribute) {// int X() __attr__ -> not a fn def
|
|
||||||
// FALL THROUGH.
|
|
||||||
} else if (DeclaratorInfo.isFunctionDeclarator() &&
|
|
||||||
(Tok.getKind() == tok::l_brace || // int X() {}
|
|
||||||
isDeclarationSpecifier())) { // int X(f) int f; {}
|
|
||||||
return ParseFunctionDefinition(DeclaratorInfo);
|
|
||||||
} else {
|
|
||||||
if (DeclaratorInfo.isFunctionDeclarator())
|
|
||||||
Diag(Tok, diag::err_expected_fn_body);
|
|
||||||
else
|
|
||||||
Diag(Tok, diag::err_expected_after_declarator);
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the init-declarator-list for a normal declaration.
|
|
||||||
return ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseFunctionDefinition - We parsed and verified that the specified
|
|
||||||
/// Declarator is well formed. If this is a K&R-style function, read the
|
|
||||||
/// parameters declaration-list, then start the compound-statement.
|
|
||||||
///
|
|
||||||
/// declaration-specifiers[opt] declarator declaration-list[opt]
|
|
||||||
/// compound-statement [TODO]
|
|
||||||
///
|
|
||||||
Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) {
|
|
||||||
const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0);
|
|
||||||
assert(FnTypeInfo.Kind == DeclaratorChunk::Function &&
|
|
||||||
"This isn't a function declarator!");
|
|
||||||
const DeclaratorChunk::FunctionTypeInfo &FTI = FnTypeInfo.Fun;
|
|
||||||
|
|
||||||
// If this declaration was formed with a K&R-style identifier list for the
|
|
||||||
// arguments, parse declarations for all of the args next.
|
|
||||||
// int foo(a,b) int a; float b; {}
|
|
||||||
if (!FTI.hasPrototype && FTI.NumArgs != 0)
|
|
||||||
ParseKNRParamDeclarations(D);
|
|
||||||
|
|
||||||
// Enter a scope for the function body.
|
|
||||||
EnterScope(Scope::FnScope|Scope::DeclScope);
|
|
||||||
|
|
||||||
// Tell the actions module that we have entered a function definition with the
|
|
||||||
// specified Declarator for the function.
|
|
||||||
DeclTy *Res = Actions.ParseStartOfFunctionDef(CurScope, D);
|
|
||||||
|
|
||||||
|
|
||||||
// We should have an opening brace now.
|
|
||||||
if (Tok.getKind() != tok::l_brace) {
|
|
||||||
Diag(Tok, diag::err_expected_fn_body);
|
|
||||||
|
|
||||||
// Skip over garbage, until we get to '{'. Don't eat the '{'.
|
|
||||||
SkipUntil(tok::l_brace, true, true);
|
|
||||||
|
|
||||||
// If we didn't find the '{', bail out.
|
|
||||||
if (Tok.getKind() != tok::l_brace) {
|
|
||||||
ExitScope();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not enter a scope for the brace, as the arguments are in the same scope
|
|
||||||
// (the function body) as the body itself. Instead, just read the statement
|
|
||||||
// list and put it into a CompoundStmt for safe keeping.
|
|
||||||
StmtResult FnBody = ParseCompoundStatementBody();
|
|
||||||
if (FnBody.isInvalid) {
|
|
||||||
ExitScope();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Leave the function body scope.
|
|
||||||
ExitScope();
|
|
||||||
|
|
||||||
// TODO: Pass argument information.
|
|
||||||
return Actions.ParseFunctionDefBody(Res, FnBody.Val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides
|
|
||||||
/// types for a function with a K&R-style identifier list for arguments.
|
|
||||||
void Parser::ParseKNRParamDeclarations(Declarator &D) {
|
|
||||||
// We know that the top-level of this declarator is a function.
|
|
||||||
DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
|
|
||||||
|
|
||||||
// Read all the argument declarations.
|
|
||||||
while (isDeclarationSpecifier()) {
|
|
||||||
SourceLocation DSStart = Tok.getLocation();
|
|
||||||
|
|
||||||
// Parse the common declaration-specifiers piece.
|
|
||||||
DeclSpec DS;
|
|
||||||
ParseDeclarationSpecifiers(DS);
|
|
||||||
|
|
||||||
// C99 6.9.1p6: 'each declaration in the declaration list shall have at
|
|
||||||
// least one declarator'.
|
|
||||||
// NOTE: GCC just makes this an ext-warn. It's not clear what it does with
|
|
||||||
// the declarations though. It's trivial to ignore them, really hard to do
|
|
||||||
// anything else with them.
|
|
||||||
if (Tok.getKind() == tok::semi) {
|
|
||||||
Diag(DSStart, diag::err_declaration_does_not_declare_param);
|
|
||||||
ConsumeToken();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// C99 6.9.1p6: Declarations shall contain no storage-class specifiers other
|
|
||||||
// than register.
|
|
||||||
if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
|
|
||||||
DS.getStorageClassSpec() != DeclSpec::SCS_register) {
|
|
||||||
Diag(DS.getStorageClassSpecLoc(),
|
|
||||||
diag::err_invalid_storage_class_in_func_decl);
|
|
||||||
DS.ClearStorageClassSpecs();
|
|
||||||
}
|
|
||||||
if (DS.isThreadSpecified()) {
|
|
||||||
Diag(DS.getThreadSpecLoc(),
|
|
||||||
diag::err_invalid_storage_class_in_func_decl);
|
|
||||||
DS.ClearStorageClassSpecs();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the first declarator attached to this declspec.
|
|
||||||
Declarator ParmDeclarator(DS, Declarator::KNRTypeListContext);
|
|
||||||
ParseDeclarator(ParmDeclarator);
|
|
||||||
|
|
||||||
// Handle the full declarator list.
|
|
||||||
while (1) {
|
|
||||||
DeclTy *AttrList;
|
|
||||||
// If attributes are present, parse them.
|
|
||||||
if (Tok.getKind() == tok::kw___attribute)
|
|
||||||
// FIXME: attach attributes too.
|
|
||||||
AttrList = ParseAttributes();
|
|
||||||
|
|
||||||
// Ask the actions module to compute the type for this declarator.
|
|
||||||
Action::TypeResult TR =
|
|
||||||
Actions.ParseParamDeclaratorType(CurScope, ParmDeclarator);
|
|
||||||
|
|
||||||
if (!TR.isInvalid &&
|
|
||||||
// A missing identifier has already been diagnosed.
|
|
||||||
ParmDeclarator.getIdentifier()) {
|
|
||||||
|
|
||||||
// Scan the argument list looking for the correct param to apply this
|
|
||||||
// type.
|
|
||||||
for (unsigned i = 0; ; ++i) {
|
|
||||||
// C99 6.9.1p6: those declarators shall declare only identifiers from
|
|
||||||
// the identifier list.
|
|
||||||
if (i == FTI.NumArgs) {
|
|
||||||
Diag(ParmDeclarator.getIdentifierLoc(), diag::err_no_matching_param,
|
|
||||||
ParmDeclarator.getIdentifier()->getName());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) {
|
|
||||||
// Reject redefinitions of parameters.
|
|
||||||
if (FTI.ArgInfo[i].TypeInfo) {
|
|
||||||
Diag(ParmDeclarator.getIdentifierLoc(),
|
|
||||||
diag::err_param_redefinition,
|
|
||||||
ParmDeclarator.getIdentifier()->getName());
|
|
||||||
} else {
|
|
||||||
FTI.ArgInfo[i].TypeInfo = TR.Val;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we don't have a comma, it is either the end of the list (a ';') or
|
|
||||||
// an error, bail out.
|
|
||||||
if (Tok.getKind() != tok::comma)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Consume the comma.
|
|
||||||
ConsumeToken();
|
|
||||||
|
|
||||||
// Parse the next declarator.
|
|
||||||
ParmDeclarator.clear();
|
|
||||||
ParseDeclarator(ParmDeclarator);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Tok.getKind() == tok::semi) {
|
|
||||||
ConsumeToken();
|
|
||||||
} else {
|
|
||||||
Diag(Tok, diag::err_parse_error);
|
|
||||||
// Skip to end of block or statement
|
|
||||||
SkipUntil(tok::semi, true);
|
|
||||||
if (Tok.getKind() == tok::semi)
|
|
||||||
ConsumeToken();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The actions module must verify that all arguments were declared.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// ParseAsmStringLiteral - This is just a normal string-literal, but is not
|
|
||||||
/// allowed to be a wide string, and is not subject to character translation.
|
|
||||||
///
|
|
||||||
/// [GNU] asm-string-literal:
|
|
||||||
/// string-literal
|
|
||||||
///
|
|
||||||
void Parser::ParseAsmStringLiteral() {
|
|
||||||
if (!isTokenStringLiteral()) {
|
|
||||||
Diag(Tok, diag::err_expected_string_literal);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExprResult Res = ParseStringLiteralExpression();
|
|
||||||
if (Res.isInvalid) return;
|
|
||||||
|
|
||||||
// TODO: Diagnose: wide string literal in 'asm'
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseSimpleAsm
|
|
||||||
///
|
|
||||||
/// [GNU] simple-asm-expr:
|
|
||||||
/// 'asm' '(' asm-string-literal ')'
|
|
||||||
///
|
|
||||||
void Parser::ParseSimpleAsm() {
|
|
||||||
assert(Tok.getKind() == tok::kw_asm && "Not an asm!");
|
|
||||||
ConsumeToken();
|
|
||||||
|
|
||||||
if (Tok.getKind() != tok::l_paren) {
|
|
||||||
Diag(Tok, diag::err_expected_lparen_after, "asm");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLocation Loc = ConsumeParen();
|
|
||||||
|
|
||||||
ParseAsmStringLiteral();
|
|
||||||
|
|
||||||
MatchRHSPunctuation(tok::r_paren, Loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
180
clang/README.txt
180
clang/README.txt
@@ -1,180 +0,0 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// C Language Family Front-end
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
Chris Lattner
|
|
||||||
|
|
||||||
I. Introduction:
|
|
||||||
|
|
||||||
clang: noun
|
|
||||||
1. A loud, resonant, metallic sound.
|
|
||||||
2. The strident call of a crane or goose.
|
|
||||||
3. C-language family front-end toolkit.
|
|
||||||
|
|
||||||
The world needs better compiler tools, tools which are built as libraries. This
|
|
||||||
design point allows reuse of the tools in new and novel ways. However, building
|
|
||||||
the tools as libraries isn't enough: they must have clean APIs, be as
|
|
||||||
decoupled from each other as possible, and be easy to modify/extend. This
|
|
||||||
requires clean layering, decent design, and avoiding tying the libraries to a
|
|
||||||
specific use. Oh yeah, did I mention that we want the resultant libraries to
|
|
||||||
be as fast as possible? :)
|
|
||||||
|
|
||||||
This front-end is built as a component of the LLVM toolkit that can be used
|
|
||||||
with the LLVM backend or independently of it. In this spirit, the API has been
|
|
||||||
carefully designed as the following components:
|
|
||||||
|
|
||||||
libsupport - Basic support library, reused from LLVM.
|
|
||||||
libsystem - System abstraction library, reused from LLVM.
|
|
||||||
|
|
||||||
libbasic - Diagnostics, SourceLocations, SourceBuffer abstraction,
|
|
||||||
file system caching for input source files. This depends on
|
|
||||||
libsupport and libsystem.
|
|
||||||
libast - Provides classes to represent the C AST, the C type system,
|
|
||||||
builtin functions, and various helpers for analyzing and
|
|
||||||
manipulating the AST (visitors, pretty printers, etc). This
|
|
||||||
library depends on libbasic.
|
|
||||||
|
|
||||||
liblex - C/C++/ObjC lexing and preprocessing, identifier hash table,
|
|
||||||
pragma handling, tokens, and macros. This depends on libbasic.
|
|
||||||
libparse - C (for now) parsing and local semantic analysis. This library
|
|
||||||
invokes coarse-grained 'Actions' provided by the client to do
|
|
||||||
stuff (e.g. libsema builds ASTs). This depends on liblex.
|
|
||||||
libsema - Provides a set of parser actions to build a standardized AST
|
|
||||||
for programs. AST's are 'streamed' out a top-level declaration
|
|
||||||
at a time, allowing clients to use decl-at-a-time processing,
|
|
||||||
build up entire translation units, or even build 'whole
|
|
||||||
program' ASTs depending on how they use the APIs. This depends
|
|
||||||
on libast and libparse.
|
|
||||||
|
|
||||||
libcodegen - Lower the AST to LLVM IR for optimization & codegen. Depends
|
|
||||||
on libast.
|
|
||||||
clang - An example driver, client of the libraries at various levels.
|
|
||||||
This depends on all these libraries, and on LLVM VMCore.
|
|
||||||
|
|
||||||
This front-end has been intentionally built as a DAG of libraries, making it
|
|
||||||
easy to reuse individual parts or replace pieces if desired. For example, to
|
|
||||||
build a preprocessor, you take the Basic and Lexer libraries. If you want an
|
|
||||||
indexer, you take those plus the Parser library and provide some actions for
|
|
||||||
indexing. If you want a refactoring, static analysis, or source-to-source
|
|
||||||
compiler tool, it makes sense to take those plus the AST building and semantic
|
|
||||||
analyzer library. Finally, if you want to use this with the LLVM backend,
|
|
||||||
you'd take these components plus the AST to LLVM lowering code.
|
|
||||||
|
|
||||||
In the future I hope this toolkit will grow to include new and interesting
|
|
||||||
components, including a C++ front-end, ObjC support, and a whole lot of other
|
|
||||||
things.
|
|
||||||
|
|
||||||
Finally, it should be pointed out that the goal here is to build something that
|
|
||||||
is high-quality and industrial-strength: all the obnoxious features of the C
|
|
||||||
family must be correctly supported (trigraphs, preprocessor arcana, K&R-style
|
|
||||||
prototypes, GCC/MS extensions, etc). It cannot be used if it is not 'real'.
|
|
||||||
|
|
||||||
|
|
||||||
II. Usage of clang driver:
|
|
||||||
|
|
||||||
* Basic Command-Line Options:
|
|
||||||
- Help: clang --help
|
|
||||||
- Standard GCC options accepted: -E, -I*, -i*, -pedantic, -std=c90, etc.
|
|
||||||
- To make diagnostics more gcc-like: -fno-caret-diagnostics -fno-show-column
|
|
||||||
- Enable metric printing: -stats
|
|
||||||
|
|
||||||
* -fsyntax-only is currently the default mode.
|
|
||||||
|
|
||||||
* -E mode works the same way as GCC.
|
|
||||||
|
|
||||||
* -Eonly mode does all preprocessing, but does not print the output,
|
|
||||||
useful for timing the preprocessor.
|
|
||||||
|
|
||||||
* -fsyntax-only is currently partially implemented, lacking some
|
|
||||||
semantic analysis (some errors and warnings are not produced).
|
|
||||||
|
|
||||||
* -parse-noop parses code without building an AST. This is useful
|
|
||||||
for timing the cost of the parser without including AST building
|
|
||||||
time.
|
|
||||||
|
|
||||||
* -parse-ast builds ASTs, but doesn't print them. This is most
|
|
||||||
useful for timing AST building vs -parse-noop.
|
|
||||||
|
|
||||||
* -parse-ast-print pretty prints most expression and statements nodes.
|
|
||||||
|
|
||||||
* -parse-ast-check checks that diagnostic messages that are expected
|
|
||||||
are reported and that those which are reported are expected.
|
|
||||||
|
|
||||||
* -dump-cfg builds ASTs and then CFGs. CFGs are then pretty-printed.
|
|
||||||
|
|
||||||
* -view-cfg builds ASTs and then CFGs. CFGs are then visualized by
|
|
||||||
invoking Graphviz.
|
|
||||||
|
|
||||||
For more information on getting Graphviz to work with clang/LLVM,
|
|
||||||
see: http://llvm.org/docs/ProgrammersManual.html#ViewGraph
|
|
||||||
|
|
||||||
|
|
||||||
III. Current advantages over GCC:
|
|
||||||
|
|
||||||
* Column numbers are fully tracked (no 256 col limit, no GCC-style pruning).
|
|
||||||
* All diagnostics have column numbers, includes 'caret diagnostics', and they
|
|
||||||
highlight regions of interesting code (e.g. the LHS and RHS of a binop).
|
|
||||||
* Full diagnostic customization by client (can format diagnostics however they
|
|
||||||
like, e.g. in an IDE or refactoring tool) through DiagnosticClient interface.
|
|
||||||
* Built as a framework, can be reused by multiple tools.
|
|
||||||
* All languages supported linked into same library (no cc1,cc1obj, ...).
|
|
||||||
* mmap's code in read-only, does not dirty the pages like GCC (mem footprint).
|
|
||||||
* LLVM License, can be linked into non-GPL projects.
|
|
||||||
* Full diagnostic control, per diagnostic. Diagnostics are identified by ID.
|
|
||||||
* Significantly faster than GCC at semantic analysis, parsing, preprocessing
|
|
||||||
and lexing.
|
|
||||||
* Defers exposing platform-specific stuff to as late as possible, tracks use of
|
|
||||||
platform-specific features (e.g. #ifdef PPC) to allow 'portable bytecodes'.
|
|
||||||
* The lexer doesn't rely on the "lexer hack": it has no notion of scope and
|
|
||||||
does not categorize identifiers as types or variables -- this is up to the
|
|
||||||
parser to decide.
|
|
||||||
|
|
||||||
Potential Future Features:
|
|
||||||
|
|
||||||
* Fine grained diag control within the source (#pragma enable/disable warning).
|
|
||||||
* Better token tracking within macros? (Token came from this line, which is
|
|
||||||
a macro argument instantiated here, recursively instantiated here).
|
|
||||||
* Fast #import with a module system.
|
|
||||||
* Dependency tracking: change to header file doesn't recompile every function
|
|
||||||
that texually depends on it: recompile only those functions that need it.
|
|
||||||
This is aka 'incremental parsing'.
|
|
||||||
|
|
||||||
|
|
||||||
IV. Missing Functionality / Improvements
|
|
||||||
|
|
||||||
clang driver:
|
|
||||||
* Include search paths are hard-coded into the driver. Doh.
|
|
||||||
|
|
||||||
File Manager:
|
|
||||||
* Reduce syscalls for reduced compile time, see NOTES.txt.
|
|
||||||
|
|
||||||
Lexer:
|
|
||||||
* Source character mapping. GCC supports ASCII and UTF-8.
|
|
||||||
See GCC options: -ftarget-charset and -ftarget-wide-charset.
|
|
||||||
* Universal character support. Experimental in GCC, enabled with
|
|
||||||
-fextended-identifiers.
|
|
||||||
* -fpreprocessed mode.
|
|
||||||
|
|
||||||
Preprocessor:
|
|
||||||
* Know about apple header maps.
|
|
||||||
* #assert/#unassert
|
|
||||||
* #line / #file directives (currently accepted and ignored).
|
|
||||||
* MSExtension: "L#param" stringizes to a wide string literal.
|
|
||||||
* Charize extension: "#define F(o) #@o F(a)" -> 'a'.
|
|
||||||
* Consider merging the parser's expression parser into the preprocessor to
|
|
||||||
eliminate duplicate code.
|
|
||||||
* Add support for -M*
|
|
||||||
|
|
||||||
Traditional Preprocessor:
|
|
||||||
* Currently, we have none. :)
|
|
||||||
|
|
||||||
Parser:
|
|
||||||
* C90/K&R modes are only partially implemented.
|
|
||||||
* __extension__ is currently just skipped and ignored.
|
|
||||||
* "initializers", GCC inline asm.
|
|
||||||
|
|
||||||
Semantic Analysis:
|
|
||||||
* Perhaps 75% done.
|
|
||||||
|
|
||||||
LLVM Code Gen:
|
|
||||||
* Still very early.
|
|
||||||
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
//===--- ASTStreamer.cpp - Provide streaming interface to 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 ASTStreamer interface.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "clang/Sema/ASTStreamer.h"
|
|
||||||
#include "clang/AST/ASTContext.h"
|
|
||||||
#include "Sema.h"
|
|
||||||
#include "clang/Parse/Action.h"
|
|
||||||
#include "clang/Parse/Parser.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class ASTStreamer {
|
|
||||||
Parser P;
|
|
||||||
std::vector<Decl*> LastInGroupList;
|
|
||||||
public:
|
|
||||||
ASTStreamer(Preprocessor &pp, ASTContext &ctxt, unsigned MainFileID)
|
|
||||||
: P(pp, *new Sema(pp, ctxt, LastInGroupList)) {
|
|
||||||
pp.EnterSourceFile(MainFileID, 0, true);
|
|
||||||
|
|
||||||
// Initialize the parser.
|
|
||||||
P.Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ReadTopLevelDecl - Parse and return the next top-level declaration.
|
|
||||||
Decl *ReadTopLevelDecl();
|
|
||||||
|
|
||||||
void PrintStats() const;
|
|
||||||
|
|
||||||
~ASTStreamer() {
|
|
||||||
P.Finalize();
|
|
||||||
delete &P.getActions();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ReadTopLevelDecl - Parse and return the next top-level declaration.
|
|
||||||
///
|
|
||||||
Decl *ASTStreamer::ReadTopLevelDecl() {
|
|
||||||
Parser::DeclTy *Result;
|
|
||||||
|
|
||||||
/// If the previous time through we read something like 'int X, Y', return
|
|
||||||
/// the next declarator.
|
|
||||||
if (!LastInGroupList.empty()) {
|
|
||||||
Result = LastInGroupList.back();
|
|
||||||
LastInGroupList.pop_back();
|
|
||||||
return static_cast<Decl*>(Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (P.ParseTopLevelDecl(Result))
|
|
||||||
return 0; // End of file.
|
|
||||||
|
|
||||||
// If we got a null return and something *was* parsed, try again. This
|
|
||||||
// is due to a top-level semicolon, an action override, or a parse error
|
|
||||||
// skipping something.
|
|
||||||
} while (Result == 0);
|
|
||||||
|
|
||||||
// If we parsed a declspec with multiple declarators, reverse the list and
|
|
||||||
// return the first one.
|
|
||||||
if (!LastInGroupList.empty()) {
|
|
||||||
LastInGroupList.push_back((Decl*)Result);
|
|
||||||
std::reverse(LastInGroupList.begin(), LastInGroupList.end());
|
|
||||||
Result = LastInGroupList.back();
|
|
||||||
LastInGroupList.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
return static_cast<Decl*>(Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASTStreamer::PrintStats() const {
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Public interface to the file
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// ASTStreamer_Init - Create an ASTStreamer with the specified preprocessor
|
|
||||||
/// and FileID.
|
|
||||||
ASTStreamerTy *clang::ASTStreamer_Init(Preprocessor &pp, ASTContext &ctxt,
|
|
||||||
unsigned MainFileID) {
|
|
||||||
return new ASTStreamer(pp, ctxt, MainFileID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ASTStreamer_ReadTopLevelDecl - Parse and return one top-level declaration.
|
|
||||||
/// This returns null at end of file.
|
|
||||||
Decl *clang::ASTStreamer_ReadTopLevelDecl(ASTStreamerTy *Streamer) {
|
|
||||||
return static_cast<ASTStreamer*>(Streamer)->ReadTopLevelDecl();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// ASTStreamer_PrintStats - Emit statistic information to stderr.
|
|
||||||
///
|
|
||||||
void clang::ASTStreamer_PrintStats(ASTStreamerTy *Streamer) {
|
|
||||||
return static_cast<ASTStreamer*>(Streamer)->PrintStats();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ASTStreamer_Terminate - Gracefully shut down the streamer.
|
|
||||||
///
|
|
||||||
void clang::ASTStreamer_Terminate(ASTStreamerTy *Streamer) {
|
|
||||||
delete static_cast<ASTStreamer*>(Streamer);
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
##===- clang/Sema/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 semantic analyzer and AST builder library for the
|
|
||||||
# C-Language front-end.
|
|
||||||
#
|
|
||||||
##===----------------------------------------------------------------------===##
|
|
||||||
|
|
||||||
LEVEL = ../../..
|
|
||||||
LIBRARYNAME := clangSEMA
|
|
||||||
BUILD_ARCHIVE = 1
|
|
||||||
CXXFLAGS = -fno-rtti
|
|
||||||
|
|
||||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.common
|
|
||||||
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
//===--- Sema.cpp - AST Builder and Semantic Analysis 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 actions class which performs semantic analysis and
|
|
||||||
// builds an AST out of a parse stream.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "Sema.h"
|
|
||||||
#include "clang/AST/ASTContext.h"
|
|
||||||
#include "clang/Lex/Preprocessor.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, std::vector<Decl*> &prevInGroup)
|
|
||||||
: PP(pp), Context(ctxt), CurFunctionDecl(0), LastInGroupList(prevInGroup) {
|
|
||||||
|
|
||||||
// Get IdentifierInfo objects for known functions for which we
|
|
||||||
// do extra checking.
|
|
||||||
IdentifierTable& IT = PP.getIdentifierTable();
|
|
||||||
|
|
||||||
KnownFunctionIDs[ id_printf ] = &IT.get("printf");
|
|
||||||
KnownFunctionIDs[ id_fprintf ] = &IT.get("fprintf");
|
|
||||||
KnownFunctionIDs[ id_sprintf ] = &IT.get("sprintf");
|
|
||||||
KnownFunctionIDs[ id_snprintf ] = &IT.get("snprintf");
|
|
||||||
KnownFunctionIDs[ id_asprintf ] = &IT.get("asprintf");
|
|
||||||
KnownFunctionIDs[ id_vsnprintf ] = &IT.get("vsnprintf");
|
|
||||||
KnownFunctionIDs[ id_vasprintf ] = &IT.get("vasprintf");
|
|
||||||
KnownFunctionIDs[ id_vfprintf ] = &IT.get("vfprintf");
|
|
||||||
KnownFunctionIDs[ id_vsprintf ] = &IT.get("vsprintf");
|
|
||||||
KnownFunctionIDs[ id_vprintf ] = &IT.get("vprintf");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sema::DeleteExpr(ExprTy *E) {
|
|
||||||
delete static_cast<Expr*>(E);
|
|
||||||
}
|
|
||||||
void Sema::DeleteStmt(StmtTy *S) {
|
|
||||||
delete static_cast<Stmt*>(S);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Helper functions.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
bool Sema::Diag(SourceLocation Loc, unsigned DiagID) {
|
|
||||||
PP.getDiagnostics().Report(Loc, DiagID);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg) {
|
|
||||||
PP.getDiagnostics().Report(Loc, DiagID, &Msg, 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
|
|
||||||
const std::string &Msg2) {
|
|
||||||
std::string MsgArr[] = { Msg1, Msg2 };
|
|
||||||
PP.getDiagnostics().Report(Loc, DiagID, MsgArr, 2);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sema::Diag(SourceLocation Loc, unsigned DiagID, SourceRange Range) {
|
|
||||||
PP.getDiagnostics().Report(Loc, DiagID, 0, 0, &Range, 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg,
|
|
||||||
SourceRange Range) {
|
|
||||||
PP.getDiagnostics().Report(Loc, DiagID, &Msg, 1, &Range, 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
|
|
||||||
const std::string &Msg2, SourceRange Range) {
|
|
||||||
std::string MsgArr[] = { Msg1, Msg2 };
|
|
||||||
PP.getDiagnostics().Report(Loc, DiagID, MsgArr, 2, &Range, 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sema::Diag(SourceLocation Loc, unsigned DiagID,
|
|
||||||
SourceRange R1, SourceRange R2) {
|
|
||||||
SourceRange RangeArr[] = { R1, R2 };
|
|
||||||
PP.getDiagnostics().Report(Loc, DiagID, 0, 0, RangeArr, 2);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg,
|
|
||||||
SourceRange R1, SourceRange R2) {
|
|
||||||
SourceRange RangeArr[] = { R1, R2 };
|
|
||||||
PP.getDiagnostics().Report(Loc, DiagID, &Msg, 1, RangeArr, 2);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sema::Diag(SourceLocation Range, unsigned DiagID, const std::string &Msg1,
|
|
||||||
const std::string &Msg2, SourceRange R1, SourceRange R2) {
|
|
||||||
std::string MsgArr[] = { Msg1, Msg2 };
|
|
||||||
SourceRange RangeArr[] = { R1, R2 };
|
|
||||||
PP.getDiagnostics().Report(Range, DiagID, MsgArr, 2, RangeArr, 2);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LangOptions &Sema::getLangOptions() const {
|
|
||||||
return PP.getLangOptions();
|
|
||||||
}
|
|
||||||
@@ -1,512 +0,0 @@
|
|||||||
//===--- Sema.h - Semantic Analysis & AST Building --------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// 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 defines the Sema class, which performs semantic analysis and
|
|
||||||
// builds ASTs.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef LLVM_CLANG_AST_SEMA_H
|
|
||||||
#define LLVM_CLANG_AST_SEMA_H
|
|
||||||
|
|
||||||
#include "clang/Parse/Action.h"
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
|
||||||
#include "llvm/ADT/SmallVector.h"
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
class APSInt;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace clang {
|
|
||||||
class ASTContext;
|
|
||||||
class Preprocessor;
|
|
||||||
class Decl;
|
|
||||||
class Expr;
|
|
||||||
class InitListExpr;
|
|
||||||
class VarDecl;
|
|
||||||
class ParmVarDecl;
|
|
||||||
class TypedefDecl;
|
|
||||||
class FunctionDecl;
|
|
||||||
class QualType;
|
|
||||||
struct LangOptions;
|
|
||||||
struct DeclaratorChunk;
|
|
||||||
class Token;
|
|
||||||
class IntegerLiteral;
|
|
||||||
class ArrayType;
|
|
||||||
class LabelStmt;
|
|
||||||
class SwitchStmt;
|
|
||||||
class OCUVectorType;
|
|
||||||
class TypedefDecl;
|
|
||||||
|
|
||||||
/// Sema - This implements semantic analysis and AST building for C.
|
|
||||||
class Sema : public Action {
|
|
||||||
Preprocessor &PP;
|
|
||||||
|
|
||||||
ASTContext &Context;
|
|
||||||
|
|
||||||
/// CurFunctionDecl - If inside of a function body, this contains a pointer to
|
|
||||||
/// the function decl for the function being parsed.
|
|
||||||
FunctionDecl *CurFunctionDecl;
|
|
||||||
|
|
||||||
/// LastInGroupList - This vector is populated when there are multiple
|
|
||||||
/// declarators in a single decl group (e.g. "int A, B, C"). In this case,
|
|
||||||
/// all but the last decl will be entered into this. This is used by the
|
|
||||||
/// ASTStreamer.
|
|
||||||
std::vector<Decl*> &LastInGroupList;
|
|
||||||
|
|
||||||
/// LabelMap - This is a mapping from label identifiers to the LabelStmt for
|
|
||||||
/// it (which acts like the label decl in some ways). Forward referenced
|
|
||||||
/// labels have a LabelStmt created for them with a null location & SubStmt.
|
|
||||||
llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap;
|
|
||||||
|
|
||||||
llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
|
|
||||||
|
|
||||||
/// OCUVectorDecls - This is a list all the OCU vector types. This allows
|
|
||||||
/// us to associate a raw vector type with one of the OCU type names.
|
|
||||||
/// This is only necessary for issuing pretty diagnostics.
|
|
||||||
llvm::SmallVector<TypedefDecl*, 24> OCUVectorDecls;
|
|
||||||
|
|
||||||
// Enum values used by KnownFunctionIDs (see below).
|
|
||||||
enum {
|
|
||||||
id_printf,
|
|
||||||
id_fprintf,
|
|
||||||
id_sprintf,
|
|
||||||
id_snprintf,
|
|
||||||
id_asprintf,
|
|
||||||
id_vsnprintf,
|
|
||||||
id_vasprintf,
|
|
||||||
id_vfprintf,
|
|
||||||
id_vsprintf,
|
|
||||||
id_vprintf,
|
|
||||||
id_num_known_functions
|
|
||||||
};
|
|
||||||
|
|
||||||
/// KnownFunctionIDs - This is a list of IdentifierInfo objects to a set
|
|
||||||
/// of known functions used by the semantic analysis to do various
|
|
||||||
/// kinds of checking (e.g. checking format string errors in printf calls).
|
|
||||||
/// This list is populated upon the creation of a Sema object.
|
|
||||||
IdentifierInfo* KnownFunctionIDs[ id_num_known_functions ];
|
|
||||||
|
|
||||||
public:
|
|
||||||
Sema(Preprocessor &pp, ASTContext &ctxt, std::vector<Decl*> &prevInGroup);
|
|
||||||
|
|
||||||
const LangOptions &getLangOptions() const;
|
|
||||||
|
|
||||||
/// The primitive diagnostic helpers - always returns true, which simplifies
|
|
||||||
/// error handling (i.e. less code).
|
|
||||||
bool Diag(SourceLocation Loc, unsigned DiagID);
|
|
||||||
bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg);
|
|
||||||
bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
|
|
||||||
const std::string &Msg2);
|
|
||||||
|
|
||||||
/// More expressive diagnostic helpers for expressions (say that 6 times:-)
|
|
||||||
bool Diag(SourceLocation Loc, unsigned DiagID, SourceRange R1);
|
|
||||||
bool Diag(SourceLocation Loc, unsigned DiagID,
|
|
||||||
SourceRange R1, SourceRange R2);
|
|
||||||
bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg,
|
|
||||||
SourceRange R1);
|
|
||||||
bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg,
|
|
||||||
SourceRange R1, SourceRange R2);
|
|
||||||
bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
|
|
||||||
const std::string &Msg2, SourceRange R1);
|
|
||||||
bool Diag(SourceLocation Loc, unsigned DiagID,
|
|
||||||
const std::string &Msg1, const std::string &Msg2,
|
|
||||||
SourceRange R1, SourceRange R2);
|
|
||||||
|
|
||||||
virtual void DeleteExpr(ExprTy *E);
|
|
||||||
virtual void DeleteStmt(StmtTy *S);
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Type Analysis / Processing: SemaType.cpp.
|
|
||||||
//
|
|
||||||
QualType GetTypeForDeclarator(Declarator &D, Scope *S);
|
|
||||||
|
|
||||||
virtual TypeResult ParseTypeName(Scope *S, Declarator &D);
|
|
||||||
|
|
||||||
virtual TypeResult ParseParamDeclaratorType(Scope *S, Declarator &D);
|
|
||||||
private:
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Symbol table / Decl tracking callbacks: SemaDecl.cpp.
|
|
||||||
//
|
|
||||||
virtual DeclTy *isTypeName(const IdentifierInfo &II, Scope *S) const;
|
|
||||||
virtual DeclTy *ParseDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup);
|
|
||||||
void AddInitializerToDecl(DeclTy *dcl, ExprTy *init);
|
|
||||||
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
|
|
||||||
|
|
||||||
virtual DeclTy *ParseStartOfFunctionDef(Scope *S, Declarator &D);
|
|
||||||
virtual DeclTy *ParseFunctionDefBody(DeclTy *Decl, StmtTy *Body);
|
|
||||||
virtual void PopScope(SourceLocation Loc, Scope *S);
|
|
||||||
|
|
||||||
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
|
|
||||||
/// no declarator (e.g. "struct foo;") is parsed.
|
|
||||||
virtual DeclTy *ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS);
|
|
||||||
|
|
||||||
virtual DeclTy *ParseTag(Scope *S, unsigned TagType, TagKind TK,
|
|
||||||
SourceLocation KWLoc, IdentifierInfo *Name,
|
|
||||||
SourceLocation NameLoc, AttributeList *Attr);
|
|
||||||
virtual DeclTy *ParseField(Scope *S, DeclTy *TagDecl,SourceLocation DeclStart,
|
|
||||||
Declarator &D, ExprTy *BitfieldWidth);
|
|
||||||
virtual void ParseRecordBody(SourceLocation RecLoc, DeclTy *TagDecl,
|
|
||||||
DeclTy **Fields, unsigned NumFields);
|
|
||||||
virtual DeclTy *ParseEnumConstant(Scope *S, DeclTy *EnumDecl,
|
|
||||||
DeclTy *LastEnumConstant,
|
|
||||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
|
||||||
SourceLocation EqualLoc, ExprTy *Val);
|
|
||||||
virtual void ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl,
|
|
||||||
DeclTy **Elements, unsigned NumElements);
|
|
||||||
private:
|
|
||||||
/// Subroutines of ParseDeclarator()...
|
|
||||||
TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, Decl *LastDeclarator);
|
|
||||||
TypedefDecl *MergeTypeDefDecl(TypedefDecl *New, Decl *Old);
|
|
||||||
FunctionDecl *MergeFunctionDecl(FunctionDecl *New, Decl *Old);
|
|
||||||
VarDecl *MergeVarDecl(VarDecl *New, Decl *Old);
|
|
||||||
/// AddTopLevelDecl - called after the decl has been fully processed.
|
|
||||||
/// Allows for bookkeeping and post-processing of each declaration.
|
|
||||||
void AddTopLevelDecl(Decl *current, Decl *last);
|
|
||||||
|
|
||||||
/// More parsing and symbol table subroutines...
|
|
||||||
ParmVarDecl *ParseParamDeclarator(DeclaratorChunk &FI, unsigned ArgNo,
|
|
||||||
Scope *FnBodyScope);
|
|
||||||
Decl *LookupScopedDecl(IdentifierInfo *II, unsigned NSI, SourceLocation IdLoc,
|
|
||||||
Scope *S);
|
|
||||||
Decl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S);
|
|
||||||
Decl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
|
|
||||||
Scope *S);
|
|
||||||
// Decl attributes - this routine is the top level dispatcher.
|
|
||||||
void HandleDeclAttributes(Decl *New, AttributeList *declspec_prefix,
|
|
||||||
AttributeList *declarator_postfix);
|
|
||||||
void HandleDeclAttribute(Decl *New, AttributeList *rawAttr);
|
|
||||||
|
|
||||||
// HandleVectorTypeAttribute - this attribute is only applicable to
|
|
||||||
// integral and float scalars, although arrays, pointers, and function
|
|
||||||
// return values are allowed in conjunction with this construct. Aggregates
|
|
||||||
// with this attribute are invalid, even if they are of the same size as a
|
|
||||||
// corresponding scalar.
|
|
||||||
// The raw attribute should contain precisely 1 argument, the vector size
|
|
||||||
// for the variable, measured in bytes. If curType and rawAttr are well
|
|
||||||
// formed, this routine will return a new vector type.
|
|
||||||
QualType HandleVectorTypeAttribute(QualType curType, AttributeList *rawAttr);
|
|
||||||
void HandleOCUVectorTypeAttribute(TypedefDecl *d, AttributeList *rawAttr);
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Statement Parsing Callbacks: SemaStmt.cpp.
|
|
||||||
public:
|
|
||||||
virtual StmtResult ParseExprStmt(ExprTy *Expr);
|
|
||||||
|
|
||||||
virtual StmtResult ParseNullStmt(SourceLocation SemiLoc);
|
|
||||||
virtual StmtResult ParseCompoundStmt(SourceLocation L, SourceLocation R,
|
|
||||||
StmtTy **Elts, unsigned NumElts,
|
|
||||||
bool isStmtExpr);
|
|
||||||
virtual StmtResult ParseDeclStmt(DeclTy *Decl);
|
|
||||||
virtual StmtResult ParseCaseStmt(SourceLocation CaseLoc, ExprTy *LHSVal,
|
|
||||||
SourceLocation DotDotDotLoc, ExprTy *RHSVal,
|
|
||||||
SourceLocation ColonLoc, StmtTy *SubStmt);
|
|
||||||
virtual StmtResult ParseDefaultStmt(SourceLocation DefaultLoc,
|
|
||||||
SourceLocation ColonLoc, StmtTy *SubStmt,
|
|
||||||
Scope *CurScope);
|
|
||||||
virtual StmtResult ParseLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
|
|
||||||
SourceLocation ColonLoc, StmtTy *SubStmt);
|
|
||||||
virtual StmtResult ParseIfStmt(SourceLocation IfLoc, ExprTy *CondVal,
|
|
||||||
StmtTy *ThenVal, SourceLocation ElseLoc,
|
|
||||||
StmtTy *ElseVal);
|
|
||||||
virtual StmtResult StartSwitchStmt(ExprTy *Cond);
|
|
||||||
virtual StmtResult FinishSwitchStmt(SourceLocation SwitchLoc, StmtTy *Switch,
|
|
||||||
ExprTy *Body);
|
|
||||||
virtual StmtResult ParseWhileStmt(SourceLocation WhileLoc, ExprTy *Cond,
|
|
||||||
StmtTy *Body);
|
|
||||||
virtual StmtResult ParseDoStmt(SourceLocation DoLoc, StmtTy *Body,
|
|
||||||
SourceLocation WhileLoc, ExprTy *Cond);
|
|
||||||
|
|
||||||
virtual StmtResult ParseForStmt(SourceLocation ForLoc,
|
|
||||||
SourceLocation LParenLoc,
|
|
||||||
StmtTy *First, ExprTy *Second, ExprTy *Third,
|
|
||||||
SourceLocation RParenLoc, StmtTy *Body);
|
|
||||||
virtual StmtResult ParseGotoStmt(SourceLocation GotoLoc,
|
|
||||||
SourceLocation LabelLoc,
|
|
||||||
IdentifierInfo *LabelII);
|
|
||||||
virtual StmtResult ParseIndirectGotoStmt(SourceLocation GotoLoc,
|
|
||||||
SourceLocation StarLoc,
|
|
||||||
ExprTy *DestExp);
|
|
||||||
virtual StmtResult ParseContinueStmt(SourceLocation ContinueLoc,
|
|
||||||
Scope *CurScope);
|
|
||||||
virtual StmtResult ParseBreakStmt(SourceLocation GotoLoc, Scope *CurScope);
|
|
||||||
|
|
||||||
virtual StmtResult ParseReturnStmt(SourceLocation ReturnLoc,
|
|
||||||
ExprTy *RetValExp);
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Expression Parsing Callbacks: SemaExpr.cpp.
|
|
||||||
|
|
||||||
// Primary Expressions.
|
|
||||||
virtual ExprResult ParseIdentifierExpr(Scope *S, SourceLocation Loc,
|
|
||||||
IdentifierInfo &II,
|
|
||||||
bool HasTrailingLParen);
|
|
||||||
virtual ExprResult ParsePreDefinedExpr(SourceLocation Loc,
|
|
||||||
tok::TokenKind Kind);
|
|
||||||
virtual ExprResult ParseNumericConstant(const Token &);
|
|
||||||
virtual ExprResult ParseCharacterConstant(const Token &);
|
|
||||||
virtual ExprResult ParseParenExpr(SourceLocation L, SourceLocation R,
|
|
||||||
ExprTy *Val);
|
|
||||||
|
|
||||||
/// ParseStringLiteral - The specified tokens were lexed as pasted string
|
|
||||||
/// fragments (e.g. "foo" "bar" L"baz").
|
|
||||||
virtual ExprResult ParseStringLiteral(const Token *Toks, unsigned NumToks);
|
|
||||||
|
|
||||||
// Binary/Unary Operators. 'Tok' is the token for the operator.
|
|
||||||
virtual ExprResult ParseUnaryOp(SourceLocation OpLoc, tok::TokenKind Op,
|
|
||||||
ExprTy *Input);
|
|
||||||
virtual ExprResult
|
|
||||||
ParseSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof,
|
|
||||||
SourceLocation LParenLoc, TypeTy *Ty,
|
|
||||||
SourceLocation RParenLoc);
|
|
||||||
|
|
||||||
virtual ExprResult ParsePostfixUnaryOp(SourceLocation OpLoc,
|
|
||||||
tok::TokenKind Kind, ExprTy *Input);
|
|
||||||
|
|
||||||
virtual ExprResult ParseArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
|
|
||||||
ExprTy *Idx, SourceLocation RLoc);
|
|
||||||
virtual ExprResult ParseMemberReferenceExpr(ExprTy *Base,SourceLocation OpLoc,
|
|
||||||
tok::TokenKind OpKind,
|
|
||||||
SourceLocation MemberLoc,
|
|
||||||
IdentifierInfo &Member);
|
|
||||||
|
|
||||||
/// ParseCallExpr - Handle a call to Fn with the specified array of arguments.
|
|
||||||
/// This provides the location of the left/right parens and a list of comma
|
|
||||||
/// locations.
|
|
||||||
virtual ExprResult ParseCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
|
|
||||||
ExprTy **Args, unsigned NumArgs,
|
|
||||||
SourceLocation *CommaLocs,
|
|
||||||
SourceLocation RParenLoc);
|
|
||||||
|
|
||||||
virtual ExprResult ParseCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
|
|
||||||
SourceLocation RParenLoc, ExprTy *Op);
|
|
||||||
|
|
||||||
virtual ExprResult ParseCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
|
|
||||||
SourceLocation RParenLoc, ExprTy *Op);
|
|
||||||
|
|
||||||
virtual ExprResult ParseInitList(SourceLocation LParenLoc,
|
|
||||||
ExprTy **InitList, unsigned NumInit,
|
|
||||||
SourceLocation RParenLoc);
|
|
||||||
|
|
||||||
virtual ExprResult ParseBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
|
|
||||||
ExprTy *LHS,ExprTy *RHS);
|
|
||||||
|
|
||||||
/// ParseConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
|
|
||||||
/// in the case of a the GNU conditional expr extension.
|
|
||||||
virtual ExprResult ParseConditionalOp(SourceLocation QuestionLoc,
|
|
||||||
SourceLocation ColonLoc,
|
|
||||||
ExprTy *Cond, ExprTy *LHS, ExprTy *RHS);
|
|
||||||
|
|
||||||
/// ParseAddrLabel - Parse the GNU address of label extension: "&&foo".
|
|
||||||
virtual ExprResult ParseAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
|
|
||||||
IdentifierInfo *LabelII);
|
|
||||||
|
|
||||||
virtual ExprResult ParseStmtExpr(SourceLocation LPLoc, StmtTy *SubStmt,
|
|
||||||
SourceLocation RPLoc); // "({..})"
|
|
||||||
|
|
||||||
/// __builtin_offsetof(type, a.b[123][456].c)
|
|
||||||
virtual ExprResult ParseBuiltinOffsetOf(SourceLocation BuiltinLoc,
|
|
||||||
SourceLocation TypeLoc, TypeTy *Arg1,
|
|
||||||
OffsetOfComponent *CompPtr,
|
|
||||||
unsigned NumComponents,
|
|
||||||
SourceLocation RParenLoc);
|
|
||||||
|
|
||||||
// __builtin_types_compatible_p(type1, type2)
|
|
||||||
virtual ExprResult ParseTypesCompatibleExpr(SourceLocation BuiltinLoc,
|
|
||||||
TypeTy *arg1, TypeTy *arg2,
|
|
||||||
SourceLocation RPLoc);
|
|
||||||
|
|
||||||
// __builtin_choose_expr(constExpr, expr1, expr2)
|
|
||||||
virtual ExprResult ParseChooseExpr(SourceLocation BuiltinLoc,
|
|
||||||
ExprTy *cond, ExprTy *expr1, ExprTy *expr2,
|
|
||||||
SourceLocation RPLoc);
|
|
||||||
|
|
||||||
/// ParseCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.
|
|
||||||
virtual ExprResult ParseCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind,
|
|
||||||
SourceLocation LAngleBracketLoc, TypeTy *Ty,
|
|
||||||
SourceLocation RAngleBracketLoc,
|
|
||||||
SourceLocation LParenLoc, ExprTy *E,
|
|
||||||
SourceLocation RParenLoc);
|
|
||||||
|
|
||||||
/// ParseCXXBoolLiteral - Parse {true,false} literals.
|
|
||||||
virtual ExprResult ParseCXXBoolLiteral(SourceLocation OpLoc,
|
|
||||||
tok::TokenKind Kind);
|
|
||||||
|
|
||||||
// ParseObjCStringLiteral - Parse Objective-C string literals.
|
|
||||||
virtual ExprResult ParseObjCStringLiteral(ExprTy *string);
|
|
||||||
virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc,
|
|
||||||
SourceLocation LParenLoc,
|
|
||||||
TypeTy *Ty,
|
|
||||||
SourceLocation RParenLoc);
|
|
||||||
|
|
||||||
// Objective-C declarations.
|
|
||||||
virtual DeclTy *ObjcStartClassInterface(SourceLocation AtInterafceLoc,
|
|
||||||
IdentifierInfo *ClassName, SourceLocation ClassLoc,
|
|
||||||
IdentifierInfo *SuperName, SourceLocation SuperLoc,
|
|
||||||
IdentifierInfo **ProtocolNames, unsigned NumProtocols,
|
|
||||||
AttributeList *AttrList);
|
|
||||||
|
|
||||||
virtual DeclTy *ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc,
|
|
||||||
IdentifierInfo **IdentList,
|
|
||||||
unsigned NumElts);
|
|
||||||
|
|
||||||
virtual void ObjcAddMethodsToClass(DeclTy *ClassDecl,
|
|
||||||
DeclTy **allMethods, unsigned allNum);
|
|
||||||
virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc,
|
|
||||||
tok::TokenKind MethodType, TypeTy *ReturnType,
|
|
||||||
ObjcKeywordInfo *Keywords, unsigned NumKeywords,
|
|
||||||
AttributeList *AttrList);
|
|
||||||
virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc,
|
|
||||||
tok::TokenKind MethodType, TypeTy *ReturnType,
|
|
||||||
IdentifierInfo *SelectorName, AttributeList *AttrList);
|
|
||||||
|
|
||||||
virtual void ObjcAddInstanceVariable(DeclTy *ClassDec, DeclTy *Ivar,
|
|
||||||
tok::ObjCKeywordKind visibility);
|
|
||||||
private:
|
|
||||||
// UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts
|
|
||||||
// functions and arrays to their respective pointers (C99 6.3.2.1).
|
|
||||||
void UsualUnaryConversions(Expr *&expr);
|
|
||||||
|
|
||||||
// DefaultFunctionArrayConversion - converts functions and arrays
|
|
||||||
// to their respective pointers (C99 6.3.2.1).
|
|
||||||
void DefaultFunctionArrayConversion(Expr *&expr);
|
|
||||||
|
|
||||||
// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
|
|
||||||
// do not have a prototype. Integer promotions are performed on each
|
|
||||||
// argument, and arguments that have type float are promoted to double.
|
|
||||||
void DefaultArgumentPromotion(Expr *&expr);
|
|
||||||
|
|
||||||
// UsualArithmeticConversions - performs the UsualUnaryConversions on it's
|
|
||||||
// operands and then handles various conversions that are common to binary
|
|
||||||
// operators (C99 6.3.1.8). If both operands aren't arithmetic, this
|
|
||||||
// routine returns the first non-arithmetic type found. The client is
|
|
||||||
// responsible for emitting appropriate error diagnostics.
|
|
||||||
QualType UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr,
|
|
||||||
bool isCompAssign = false);
|
|
||||||
enum AssignmentCheckResult {
|
|
||||||
Compatible,
|
|
||||||
Incompatible,
|
|
||||||
PointerFromInt,
|
|
||||||
IntFromPointer,
|
|
||||||
IncompatiblePointer,
|
|
||||||
CompatiblePointerDiscardsQualifiers
|
|
||||||
};
|
|
||||||
// CheckAssignmentConstraints - Perform type checking for assignment,
|
|
||||||
// argument passing, variable initialization, and function return values.
|
|
||||||
// This routine is only used by the following two methods. C99 6.5.16.
|
|
||||||
AssignmentCheckResult CheckAssignmentConstraints(QualType lhs, QualType rhs);
|
|
||||||
|
|
||||||
// CheckSingleAssignmentConstraints - Currently used by ParseCallExpr,
|
|
||||||
// CheckAssignmentOperands, and ParseReturnStmt. Prior to type checking,
|
|
||||||
// this routine performs the default function/array converions.
|
|
||||||
AssignmentCheckResult CheckSingleAssignmentConstraints(QualType lhs,
|
|
||||||
Expr *&rExpr);
|
|
||||||
// CheckCompoundAssignmentConstraints - Type check without performing any
|
|
||||||
// conversions. For compound assignments, the "Check...Operands" methods
|
|
||||||
// perform the necessary conversions.
|
|
||||||
AssignmentCheckResult CheckCompoundAssignmentConstraints(QualType lhs,
|
|
||||||
QualType rhs);
|
|
||||||
|
|
||||||
// Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1)
|
|
||||||
AssignmentCheckResult CheckPointerTypesForAssignment(QualType lhsType,
|
|
||||||
QualType rhsType);
|
|
||||||
|
|
||||||
/// the following "Check" methods will return a valid/converted QualType
|
|
||||||
/// or a null QualType (indicating an error diagnostic was issued).
|
|
||||||
|
|
||||||
/// type checking binary operators (subroutines of ParseBinOp).
|
|
||||||
inline void InvalidOperands(SourceLocation l, Expr *&lex, Expr *&rex);
|
|
||||||
inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex);
|
|
||||||
inline QualType CheckMultiplyDivideOperands( // C99 6.5.5
|
|
||||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
|
|
||||||
inline QualType CheckRemainderOperands( // C99 6.5.5
|
|
||||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
|
|
||||||
inline QualType CheckAdditionOperands( // C99 6.5.6
|
|
||||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
|
|
||||||
inline QualType CheckSubtractionOperands( // C99 6.5.6
|
|
||||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
|
|
||||||
inline QualType CheckShiftOperands( // C99 6.5.7
|
|
||||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
|
|
||||||
inline QualType CheckCompareOperands( // C99 6.5.8/9
|
|
||||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isRelational);
|
|
||||||
inline QualType CheckBitwiseOperands( // C99 6.5.[10...12]
|
|
||||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
|
|
||||||
inline QualType CheckLogicalOperands( // C99 6.5.[13,14]
|
|
||||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc);
|
|
||||||
// CheckAssignmentOperands is used for both simple and compound assignment.
|
|
||||||
// For simple assignment, pass both expressions and a null converted type.
|
|
||||||
// For compound assignment, pass both expressions and the converted type.
|
|
||||||
inline QualType CheckAssignmentOperands( // C99 6.5.16.[1,2]
|
|
||||||
Expr *lex, Expr *&rex, SourceLocation OpLoc, QualType convertedType);
|
|
||||||
inline QualType CheckCommaOperands( // C99 6.5.17
|
|
||||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc);
|
|
||||||
inline QualType CheckConditionalOperands( // C99 6.5.15
|
|
||||||
Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
|
|
||||||
|
|
||||||
/// type checking unary operators (subroutines of ParseUnaryOp).
|
|
||||||
/// C99 6.5.3.1, 6.5.3.2, 6.5.3.4
|
|
||||||
QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc);
|
|
||||||
QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc);
|
|
||||||
QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc);
|
|
||||||
QualType CheckSizeOfAlignOfOperand(QualType type, SourceLocation loc,
|
|
||||||
bool isSizeof);
|
|
||||||
QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc);
|
|
||||||
|
|
||||||
/// type checking primary expressions.
|
|
||||||
QualType CheckOCUVectorComponent(QualType baseType, SourceLocation OpLoc,
|
|
||||||
IdentifierInfo &Comp, SourceLocation CmpLoc);
|
|
||||||
|
|
||||||
/// type checking declaration initializers (C99 6.7.8)
|
|
||||||
bool CheckInitializer(Expr *&simpleInit_or_initList, QualType &declType,
|
|
||||||
bool isStatic);
|
|
||||||
bool CheckSingleInitializer(Expr *&simpleInit, QualType declType);
|
|
||||||
bool CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot,
|
|
||||||
bool isStatic, QualType ElementType);
|
|
||||||
void CheckVariableInitList(QualType DeclType, InitListExpr *IList,
|
|
||||||
QualType ElementType, bool isStatic,
|
|
||||||
int &nInitializers, bool &hadError);
|
|
||||||
void CheckConstantInitList(QualType DeclType, InitListExpr *IList,
|
|
||||||
QualType ElementType, bool isStatic,
|
|
||||||
int &nInitializers, bool &hadError);
|
|
||||||
|
|
||||||
/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
|
|
||||||
/// the specified width and sign. If an overflow occurs, detect it and emit
|
|
||||||
/// the specified diagnostic.
|
|
||||||
void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal,
|
|
||||||
unsigned NewWidth, bool NewSign,
|
|
||||||
SourceLocation Loc, unsigned DiagID);
|
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
|
||||||
// Extra semantic analysis beyond the C type system
|
|
||||||
private:
|
|
||||||
|
|
||||||
bool CheckFunctionCall(Expr *Fn,
|
|
||||||
SourceLocation LParenLoc, SourceLocation RParenLoc,
|
|
||||||
FunctionDecl *FDecl,
|
|
||||||
Expr** Args, unsigned NumArgsInCall);
|
|
||||||
|
|
||||||
void CheckPrintfArguments(Expr *Fn,
|
|
||||||
SourceLocation LParenLoc, SourceLocation RParenLoc,
|
|
||||||
bool HasVAListArg, FunctionDecl *FDecl,
|
|
||||||
unsigned format_idx, Expr** Args,
|
|
||||||
unsigned NumArgsInCall);
|
|
||||||
|
|
||||||
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
|
|
||||||
SourceLocation ReturnLoc);
|
|
||||||
|
|
||||||
|
|
||||||
bool CheckBuiltinCFStringArgument(Expr* Arg);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // end namespace clang
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,623 +0,0 @@
|
|||||||
//===--- SemaChecking.cpp - Extra Semantic Checking -----------------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Ted Kremenek and is distributed under
|
|
||||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file implements extra semantic analysis beyond what is enforced
|
|
||||||
// by the C type system.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "Sema.h"
|
|
||||||
#include "clang/AST/ASTContext.h"
|
|
||||||
#include "clang/AST/Decl.h"
|
|
||||||
#include "clang/AST/Expr.h"
|
|
||||||
#include "clang/AST/ExprCXX.h"
|
|
||||||
#include "clang/Lex/Preprocessor.h"
|
|
||||||
#include "clang/Lex/LiteralSupport.h"
|
|
||||||
#include "clang/Basic/SourceManager.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "clang/Basic/LangOptions.h"
|
|
||||||
#include "clang/Basic/TargetInfo.h"
|
|
||||||
#include "llvm/ADT/SmallString.h"
|
|
||||||
#include "llvm/ADT/StringExtras.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
/// CheckFunctionCall - Check a direct function call for various correctness
|
|
||||||
/// and safety properties not strictly enforced by the C type system.
|
|
||||||
bool
|
|
||||||
Sema::CheckFunctionCall(Expr *Fn,
|
|
||||||
SourceLocation LParenLoc, SourceLocation RParenLoc,
|
|
||||||
FunctionDecl *FDecl,
|
|
||||||
Expr** Args, unsigned NumArgsInCall) {
|
|
||||||
|
|
||||||
// Get the IdentifierInfo* for the called function.
|
|
||||||
IdentifierInfo *FnInfo = FDecl->getIdentifier();
|
|
||||||
|
|
||||||
if (FnInfo->getBuiltinID() ==
|
|
||||||
Builtin::BI__builtin___CFStringMakeConstantString) {
|
|
||||||
assert(NumArgsInCall == 1 &&
|
|
||||||
"Wrong number of arguments to builtin CFStringMakeConstantString");
|
|
||||||
return CheckBuiltinCFStringArgument(Args[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search the KnownFunctionIDs for the identifier.
|
|
||||||
unsigned i = 0, e = id_num_known_functions;
|
|
||||||
for (; i != e; ++i) { if (KnownFunctionIDs[i] == FnInfo) break; }
|
|
||||||
if (i == e) return false;
|
|
||||||
|
|
||||||
// Printf checking.
|
|
||||||
if (i <= id_vprintf) {
|
|
||||||
// Retrieve the index of the format string parameter and determine
|
|
||||||
// if the function is passed a va_arg argument.
|
|
||||||
unsigned format_idx = 0;
|
|
||||||
bool HasVAListArg = false;
|
|
||||||
|
|
||||||
switch (i) {
|
|
||||||
default: assert(false && "No format string argument index.");
|
|
||||||
case id_printf: format_idx = 0; break;
|
|
||||||
case id_fprintf: format_idx = 1; break;
|
|
||||||
case id_sprintf: format_idx = 1; break;
|
|
||||||
case id_snprintf: format_idx = 2; break;
|
|
||||||
case id_asprintf: format_idx = 1; HasVAListArg = true; break;
|
|
||||||
case id_vsnprintf: format_idx = 2; HasVAListArg = true; break;
|
|
||||||
case id_vasprintf: format_idx = 1; HasVAListArg = true; break;
|
|
||||||
case id_vfprintf: format_idx = 1; HasVAListArg = true; break;
|
|
||||||
case id_vsprintf: format_idx = 1; HasVAListArg = true; break;
|
|
||||||
case id_vprintf: format_idx = 0; HasVAListArg = true; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckPrintfArguments(Fn, LParenLoc, RParenLoc, HasVAListArg,
|
|
||||||
FDecl, format_idx, Args, NumArgsInCall);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// CheckBuiltinCFStringArgument - Checks that the argument to the builtin
|
|
||||||
/// CFString constructor is correct
|
|
||||||
bool Sema::CheckBuiltinCFStringArgument(Expr* Arg) {
|
|
||||||
// FIXME: This should go in a helper.
|
|
||||||
while (1) {
|
|
||||||
if (ParenExpr *PE = dyn_cast<ParenExpr>(Arg))
|
|
||||||
Arg = PE->getSubExpr();
|
|
||||||
else if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg))
|
|
||||||
Arg = ICE->getSubExpr();
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringLiteral *Literal = dyn_cast<StringLiteral>(Arg);
|
|
||||||
|
|
||||||
if (!Literal || Literal->isWide()) {
|
|
||||||
Diag(Arg->getLocStart(),
|
|
||||||
diag::err_cfstring_literal_not_string_constant,
|
|
||||||
Arg->getSourceRange());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *Data = Literal->getStrData();
|
|
||||||
unsigned Length = Literal->getByteLength();
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < Length; ++i) {
|
|
||||||
if (!isascii(Data[i])) {
|
|
||||||
Diag(PP.AdvanceToTokenCharacter(Arg->getLocStart(), i + 1),
|
|
||||||
diag::warn_cfstring_literal_contains_non_ascii_character,
|
|
||||||
Arg->getSourceRange());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Data[i]) {
|
|
||||||
Diag(PP.AdvanceToTokenCharacter(Arg->getLocStart(), i + 1),
|
|
||||||
diag::warn_cfstring_literal_contains_nul_character,
|
|
||||||
Arg->getSourceRange());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// CheckPrintfArguments - Check calls to printf (and similar functions) for
|
|
||||||
/// correct use of format strings.
|
|
||||||
///
|
|
||||||
/// HasVAListArg - A predicate indicating whether the printf-like
|
|
||||||
/// function is passed an explicit va_arg argument (e.g., vprintf)
|
|
||||||
///
|
|
||||||
/// format_idx - The index into Args for the format string.
|
|
||||||
///
|
|
||||||
/// Improper format strings to functions in the printf family can be
|
|
||||||
/// the source of bizarre bugs and very serious security holes. A
|
|
||||||
/// good source of information is available in the following paper
|
|
||||||
/// (which includes additional references):
|
|
||||||
///
|
|
||||||
/// FormatGuard: Automatic Protection From printf Format String
|
|
||||||
/// Vulnerabilities, Proceedings of the 10th USENIX Security Symposium, 2001.
|
|
||||||
///
|
|
||||||
/// Functionality implemented:
|
|
||||||
///
|
|
||||||
/// We can statically check the following properties for string
|
|
||||||
/// literal format strings for non v.*printf functions (where the
|
|
||||||
/// arguments are passed directly):
|
|
||||||
//
|
|
||||||
/// (1) Are the number of format conversions equal to the number of
|
|
||||||
/// data arguments?
|
|
||||||
///
|
|
||||||
/// (2) Does each format conversion correctly match the type of the
|
|
||||||
/// corresponding data argument? (TODO)
|
|
||||||
///
|
|
||||||
/// Moreover, for all printf functions we can:
|
|
||||||
///
|
|
||||||
/// (3) Check for a missing format string (when not caught by type checking).
|
|
||||||
///
|
|
||||||
/// (4) Check for no-operation flags; e.g. using "#" with format
|
|
||||||
/// conversion 'c' (TODO)
|
|
||||||
///
|
|
||||||
/// (5) Check the use of '%n', a major source of security holes.
|
|
||||||
///
|
|
||||||
/// (6) Check for malformed format conversions that don't specify anything.
|
|
||||||
///
|
|
||||||
/// (7) Check for empty format strings. e.g: printf("");
|
|
||||||
///
|
|
||||||
/// (8) Check that the format string is a wide literal.
|
|
||||||
///
|
|
||||||
/// All of these checks can be done by parsing the format string.
|
|
||||||
///
|
|
||||||
/// For now, we ONLY do (1), (3), (5), (6), (7), and (8).
|
|
||||||
void
|
|
||||||
Sema::CheckPrintfArguments(Expr *Fn,
|
|
||||||
SourceLocation LParenLoc, SourceLocation RParenLoc,
|
|
||||||
bool HasVAListArg, FunctionDecl *FDecl,
|
|
||||||
unsigned format_idx, Expr** Args,
|
|
||||||
unsigned NumArgsInCall) {
|
|
||||||
// CHECK: printf-like function is called with no format string.
|
|
||||||
if (format_idx >= NumArgsInCall) {
|
|
||||||
Diag(RParenLoc, diag::warn_printf_missing_format_string,
|
|
||||||
Fn->getSourceRange());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Expr *OrigFormatExpr = Args[format_idx];
|
|
||||||
// FIXME: This should go in a helper.
|
|
||||||
while (1) {
|
|
||||||
if (ParenExpr *PE = dyn_cast<ParenExpr>(OrigFormatExpr))
|
|
||||||
OrigFormatExpr = PE->getSubExpr();
|
|
||||||
else if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(OrigFormatExpr))
|
|
||||||
OrigFormatExpr = ICE->getSubExpr();
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CHECK: format string is not a string literal.
|
|
||||||
//
|
|
||||||
// Dynamically generated format strings are difficult to
|
|
||||||
// automatically vet at compile time. Requiring that format strings
|
|
||||||
// are string literals: (1) permits the checking of format strings by
|
|
||||||
// the compiler and thereby (2) can practically remove the source of
|
|
||||||
// many format string exploits.
|
|
||||||
StringLiteral *FExpr = dyn_cast<StringLiteral>(OrigFormatExpr);
|
|
||||||
|
|
||||||
if (FExpr == NULL) {
|
|
||||||
Diag(Args[format_idx]->getLocStart(),
|
|
||||||
diag::warn_printf_not_string_constant, Fn->getSourceRange());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CHECK: is the format string a wide literal?
|
|
||||||
if (FExpr->isWide()) {
|
|
||||||
Diag(Args[format_idx]->getLocStart(),
|
|
||||||
diag::warn_printf_format_string_is_wide_literal,
|
|
||||||
Fn->getSourceRange());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Str - The format string. NOTE: this is NOT null-terminated!
|
|
||||||
const char * const Str = FExpr->getStrData();
|
|
||||||
|
|
||||||
// CHECK: empty format string?
|
|
||||||
const unsigned StrLen = FExpr->getByteLength();
|
|
||||||
|
|
||||||
if (StrLen == 0) {
|
|
||||||
Diag(Args[format_idx]->getLocStart(),
|
|
||||||
diag::warn_printf_empty_format_string, Fn->getSourceRange());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We process the format string using a binary state machine. The
|
|
||||||
// current state is stored in CurrentState.
|
|
||||||
enum {
|
|
||||||
state_OrdChr,
|
|
||||||
state_Conversion
|
|
||||||
} CurrentState = state_OrdChr;
|
|
||||||
|
|
||||||
// numConversions - The number of conversions seen so far. This is
|
|
||||||
// incremented as we traverse the format string.
|
|
||||||
unsigned numConversions = 0;
|
|
||||||
|
|
||||||
// numDataArgs - The number of data arguments after the format
|
|
||||||
// string. This can only be determined for non vprintf-like
|
|
||||||
// functions. For those functions, this value is 1 (the sole
|
|
||||||
// va_arg argument).
|
|
||||||
unsigned numDataArgs = NumArgsInCall-(format_idx+1);
|
|
||||||
|
|
||||||
// Inspect the format string.
|
|
||||||
unsigned StrIdx = 0;
|
|
||||||
|
|
||||||
// LastConversionIdx - Index within the format string where we last saw
|
|
||||||
// a '%' character that starts a new format conversion.
|
|
||||||
unsigned LastConversionIdx = 0;
|
|
||||||
|
|
||||||
for ( ; StrIdx < StrLen ; ++StrIdx ) {
|
|
||||||
|
|
||||||
// Is the number of detected conversion conversions greater than
|
|
||||||
// the number of matching data arguments? If so, stop.
|
|
||||||
if (!HasVAListArg && numConversions > numDataArgs) break;
|
|
||||||
|
|
||||||
// Handle "\0"
|
|
||||||
if(Str[StrIdx] == '\0' ) {
|
|
||||||
// The string returned by getStrData() is not null-terminated,
|
|
||||||
// so the presence of a null character is likely an error.
|
|
||||||
|
|
||||||
SourceLocation Loc =
|
|
||||||
PP.AdvanceToTokenCharacter(Args[format_idx]->getLocStart(),StrIdx+1);
|
|
||||||
|
|
||||||
Diag(Loc, diag::warn_printf_format_string_contains_null_char,
|
|
||||||
Fn->getSourceRange());
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ordinary characters (not processing a format conversion).
|
|
||||||
if (CurrentState == state_OrdChr) {
|
|
||||||
if (Str[StrIdx] == '%') {
|
|
||||||
CurrentState = state_Conversion;
|
|
||||||
LastConversionIdx = StrIdx;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Seen '%'. Now processing a format conversion.
|
|
||||||
switch (Str[StrIdx]) {
|
|
||||||
// Characters which can terminate a format conversion
|
|
||||||
// (e.g. "%d"). Characters that specify length modifiers or
|
|
||||||
// other flags are handled by the default case below.
|
|
||||||
//
|
|
||||||
// TODO: additional checks will go into the following cases.
|
|
||||||
case 'i':
|
|
||||||
case 'd':
|
|
||||||
case 'o':
|
|
||||||
case 'u':
|
|
||||||
case 'x':
|
|
||||||
case 'X':
|
|
||||||
case 'D':
|
|
||||||
case 'O':
|
|
||||||
case 'U':
|
|
||||||
case 'e':
|
|
||||||
case 'E':
|
|
||||||
case 'f':
|
|
||||||
case 'F':
|
|
||||||
case 'g':
|
|
||||||
case 'G':
|
|
||||||
case 'a':
|
|
||||||
case 'A':
|
|
||||||
case 'c':
|
|
||||||
case 'C':
|
|
||||||
case 'S':
|
|
||||||
case 's':
|
|
||||||
case 'p':
|
|
||||||
++numConversions;
|
|
||||||
CurrentState = state_OrdChr;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// CHECK: Are we using "%n"? Issue a warning.
|
|
||||||
case 'n': {
|
|
||||||
++numConversions;
|
|
||||||
CurrentState = state_OrdChr;
|
|
||||||
SourceLocation Loc =
|
|
||||||
PP.AdvanceToTokenCharacter(Args[format_idx]->getLocStart(),
|
|
||||||
LastConversionIdx+1);
|
|
||||||
|
|
||||||
Diag(Loc, diag::warn_printf_write_back, Fn->getSourceRange());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle "%%"
|
|
||||||
case '%':
|
|
||||||
// Sanity check: Was the first "%" character the previous one?
|
|
||||||
// If not, we will assume that we have a malformed format
|
|
||||||
// conversion, and that the current "%" character is the start
|
|
||||||
// of a new conversion.
|
|
||||||
if (StrIdx - LastConversionIdx == 1)
|
|
||||||
CurrentState = state_OrdChr;
|
|
||||||
else {
|
|
||||||
// Issue a warning: invalid format conversion.
|
|
||||||
SourceLocation Loc =
|
|
||||||
PP.AdvanceToTokenCharacter(Args[format_idx]->getLocStart(),
|
|
||||||
LastConversionIdx+1);
|
|
||||||
|
|
||||||
Diag(Loc, diag::warn_printf_invalid_conversion,
|
|
||||||
std::string(Str+LastConversionIdx, Str+StrIdx),
|
|
||||||
Fn->getSourceRange());
|
|
||||||
|
|
||||||
// This conversion is broken. Advance to the next format
|
|
||||||
// conversion.
|
|
||||||
LastConversionIdx = StrIdx;
|
|
||||||
++numConversions;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// This case catches all other characters: flags, widths, etc.
|
|
||||||
// We should eventually process those as well.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrentState == state_Conversion) {
|
|
||||||
// Issue a warning: invalid format conversion.
|
|
||||||
SourceLocation Loc =
|
|
||||||
PP.AdvanceToTokenCharacter(Args[format_idx]->getLocStart(),
|
|
||||||
LastConversionIdx+1);
|
|
||||||
|
|
||||||
Diag(Loc, diag::warn_printf_invalid_conversion,
|
|
||||||
std::string(Str+LastConversionIdx,
|
|
||||||
Str+std::min(LastConversionIdx+2, StrLen)),
|
|
||||||
Fn->getSourceRange());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!HasVAListArg) {
|
|
||||||
// CHECK: Does the number of format conversions exceed the number
|
|
||||||
// of data arguments?
|
|
||||||
if (numConversions > numDataArgs) {
|
|
||||||
SourceLocation Loc =
|
|
||||||
PP.AdvanceToTokenCharacter(Args[format_idx]->getLocStart(),
|
|
||||||
LastConversionIdx);
|
|
||||||
|
|
||||||
Diag(Loc, diag::warn_printf_insufficient_data_args,
|
|
||||||
Fn->getSourceRange());
|
|
||||||
}
|
|
||||||
// CHECK: Does the number of data arguments exceed the number of
|
|
||||||
// format conversions in the format string?
|
|
||||||
else if (numConversions < numDataArgs)
|
|
||||||
Diag(Args[format_idx+numConversions+1]->getLocStart(),
|
|
||||||
diag::warn_printf_too_many_data_args, Fn->getSourceRange());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//===--- CHECK: Return Address of Stack Variable --------------------------===//
|
|
||||||
|
|
||||||
static DeclRefExpr* EvalVal(Expr *E);
|
|
||||||
static DeclRefExpr* EvalAddr(Expr* E);
|
|
||||||
|
|
||||||
/// CheckReturnStackAddr - Check if a return statement returns the address
|
|
||||||
/// of a stack variable.
|
|
||||||
void
|
|
||||||
Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
|
|
||||||
SourceLocation ReturnLoc) {
|
|
||||||
|
|
||||||
// Perform checking for returned stack addresses.
|
|
||||||
if (lhsType->isPointerType()) {
|
|
||||||
if (DeclRefExpr *DR = EvalAddr(RetValExp))
|
|
||||||
Diag(DR->getLocStart(), diag::warn_ret_stack_addr,
|
|
||||||
DR->getDecl()->getIdentifier()->getName(),
|
|
||||||
RetValExp->getSourceRange());
|
|
||||||
}
|
|
||||||
// Perform checking for stack values returned by reference.
|
|
||||||
else if (lhsType->isReferenceType()) {
|
|
||||||
// Check for an implicit cast to a reference.
|
|
||||||
if (ImplicitCastExpr *I = dyn_cast<ImplicitCastExpr>(RetValExp))
|
|
||||||
if (DeclRefExpr *DR = EvalVal(I->getSubExpr()))
|
|
||||||
Diag(DR->getLocStart(), diag::warn_ret_stack_ref,
|
|
||||||
DR->getDecl()->getIdentifier()->getName(),
|
|
||||||
RetValExp->getSourceRange());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// EvalAddr - EvalAddr and EvalVal are mutually recursive functions that
|
|
||||||
/// check if the expression in a return statement evaluates to an address
|
|
||||||
/// to a location on the stack. The recursion is used to traverse the
|
|
||||||
/// AST of the return expression, with recursion backtracking when we
|
|
||||||
/// encounter a subexpression that (1) clearly does not lead to the address
|
|
||||||
/// of a stack variable or (2) is something we cannot determine leads to
|
|
||||||
/// the address of a stack variable based on such local checking.
|
|
||||||
///
|
|
||||||
/// EvalAddr processes expressions that are pointers that are used as
|
|
||||||
/// references (and not L-values). EvalVal handles all other values.
|
|
||||||
/// At the base case of the recursion is a check for a DeclRefExpr* in
|
|
||||||
/// the refers to a stack variable.
|
|
||||||
///
|
|
||||||
/// This implementation handles:
|
|
||||||
///
|
|
||||||
/// * pointer-to-pointer casts
|
|
||||||
/// * implicit conversions from array references to pointers
|
|
||||||
/// * taking the address of fields
|
|
||||||
/// * arbitrary interplay between "&" and "*" operators
|
|
||||||
/// * pointer arithmetic from an address of a stack variable
|
|
||||||
/// * taking the address of an array element where the array is on the stack
|
|
||||||
static DeclRefExpr* EvalAddr(Expr *E) {
|
|
||||||
|
|
||||||
// We should only be called for evaluating pointer expressions.
|
|
||||||
assert (E->getType()->isPointerType() && "EvalAddr only works on pointers");
|
|
||||||
|
|
||||||
// Our "symbolic interpreter" is just a dispatch off the currently
|
|
||||||
// viewed AST node. We then recursively traverse the AST by calling
|
|
||||||
// EvalAddr and EvalVal appropriately.
|
|
||||||
switch (E->getStmtClass()) {
|
|
||||||
|
|
||||||
case Stmt::ParenExprClass:
|
|
||||||
// Ignore parentheses.
|
|
||||||
return EvalAddr(cast<ParenExpr>(E)->getSubExpr());
|
|
||||||
|
|
||||||
case Stmt::UnaryOperatorClass: {
|
|
||||||
// The only unary operator that make sense to handle here
|
|
||||||
// is AddrOf. All others don't make sense as pointers.
|
|
||||||
UnaryOperator *U = cast<UnaryOperator>(E);
|
|
||||||
|
|
||||||
if (U->getOpcode() == UnaryOperator::AddrOf)
|
|
||||||
return EvalVal(U->getSubExpr());
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Stmt::BinaryOperatorClass: {
|
|
||||||
// Handle pointer arithmetic. All other binary operators are not valid
|
|
||||||
// in this context.
|
|
||||||
BinaryOperator *B = cast<BinaryOperator>(E);
|
|
||||||
BinaryOperator::Opcode op = B->getOpcode();
|
|
||||||
|
|
||||||
if (op != BinaryOperator::Add && op != BinaryOperator::Sub)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
Expr *Base = B->getLHS();
|
|
||||||
|
|
||||||
// Determine which argument is the real pointer base. It could be
|
|
||||||
// the RHS argument instead of the LHS.
|
|
||||||
if (!Base->getType()->isPointerType()) Base = B->getRHS();
|
|
||||||
|
|
||||||
assert (Base->getType()->isPointerType());
|
|
||||||
return EvalAddr(Base);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For conditional operators we need to see if either the LHS or RHS are
|
|
||||||
// valid DeclRefExpr*s. If one of them is valid, we return it.
|
|
||||||
case Stmt::ConditionalOperatorClass: {
|
|
||||||
ConditionalOperator *C = cast<ConditionalOperator>(E);
|
|
||||||
|
|
||||||
if (DeclRefExpr* LHS = EvalAddr(C->getLHS()))
|
|
||||||
return LHS;
|
|
||||||
else
|
|
||||||
return EvalAddr(C->getRHS());
|
|
||||||
}
|
|
||||||
|
|
||||||
// For implicit casts, we need to handle conversions from arrays to
|
|
||||||
// pointer values, and implicit pointer-to-pointer conversions.
|
|
||||||
case Stmt::ImplicitCastExprClass: {
|
|
||||||
ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E);
|
|
||||||
Expr* SubExpr = IE->getSubExpr();
|
|
||||||
|
|
||||||
if (SubExpr->getType()->isPointerType())
|
|
||||||
return EvalAddr(SubExpr);
|
|
||||||
else
|
|
||||||
return EvalVal(SubExpr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For casts, we handle pointer-to-pointer conversions (which
|
|
||||||
// is essentially a no-op from our mini-interpreter's standpoint).
|
|
||||||
// For other casts we abort.
|
|
||||||
case Stmt::CastExprClass: {
|
|
||||||
CastExpr *C = cast<CastExpr>(E);
|
|
||||||
Expr *SubExpr = C->getSubExpr();
|
|
||||||
|
|
||||||
if (SubExpr->getType()->isPointerType())
|
|
||||||
return EvalAddr(SubExpr);
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// C++ casts. For dynamic casts, static casts, and const casts, we
|
|
||||||
// are always converting from a pointer-to-pointer, so we just blow
|
|
||||||
// through the cast. In the case the dynamic cast doesn't fail
|
|
||||||
// (and return NULL), we take the conservative route and report cases
|
|
||||||
// where we return the address of a stack variable. For Reinterpre
|
|
||||||
case Stmt::CXXCastExprClass: {
|
|
||||||
CXXCastExpr *C = cast<CXXCastExpr>(E);
|
|
||||||
|
|
||||||
if (C->getOpcode() == CXXCastExpr::ReinterpretCast) {
|
|
||||||
Expr *S = C->getSubExpr();
|
|
||||||
if (S->getType()->isPointerType())
|
|
||||||
return EvalAddr(S);
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return EvalAddr(C->getSubExpr());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Everything else: we simply don't reason about them.
|
|
||||||
default:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// EvalVal - This function is complements EvalAddr in the mutual recursion.
|
|
||||||
/// See the comments for EvalAddr for more details.
|
|
||||||
static DeclRefExpr* EvalVal(Expr *E) {
|
|
||||||
|
|
||||||
// We should only be called for evaluating non-pointer expressions, or
|
|
||||||
// expressions with a pointer type that are not used as references but instead
|
|
||||||
// are l-values (e.g., DeclRefExpr with a pointer type).
|
|
||||||
|
|
||||||
// Our "symbolic interpreter" is just a dispatch off the currently
|
|
||||||
// viewed AST node. We then recursively traverse the AST by calling
|
|
||||||
// EvalAddr and EvalVal appropriately.
|
|
||||||
switch (E->getStmtClass()) {
|
|
||||||
|
|
||||||
case Stmt::DeclRefExprClass: {
|
|
||||||
// DeclRefExpr: the base case. When we hit a DeclRefExpr we are looking
|
|
||||||
// at code that refers to a variable's name. We check if it has local
|
|
||||||
// storage within the function, and if so, return the expression.
|
|
||||||
DeclRefExpr *DR = cast<DeclRefExpr>(E);
|
|
||||||
|
|
||||||
if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl()))
|
|
||||||
if(V->hasLocalStorage()) return DR;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Stmt::ParenExprClass:
|
|
||||||
// Ignore parentheses.
|
|
||||||
return EvalVal(cast<ParenExpr>(E)->getSubExpr());
|
|
||||||
|
|
||||||
case Stmt::UnaryOperatorClass: {
|
|
||||||
// The only unary operator that make sense to handle here
|
|
||||||
// is Deref. All others don't resolve to a "name." This includes
|
|
||||||
// handling all sorts of rvalues passed to a unary operator.
|
|
||||||
UnaryOperator *U = cast<UnaryOperator>(E);
|
|
||||||
|
|
||||||
if (U->getOpcode() == UnaryOperator::Deref)
|
|
||||||
return EvalAddr(U->getSubExpr());
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Stmt::ArraySubscriptExprClass: {
|
|
||||||
// Array subscripts are potential references to data on the stack. We
|
|
||||||
// retrieve the DeclRefExpr* for the array variable if it indeed
|
|
||||||
// has local storage.
|
|
||||||
return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase());
|
|
||||||
}
|
|
||||||
|
|
||||||
case Stmt::ConditionalOperatorClass: {
|
|
||||||
// For conditional operators we need to see if either the LHS or RHS are
|
|
||||||
// non-NULL DeclRefExpr's. If one is non-NULL, we return it.
|
|
||||||
ConditionalOperator *C = cast<ConditionalOperator>(E);
|
|
||||||
|
|
||||||
if (DeclRefExpr *LHS = EvalVal(C->getLHS()))
|
|
||||||
return LHS;
|
|
||||||
else
|
|
||||||
return EvalVal(C->getRHS());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accesses to members are potential references to data on the stack.
|
|
||||||
case Stmt::MemberExprClass: {
|
|
||||||
MemberExpr *M = cast<MemberExpr>(E);
|
|
||||||
|
|
||||||
// Check for indirect access. We only want direct field accesses.
|
|
||||||
if (!M->isArrow())
|
|
||||||
return EvalVal(M->getBase());
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Everything else: we simply don't reason about them.
|
|
||||||
default:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,45 +0,0 @@
|
|||||||
//===--- SemaExprCXX.cpp - Semantic Analysis for Expressions --------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file was developed by Bill Wendling and is distributed under the
|
|
||||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file implements semantic analysis for C++ expressions.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "Sema.h"
|
|
||||||
#include "clang/AST/ExprCXX.h"
|
|
||||||
#include "clang/AST/ASTContext.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
/// ParseCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.
|
|
||||||
Action::ExprResult
|
|
||||||
Sema::ParseCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind,
|
|
||||||
SourceLocation LAngleBracketLoc, TypeTy *Ty,
|
|
||||||
SourceLocation RAngleBracketLoc,
|
|
||||||
SourceLocation LParenLoc, ExprTy *E,
|
|
||||||
SourceLocation RParenLoc) {
|
|
||||||
CXXCastExpr::Opcode Op;
|
|
||||||
|
|
||||||
switch (Kind) {
|
|
||||||
default: assert(0 && "Unknown C++ cast!");
|
|
||||||
case tok::kw_const_cast: Op = CXXCastExpr::ConstCast; break;
|
|
||||||
case tok::kw_dynamic_cast: Op = CXXCastExpr::DynamicCast; break;
|
|
||||||
case tok::kw_reinterpret_cast: Op = CXXCastExpr::ReinterpretCast; break;
|
|
||||||
case tok::kw_static_cast: Op = CXXCastExpr::StaticCast; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CXXCastExpr(Op, QualType::getFromOpaquePtr(Ty), (Expr*)E, OpLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ParseCXXBoolLiteral - Parse {true,false} literals.
|
|
||||||
Action::ExprResult
|
|
||||||
Sema::ParseCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) {
|
|
||||||
assert((Kind != tok::kw_true || Kind != tok::kw_false) &&
|
|
||||||
"Unknown C++ Boolean value!");
|
|
||||||
return new CXXBoolLiteralExpr(Kind == tok::kw_true, Context.BoolTy, OpLoc);
|
|
||||||
}
|
|
||||||
@@ -1,617 +0,0 @@
|
|||||||
//===--- SemaStmt.cpp - Semantic Analysis for Statements ------------------===//
|
|
||||||
//
|
|
||||||
// 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 semantic analysis for statements.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "Sema.h"
|
|
||||||
#include "clang/AST/ASTContext.h"
|
|
||||||
#include "clang/AST/Expr.h"
|
|
||||||
#include "clang/AST/Stmt.h"
|
|
||||||
#include "clang/Parse/Scope.h"
|
|
||||||
#include "clang/Basic/Diagnostic.h"
|
|
||||||
#include "clang/Basic/LangOptions.h"
|
|
||||||
#include "clang/Lex/IdentifierTable.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
Sema::StmtResult Sema::ParseExprStmt(ExprTy *expr) {
|
|
||||||
Expr *E = static_cast<Expr*>(expr);
|
|
||||||
assert(E && "ParseExprStmt(): missing expression");
|
|
||||||
return E;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Sema::StmtResult Sema::ParseNullStmt(SourceLocation SemiLoc) {
|
|
||||||
return new NullStmt(SemiLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
Sema::StmtResult Sema::ParseDeclStmt(DeclTy *decl) {
|
|
||||||
if (decl)
|
|
||||||
return new DeclStmt(static_cast<Decl *>(decl));
|
|
||||||
else
|
|
||||||
return true; // error
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::ParseCompoundStmt(SourceLocation L, SourceLocation R,
|
|
||||||
StmtTy **elts, unsigned NumElts, bool isStmtExpr) {
|
|
||||||
Stmt **Elts = reinterpret_cast<Stmt**>(elts);
|
|
||||||
// If we're in C89 mode, check that we don't have any decls after stmts. If
|
|
||||||
// so, emit an extension diagnostic.
|
|
||||||
if (!getLangOptions().C99 && !getLangOptions().CPlusPlus) {
|
|
||||||
// Note that __extension__ can be around a decl.
|
|
||||||
unsigned i = 0;
|
|
||||||
// Skip over all declarations.
|
|
||||||
for (; i != NumElts && isa<DeclStmt>(Elts[i]); ++i)
|
|
||||||
/*empty*/;
|
|
||||||
|
|
||||||
// We found the end of the list or a statement. Scan for another declstmt.
|
|
||||||
for (; i != NumElts && !isa<DeclStmt>(Elts[i]); ++i)
|
|
||||||
/*empty*/;
|
|
||||||
|
|
||||||
if (i != NumElts) {
|
|
||||||
Decl *D = cast<DeclStmt>(Elts[i])->getDecl();
|
|
||||||
Diag(D->getLocation(), diag::ext_mixed_decls_code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Warn about unused expressions in statements.
|
|
||||||
for (unsigned i = 0; i != NumElts; ++i) {
|
|
||||||
Expr *E = dyn_cast<Expr>(Elts[i]);
|
|
||||||
if (!E) continue;
|
|
||||||
|
|
||||||
// Warn about expressions with unused results.
|
|
||||||
if (E->hasLocalSideEffect() || E->getType()->isVoidType())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// The last expr in a stmt expr really is used.
|
|
||||||
if (isStmtExpr && i == NumElts-1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/// DiagnoseDeadExpr - This expression is side-effect free and evaluated in
|
|
||||||
/// a context where the result is unused. Emit a diagnostic to warn about
|
|
||||||
/// this.
|
|
||||||
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E))
|
|
||||||
Diag(BO->getOperatorLoc(), diag::warn_unused_expr,
|
|
||||||
BO->getLHS()->getSourceRange(), BO->getRHS()->getSourceRange());
|
|
||||||
else if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
|
|
||||||
Diag(UO->getOperatorLoc(), diag::warn_unused_expr,
|
|
||||||
UO->getSubExpr()->getSourceRange());
|
|
||||||
else
|
|
||||||
Diag(E->getExprLoc(), diag::warn_unused_expr, E->getSourceRange());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CompoundStmt(Elts, NumElts, L, R);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::ParseCaseStmt(SourceLocation CaseLoc, ExprTy *lhsval,
|
|
||||||
SourceLocation DotDotDotLoc, ExprTy *rhsval,
|
|
||||||
SourceLocation ColonLoc, StmtTy *subStmt) {
|
|
||||||
Stmt *SubStmt = static_cast<Stmt*>(subStmt);
|
|
||||||
Expr *LHSVal = ((Expr *)lhsval), *RHSVal = ((Expr *)rhsval);
|
|
||||||
assert((LHSVal != 0) && "missing expression in case statement");
|
|
||||||
|
|
||||||
SourceLocation ExpLoc;
|
|
||||||
// C99 6.8.4.2p3: The expression shall be an integer constant.
|
|
||||||
if (!LHSVal->isIntegerConstantExpr(Context, &ExpLoc)) {
|
|
||||||
Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr,
|
|
||||||
LHSVal->getSourceRange());
|
|
||||||
return SubStmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GCC extension: The expression shall be an integer constant.
|
|
||||||
if (RHSVal && !RHSVal->isIntegerConstantExpr(Context, &ExpLoc)) {
|
|
||||||
Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr,
|
|
||||||
RHSVal->getSourceRange());
|
|
||||||
RHSVal = 0; // Recover by just forgetting about it.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SwitchStack.empty()) {
|
|
||||||
Diag(CaseLoc, diag::err_case_not_in_switch);
|
|
||||||
return SubStmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
CaseStmt *CS = new CaseStmt(LHSVal, RHSVal, SubStmt, CaseLoc);
|
|
||||||
SwitchStack.back()->addSwitchCase(CS);
|
|
||||||
return CS;
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::ParseDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
|
|
||||||
StmtTy *subStmt, Scope *CurScope) {
|
|
||||||
Stmt *SubStmt = static_cast<Stmt*>(subStmt);
|
|
||||||
|
|
||||||
if (SwitchStack.empty()) {
|
|
||||||
Diag(DefaultLoc, diag::err_default_not_in_switch);
|
|
||||||
return SubStmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultStmt *DS = new DefaultStmt(DefaultLoc, SubStmt);
|
|
||||||
SwitchStack.back()->addSwitchCase(DS);
|
|
||||||
|
|
||||||
return DS;
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::ParseLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
|
|
||||||
SourceLocation ColonLoc, StmtTy *subStmt) {
|
|
||||||
Stmt *SubStmt = static_cast<Stmt*>(subStmt);
|
|
||||||
// Look up the record for this label identifier.
|
|
||||||
LabelStmt *&LabelDecl = LabelMap[II];
|
|
||||||
|
|
||||||
// If not forward referenced or defined already, just create a new LabelStmt.
|
|
||||||
if (LabelDecl == 0)
|
|
||||||
return LabelDecl = new LabelStmt(IdentLoc, II, SubStmt);
|
|
||||||
|
|
||||||
assert(LabelDecl->getID() == II && "Label mismatch!");
|
|
||||||
|
|
||||||
// Otherwise, this label was either forward reference or multiply defined. If
|
|
||||||
// multiply defined, reject it now.
|
|
||||||
if (LabelDecl->getSubStmt()) {
|
|
||||||
Diag(IdentLoc, diag::err_redefinition_of_label, LabelDecl->getName());
|
|
||||||
Diag(LabelDecl->getIdentLoc(), diag::err_previous_definition);
|
|
||||||
return SubStmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, this label was forward declared, and we just found its real
|
|
||||||
// definition. Fill in the forward definition and return it.
|
|
||||||
LabelDecl->setIdentLoc(IdentLoc);
|
|
||||||
LabelDecl->setSubStmt(SubStmt);
|
|
||||||
return LabelDecl;
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::ParseIfStmt(SourceLocation IfLoc, ExprTy *CondVal,
|
|
||||||
StmtTy *ThenVal, SourceLocation ElseLoc,
|
|
||||||
StmtTy *ElseVal) {
|
|
||||||
Expr *condExpr = (Expr *)CondVal;
|
|
||||||
assert(condExpr && "ParseIfStmt(): missing expression");
|
|
||||||
|
|
||||||
DefaultFunctionArrayConversion(condExpr);
|
|
||||||
QualType condType = condExpr->getType();
|
|
||||||
|
|
||||||
if (!condType->isScalarType()) // C99 6.8.4.1p1
|
|
||||||
return Diag(IfLoc, diag::err_typecheck_statement_requires_scalar,
|
|
||||||
condType.getAsString(), condExpr->getSourceRange());
|
|
||||||
|
|
||||||
return new IfStmt(IfLoc, condExpr, (Stmt*)ThenVal, (Stmt*)ElseVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::StartSwitchStmt(ExprTy *cond) {
|
|
||||||
Expr *Cond = static_cast<Expr*>(cond);
|
|
||||||
|
|
||||||
// C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
|
|
||||||
UsualUnaryConversions(Cond);
|
|
||||||
|
|
||||||
SwitchStmt *SS = new SwitchStmt(Cond);
|
|
||||||
SwitchStack.push_back(SS);
|
|
||||||
return SS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
|
|
||||||
/// the specified width and sign. If an overflow occurs, detect it and emit
|
|
||||||
/// the specified diagnostic.
|
|
||||||
void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
|
|
||||||
unsigned NewWidth, bool NewSign,
|
|
||||||
SourceLocation Loc,
|
|
||||||
unsigned DiagID) {
|
|
||||||
// Perform a conversion to the promoted condition type if needed.
|
|
||||||
if (NewWidth > Val.getBitWidth()) {
|
|
||||||
// If this is an extension, just do it.
|
|
||||||
llvm::APSInt OldVal(Val);
|
|
||||||
Val.extend(NewWidth);
|
|
||||||
|
|
||||||
// If the input was signed and negative and the output is unsigned,
|
|
||||||
// warn.
|
|
||||||
if (!NewSign && OldVal.isSigned() && OldVal.isNegative())
|
|
||||||
Diag(Loc, DiagID, OldVal.toString(), Val.toString());
|
|
||||||
|
|
||||||
Val.setIsSigned(NewSign);
|
|
||||||
} else if (NewWidth < Val.getBitWidth()) {
|
|
||||||
// If this is a truncation, check for overflow.
|
|
||||||
llvm::APSInt ConvVal(Val);
|
|
||||||
ConvVal.trunc(NewWidth);
|
|
||||||
ConvVal.setIsSigned(NewSign);
|
|
||||||
ConvVal.extend(Val.getBitWidth());
|
|
||||||
ConvVal.setIsSigned(Val.isSigned());
|
|
||||||
if (ConvVal != Val)
|
|
||||||
Diag(Loc, DiagID, Val.toString(), ConvVal.toString());
|
|
||||||
|
|
||||||
// Regardless of whether a diagnostic was emitted, really do the
|
|
||||||
// truncation.
|
|
||||||
Val.trunc(NewWidth);
|
|
||||||
Val.setIsSigned(NewSign);
|
|
||||||
} else if (NewSign != Val.isSigned()) {
|
|
||||||
// Convert the sign to match the sign of the condition. This can cause
|
|
||||||
// overflow as well: unsigned(INTMIN)
|
|
||||||
llvm::APSInt OldVal(Val);
|
|
||||||
Val.setIsSigned(NewSign);
|
|
||||||
|
|
||||||
if (Val.isNegative()) // Sign bit changes meaning.
|
|
||||||
Diag(Loc, DiagID, OldVal.toString(), Val.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
struct CaseCompareFunctor {
|
|
||||||
bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
|
|
||||||
const llvm::APSInt &RHS) {
|
|
||||||
return LHS.first < RHS;
|
|
||||||
}
|
|
||||||
bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
|
|
||||||
const std::pair<llvm::APSInt, CaseStmt*> &RHS) {
|
|
||||||
return LHS.first < RHS.first;
|
|
||||||
}
|
|
||||||
bool operator()(const llvm::APSInt &LHS,
|
|
||||||
const std::pair<llvm::APSInt, CaseStmt*> &RHS) {
|
|
||||||
return LHS < RHS.first;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::FinishSwitchStmt(SourceLocation SwitchLoc, StmtTy *Switch, ExprTy *Body) {
|
|
||||||
Stmt *BodyStmt = (Stmt*)Body;
|
|
||||||
|
|
||||||
SwitchStmt *SS = SwitchStack.back();
|
|
||||||
assert(SS == (SwitchStmt*)Switch && "switch stack missing push/pop!");
|
|
||||||
|
|
||||||
SS->setBody(BodyStmt, SwitchLoc);
|
|
||||||
SwitchStack.pop_back();
|
|
||||||
|
|
||||||
Expr *CondExpr = SS->getCond();
|
|
||||||
QualType CondType = CondExpr->getType();
|
|
||||||
|
|
||||||
if (!CondType->isIntegerType()) { // C99 6.8.4.2p1
|
|
||||||
Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer,
|
|
||||||
CondType.getAsString(), CondExpr->getSourceRange());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the bitwidth of the switched-on value before promotions. We must
|
|
||||||
// convert the integer case values to this width before comparison.
|
|
||||||
unsigned CondWidth = Context.getTypeSize(CondType, SwitchLoc);
|
|
||||||
bool CondIsSigned = CondType->isSignedIntegerType();
|
|
||||||
|
|
||||||
// Accumulate all of the case values in a vector so that we can sort them
|
|
||||||
// and detect duplicates. This vector contains the APInt for the case after
|
|
||||||
// it has been converted to the condition type.
|
|
||||||
typedef llvm::SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy;
|
|
||||||
CaseValsTy CaseVals;
|
|
||||||
|
|
||||||
// Keep track of any GNU case ranges we see. The APSInt is the low value.
|
|
||||||
std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRanges;
|
|
||||||
|
|
||||||
DefaultStmt *TheDefaultStmt = 0;
|
|
||||||
|
|
||||||
bool CaseListIsErroneous = false;
|
|
||||||
|
|
||||||
for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
|
|
||||||
SC = SC->getNextSwitchCase()) {
|
|
||||||
|
|
||||||
if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC)) {
|
|
||||||
if (TheDefaultStmt) {
|
|
||||||
Diag(DS->getDefaultLoc(), diag::err_multiple_default_labels_defined);
|
|
||||||
Diag(TheDefaultStmt->getDefaultLoc(), diag::err_first_label);
|
|
||||||
|
|
||||||
// FIXME: Remove the default statement from the switch block so that
|
|
||||||
// we'll return a valid AST. This requires recursing down the
|
|
||||||
// AST and finding it, not something we are set up to do right now. For
|
|
||||||
// now, just lop the entire switch stmt out of the AST.
|
|
||||||
CaseListIsErroneous = true;
|
|
||||||
}
|
|
||||||
TheDefaultStmt = DS;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
CaseStmt *CS = cast<CaseStmt>(SC);
|
|
||||||
|
|
||||||
// We already verified that the expression has a i-c-e value (C99
|
|
||||||
// 6.8.4.2p3) - get that value now.
|
|
||||||
llvm::APSInt LoVal(32);
|
|
||||||
CS->getLHS()->isIntegerConstantExpr(LoVal, Context);
|
|
||||||
|
|
||||||
// Convert the value to the same width/sign as the condition.
|
|
||||||
ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
|
|
||||||
CS->getLHS()->getLocStart(),
|
|
||||||
diag::warn_case_value_overflow);
|
|
||||||
|
|
||||||
// If this is a case range, remember it in CaseRanges, otherwise CaseVals.
|
|
||||||
if (CS->getRHS())
|
|
||||||
CaseRanges.push_back(std::make_pair(LoVal, CS));
|
|
||||||
else
|
|
||||||
CaseVals.push_back(std::make_pair(LoVal, CS));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort all the scalar case values so we can easily detect duplicates.
|
|
||||||
std::stable_sort(CaseVals.begin(), CaseVals.end());
|
|
||||||
|
|
||||||
if (!CaseVals.empty()) {
|
|
||||||
for (unsigned i = 0, e = CaseVals.size()-1; i != e; ++i) {
|
|
||||||
if (CaseVals[i].first == CaseVals[i+1].first) {
|
|
||||||
// If we have a duplicate, report it.
|
|
||||||
Diag(CaseVals[i+1].second->getLHS()->getLocStart(),
|
|
||||||
diag::err_duplicate_case, CaseVals[i].first.toString());
|
|
||||||
Diag(CaseVals[i].second->getLHS()->getLocStart(),
|
|
||||||
diag::err_duplicate_case_prev);
|
|
||||||
// FIXME: We really want to remove the bogus case stmt from the substmt,
|
|
||||||
// but we have no way to do this right now.
|
|
||||||
CaseListIsErroneous = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detect duplicate case ranges, which usually don't exist at all in the first
|
|
||||||
// place.
|
|
||||||
if (!CaseRanges.empty()) {
|
|
||||||
// Sort all the case ranges by their low value so we can easily detect
|
|
||||||
// overlaps between ranges.
|
|
||||||
std::stable_sort(CaseRanges.begin(), CaseRanges.end());
|
|
||||||
|
|
||||||
// Scan the ranges, computing the high values and removing empty ranges.
|
|
||||||
std::vector<llvm::APSInt> HiVals;
|
|
||||||
for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) {
|
|
||||||
CaseStmt *CR = CaseRanges[i].second;
|
|
||||||
llvm::APSInt HiVal(32);
|
|
||||||
CR->getRHS()->isIntegerConstantExpr(HiVal, Context);
|
|
||||||
|
|
||||||
// Convert the value to the same width/sign as the condition.
|
|
||||||
ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
|
|
||||||
CR->getRHS()->getLocStart(),
|
|
||||||
diag::warn_case_value_overflow);
|
|
||||||
|
|
||||||
// If the low value is bigger than the high value, the case is empty.
|
|
||||||
if (CaseRanges[i].first > HiVal) {
|
|
||||||
Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range,
|
|
||||||
SourceRange(CR->getLHS()->getLocStart(),
|
|
||||||
CR->getRHS()->getLocEnd()));
|
|
||||||
CaseRanges.erase(CaseRanges.begin()+i);
|
|
||||||
--i, --e;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
HiVals.push_back(HiVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rescan the ranges, looking for overlap with singleton values and other
|
|
||||||
// ranges. Since the range list is sorted, we only need to compare case
|
|
||||||
// ranges with their neighbors.
|
|
||||||
for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) {
|
|
||||||
llvm::APSInt &CRLo = CaseRanges[i].first;
|
|
||||||
llvm::APSInt &CRHi = HiVals[i];
|
|
||||||
CaseStmt *CR = CaseRanges[i].second;
|
|
||||||
|
|
||||||
// Check to see whether the case range overlaps with any singleton cases.
|
|
||||||
CaseStmt *OverlapStmt = 0;
|
|
||||||
llvm::APSInt OverlapVal(32);
|
|
||||||
|
|
||||||
// Find the smallest value >= the lower bound. If I is in the case range,
|
|
||||||
// then we have overlap.
|
|
||||||
CaseValsTy::iterator I = std::lower_bound(CaseVals.begin(),
|
|
||||||
CaseVals.end(), CRLo,
|
|
||||||
CaseCompareFunctor());
|
|
||||||
if (I != CaseVals.end() && I->first < CRHi) {
|
|
||||||
OverlapVal = I->first; // Found overlap with scalar.
|
|
||||||
OverlapStmt = I->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the smallest value bigger than the upper bound.
|
|
||||||
I = std::upper_bound(I, CaseVals.end(), CRHi, CaseCompareFunctor());
|
|
||||||
if (I != CaseVals.begin() && (I-1)->first >= CRLo) {
|
|
||||||
OverlapVal = (I-1)->first; // Found overlap with scalar.
|
|
||||||
OverlapStmt = (I-1)->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check to see if this case stmt overlaps with the subsequent case range.
|
|
||||||
if (i && CRLo <= HiVals[i-1]) {
|
|
||||||
OverlapVal = HiVals[i-1]; // Found overlap with range.
|
|
||||||
OverlapStmt = CaseRanges[i-1].second;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OverlapStmt) {
|
|
||||||
// If we have a duplicate, report it.
|
|
||||||
Diag(CR->getLHS()->getLocStart(),
|
|
||||||
diag::err_duplicate_case, OverlapVal.toString());
|
|
||||||
Diag(OverlapStmt->getLHS()->getLocStart(),
|
|
||||||
diag::err_duplicate_case_prev);
|
|
||||||
// FIXME: We really want to remove the bogus case stmt from the substmt,
|
|
||||||
// but we have no way to do this right now.
|
|
||||||
CaseListIsErroneous = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: If the case list was broken is some way, we don't have a good system
|
|
||||||
// to patch it up. Instead, just return the whole substmt as broken.
|
|
||||||
if (CaseListIsErroneous)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return SS;
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::ParseWhileStmt(SourceLocation WhileLoc, ExprTy *Cond, StmtTy *Body) {
|
|
||||||
Expr *condExpr = (Expr *)Cond;
|
|
||||||
assert(condExpr && "ParseWhileStmt(): missing expression");
|
|
||||||
|
|
||||||
DefaultFunctionArrayConversion(condExpr);
|
|
||||||
QualType condType = condExpr->getType();
|
|
||||||
|
|
||||||
if (!condType->isScalarType()) // C99 6.8.5p2
|
|
||||||
return Diag(WhileLoc, diag::err_typecheck_statement_requires_scalar,
|
|
||||||
condType.getAsString(), condExpr->getSourceRange());
|
|
||||||
|
|
||||||
return new WhileStmt(condExpr, (Stmt*)Body, WhileLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::ParseDoStmt(SourceLocation DoLoc, StmtTy *Body,
|
|
||||||
SourceLocation WhileLoc, ExprTy *Cond) {
|
|
||||||
Expr *condExpr = (Expr *)Cond;
|
|
||||||
assert(condExpr && "ParseDoStmt(): missing expression");
|
|
||||||
|
|
||||||
DefaultFunctionArrayConversion(condExpr);
|
|
||||||
QualType condType = condExpr->getType();
|
|
||||||
|
|
||||||
if (!condType->isScalarType()) // C99 6.8.5p2
|
|
||||||
return Diag(DoLoc, diag::err_typecheck_statement_requires_scalar,
|
|
||||||
condType.getAsString(), condExpr->getSourceRange());
|
|
||||||
|
|
||||||
return new DoStmt((Stmt*)Body, condExpr, DoLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::ParseForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
|
|
||||||
StmtTy *first, ExprTy *second, ExprTy *third,
|
|
||||||
SourceLocation RParenLoc, StmtTy *body) {
|
|
||||||
Stmt *First = static_cast<Stmt*>(first);
|
|
||||||
Expr *Second = static_cast<Expr*>(second);
|
|
||||||
Expr *Third = static_cast<Expr*>(third);
|
|
||||||
Stmt *Body = static_cast<Stmt*>(body);
|
|
||||||
|
|
||||||
if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) {
|
|
||||||
// C99 6.8.5p3: The declaration part of a 'for' statement shall only declare
|
|
||||||
// identifiers for objects having storage class 'auto' or 'register'.
|
|
||||||
for (Decl *D = DS->getDecl(); D; D = D->getNextDeclarator()) {
|
|
||||||
BlockVarDecl *BVD = dyn_cast<BlockVarDecl>(D);
|
|
||||||
if (BVD && !BVD->hasLocalStorage())
|
|
||||||
BVD = 0;
|
|
||||||
if (BVD == 0)
|
|
||||||
Diag(D->getLocation(), diag::err_non_variable_decl_in_for);
|
|
||||||
// FIXME: mark decl erroneous!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Second) {
|
|
||||||
DefaultFunctionArrayConversion(Second);
|
|
||||||
QualType SecondType = Second->getType();
|
|
||||||
|
|
||||||
if (!SecondType->isScalarType()) // C99 6.8.5p2
|
|
||||||
return Diag(ForLoc, diag::err_typecheck_statement_requires_scalar,
|
|
||||||
SecondType.getAsString(), Second->getSourceRange());
|
|
||||||
}
|
|
||||||
return new ForStmt(First, Second, Third, Body, ForLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::ParseGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
|
|
||||||
IdentifierInfo *LabelII) {
|
|
||||||
// Look up the record for this label identifier.
|
|
||||||
LabelStmt *&LabelDecl = LabelMap[LabelII];
|
|
||||||
|
|
||||||
// If we haven't seen this label yet, create a forward reference.
|
|
||||||
if (LabelDecl == 0)
|
|
||||||
LabelDecl = new LabelStmt(LabelLoc, LabelII, 0);
|
|
||||||
|
|
||||||
return new GotoStmt(LabelDecl, GotoLoc, LabelLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::ParseIndirectGotoStmt(SourceLocation GotoLoc,SourceLocation StarLoc,
|
|
||||||
ExprTy *DestExp) {
|
|
||||||
// FIXME: Verify that the operand is convertible to void*.
|
|
||||||
|
|
||||||
return new IndirectGotoStmt((Expr*)DestExp);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::ParseContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
|
|
||||||
Scope *S = CurScope->getContinueParent();
|
|
||||||
if (!S) {
|
|
||||||
// C99 6.8.6.2p1: A break shall appear only in or as a loop body.
|
|
||||||
Diag(ContinueLoc, diag::err_continue_not_in_loop);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ContinueStmt(ContinueLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::ParseBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
|
|
||||||
Scope *S = CurScope->getBreakParent();
|
|
||||||
if (!S) {
|
|
||||||
// C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body.
|
|
||||||
Diag(BreakLoc, diag::err_break_not_in_loop_or_switch);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BreakStmt(BreakLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Action::StmtResult
|
|
||||||
Sema::ParseReturnStmt(SourceLocation ReturnLoc, ExprTy *rex) {
|
|
||||||
Expr *RetValExp = static_cast<Expr *>(rex);
|
|
||||||
QualType lhsType = CurFunctionDecl->getResultType();
|
|
||||||
|
|
||||||
if (lhsType->isVoidType()) {
|
|
||||||
if (RetValExp) // C99 6.8.6.4p1 (ext_ since GCC warns)
|
|
||||||
Diag(ReturnLoc, diag::ext_return_has_expr,
|
|
||||||
CurFunctionDecl->getIdentifier()->getName(),
|
|
||||||
RetValExp->getSourceRange());
|
|
||||||
return new ReturnStmt(ReturnLoc, RetValExp);
|
|
||||||
} else {
|
|
||||||
if (!RetValExp) {
|
|
||||||
const char *funcName = CurFunctionDecl->getIdentifier()->getName();
|
|
||||||
if (getLangOptions().C99) // C99 6.8.6.4p1 (ext_ since GCC warns)
|
|
||||||
Diag(ReturnLoc, diag::ext_return_missing_expr, funcName);
|
|
||||||
else // C90 6.6.6.4p4
|
|
||||||
Diag(ReturnLoc, diag::warn_return_missing_expr, funcName);
|
|
||||||
return new ReturnStmt(ReturnLoc, (Expr*)0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// we have a non-void function with an expression, continue checking
|
|
||||||
QualType rhsType = RetValExp->getType();
|
|
||||||
|
|
||||||
// C99 6.8.6.4p3(136): The return statement is not an assignment. The
|
|
||||||
// overlap restriction of subclause 6.5.16.1 does not apply to the case of
|
|
||||||
// function return.
|
|
||||||
AssignmentCheckResult result = CheckSingleAssignmentConstraints(lhsType,
|
|
||||||
RetValExp);
|
|
||||||
|
|
||||||
// decode the result (notice that extensions still return a type).
|
|
||||||
switch (result) {
|
|
||||||
case Compatible:
|
|
||||||
break;
|
|
||||||
case Incompatible:
|
|
||||||
Diag(ReturnLoc, diag::err_typecheck_return_incompatible,
|
|
||||||
lhsType.getAsString(), rhsType.getAsString(),
|
|
||||||
RetValExp->getSourceRange());
|
|
||||||
break;
|
|
||||||
case PointerFromInt:
|
|
||||||
// check for null pointer constant (C99 6.3.2.3p3)
|
|
||||||
if (!RetValExp->isNullPointerConstant(Context)) {
|
|
||||||
Diag(ReturnLoc, diag::ext_typecheck_return_pointer_int,
|
|
||||||
lhsType.getAsString(), rhsType.getAsString(),
|
|
||||||
RetValExp->getSourceRange());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case IntFromPointer:
|
|
||||||
Diag(ReturnLoc, diag::ext_typecheck_return_pointer_int,
|
|
||||||
lhsType.getAsString(), rhsType.getAsString(),
|
|
||||||
RetValExp->getSourceRange());
|
|
||||||
break;
|
|
||||||
case IncompatiblePointer:
|
|
||||||
Diag(ReturnLoc, diag::ext_typecheck_return_incompatible_pointer,
|
|
||||||
lhsType.getAsString(), rhsType.getAsString(),
|
|
||||||
RetValExp->getSourceRange());
|
|
||||||
break;
|
|
||||||
case CompatiblePointerDiscardsQualifiers:
|
|
||||||
Diag(ReturnLoc, diag::ext_typecheck_return_discards_qualifiers,
|
|
||||||
lhsType.getAsString(), rhsType.getAsString(),
|
|
||||||
RetValExp->getSourceRange());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RetValExp) CheckReturnStackAddr(RetValExp, lhsType, ReturnLoc);
|
|
||||||
|
|
||||||
return new ReturnStmt(ReturnLoc, (Expr*)RetValExp);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,348 +0,0 @@
|
|||||||
//===--- SemaType.cpp - Semantic Analysis for Types -----------------------===//
|
|
||||||
//
|
|
||||||
// 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 semantic analysis.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "Sema.h"
|
|
||||||
#include "clang/AST/ASTContext.h"
|
|
||||||
#include "clang/AST/Decl.h"
|
|
||||||
#include "clang/Parse/DeclSpec.h"
|
|
||||||
#include "clang/Lex/IdentifierTable.h"
|
|
||||||
#include "clang/Basic/LangOptions.h"
|
|
||||||
using namespace clang;
|
|
||||||
|
|
||||||
/// ConvertDeclSpecToType - Convert the specified declspec to the appropriate
|
|
||||||
/// type object. This returns null on error.
|
|
||||||
static QualType ConvertDeclSpecToType(const DeclSpec &DS, ASTContext &Ctx) {
|
|
||||||
// FIXME: Should move the logic from DeclSpec::Finish to here for validity
|
|
||||||
// checking.
|
|
||||||
|
|
||||||
switch (DS.getTypeSpecType()) {
|
|
||||||
default: return QualType(); // FIXME: Handle unimp cases!
|
|
||||||
case DeclSpec::TST_void: return Ctx.VoidTy;
|
|
||||||
case DeclSpec::TST_char:
|
|
||||||
if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified)
|
|
||||||
return Ctx.CharTy;
|
|
||||||
else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed)
|
|
||||||
return Ctx.SignedCharTy;
|
|
||||||
else {
|
|
||||||
assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned &&
|
|
||||||
"Unknown TSS value");
|
|
||||||
return Ctx.UnsignedCharTy;
|
|
||||||
}
|
|
||||||
case DeclSpec::TST_unspecified: // Unspecific typespec defaults to int.
|
|
||||||
case DeclSpec::TST_int: {
|
|
||||||
QualType Result;
|
|
||||||
if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) {
|
|
||||||
switch (DS.getTypeSpecWidth()) {
|
|
||||||
case DeclSpec::TSW_unspecified: Result = Ctx.IntTy; break;
|
|
||||||
case DeclSpec::TSW_short: Result = Ctx.ShortTy; break;
|
|
||||||
case DeclSpec::TSW_long: Result = Ctx.LongTy; break;
|
|
||||||
case DeclSpec::TSW_longlong: Result = Ctx.LongLongTy; break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (DS.getTypeSpecWidth()) {
|
|
||||||
case DeclSpec::TSW_unspecified: Result = Ctx.UnsignedIntTy; break;
|
|
||||||
case DeclSpec::TSW_short: Result = Ctx.UnsignedShortTy; break;
|
|
||||||
case DeclSpec::TSW_long: Result = Ctx.UnsignedLongTy; break;
|
|
||||||
case DeclSpec::TSW_longlong: Result = Ctx.UnsignedLongLongTy; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Handle complex integer types.
|
|
||||||
if (DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified)
|
|
||||||
return Result;
|
|
||||||
assert(DS.getTypeSpecComplex() == DeclSpec::TSC_complex &&
|
|
||||||
"FIXME: imaginary types not supported yet!");
|
|
||||||
return Ctx.getComplexType(Result);
|
|
||||||
}
|
|
||||||
case DeclSpec::TST_float:
|
|
||||||
if (DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified)
|
|
||||||
return Ctx.FloatTy;
|
|
||||||
assert(DS.getTypeSpecComplex() == DeclSpec::TSC_complex &&
|
|
||||||
"FIXME: imaginary types not supported yet!");
|
|
||||||
return Ctx.getComplexType(Ctx.FloatTy);
|
|
||||||
|
|
||||||
case DeclSpec::TST_double: {
|
|
||||||
bool isLong = DS.getTypeSpecWidth() == DeclSpec::TSW_long;
|
|
||||||
QualType T = isLong ? Ctx.LongDoubleTy : Ctx.DoubleTy;
|
|
||||||
if (DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified)
|
|
||||||
return T;
|
|
||||||
assert(DS.getTypeSpecComplex() == DeclSpec::TSC_complex &&
|
|
||||||
"FIXME: imaginary types not supported yet!");
|
|
||||||
return Ctx.getComplexType(T);
|
|
||||||
}
|
|
||||||
case DeclSpec::TST_bool: // _Bool or bool
|
|
||||||
return Ctx.BoolTy;
|
|
||||||
case DeclSpec::TST_decimal32: // _Decimal32
|
|
||||||
case DeclSpec::TST_decimal64: // _Decimal64
|
|
||||||
case DeclSpec::TST_decimal128: // _Decimal128
|
|
||||||
assert(0 && "FIXME: GNU decimal extensions not supported yet!");
|
|
||||||
case DeclSpec::TST_enum:
|
|
||||||
case DeclSpec::TST_union:
|
|
||||||
case DeclSpec::TST_struct: {
|
|
||||||
Decl *D = static_cast<Decl *>(DS.getTypeRep());
|
|
||||||
assert(D && "Didn't get a decl for a enum/union/struct?");
|
|
||||||
assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
|
|
||||||
DS.getTypeSpecSign() == 0 &&
|
|
||||||
"Can't handle qualifiers on typedef names yet!");
|
|
||||||
// TypeQuals handled by caller.
|
|
||||||
return Ctx.getTagDeclType(cast<TagDecl>(D));
|
|
||||||
}
|
|
||||||
case DeclSpec::TST_typedef: {
|
|
||||||
Decl *D = static_cast<Decl *>(DS.getTypeRep());
|
|
||||||
assert(D && "Didn't get a decl for a typedef?");
|
|
||||||
assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
|
|
||||||
DS.getTypeSpecSign() == 0 &&
|
|
||||||
"Can't handle qualifiers on typedef names yet!");
|
|
||||||
// FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so
|
|
||||||
// we have this "hack" for now...
|
|
||||||
if (isa<ObjcInterfaceDecl>(D))
|
|
||||||
return Ctx.getObjcInterfaceType(cast<ObjcInterfaceDecl>(D));
|
|
||||||
// TypeQuals handled by caller.
|
|
||||||
return Ctx.getTypedefType(cast<TypedefDecl>(D));
|
|
||||||
}
|
|
||||||
case DeclSpec::TST_typeofType: {
|
|
||||||
QualType T = QualType::getFromOpaquePtr(DS.getTypeRep());
|
|
||||||
assert(!T.isNull() && "Didn't get a type for typeof?");
|
|
||||||
// TypeQuals handled by caller.
|
|
||||||
return Ctx.getTypeOfType(T);
|
|
||||||
}
|
|
||||||
case DeclSpec::TST_typeofExpr: {
|
|
||||||
Expr *E = static_cast<Expr *>(DS.getTypeRep());
|
|
||||||
assert(E && "Didn't get an expression for typeof?");
|
|
||||||
// TypeQuals handled by caller.
|
|
||||||
return Ctx.getTypeOfExpr(E);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// GetTypeForDeclarator - Convert the type for the specified declarator to Type
|
|
||||||
/// instances.
|
|
||||||
QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
|
|
||||||
// long long is a C99 feature.
|
|
||||||
if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x &&
|
|
||||||
D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong)
|
|
||||||
Diag(D.getDeclSpec().getTypeSpecWidthLoc(), diag::ext_longlong);
|
|
||||||
|
|
||||||
QualType T = ConvertDeclSpecToType(D.getDeclSpec(), Context);
|
|
||||||
|
|
||||||
// Apply const/volatile/restrict qualifiers to T.
|
|
||||||
T = T.getQualifiedType(D.getDeclSpec().getTypeQualifiers());
|
|
||||||
|
|
||||||
// Walk the DeclTypeInfo, building the recursive type as we go. DeclTypeInfos
|
|
||||||
// are ordered from the identifier out, which is opposite of what we want :).
|
|
||||||
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
|
|
||||||
const DeclaratorChunk &DeclType = D.getTypeObject(e-i-1);
|
|
||||||
switch (DeclType.Kind) {
|
|
||||||
default: assert(0 && "Unknown decltype!");
|
|
||||||
case DeclaratorChunk::Pointer:
|
|
||||||
if (T->isReferenceType()) {
|
|
||||||
// C++ 8.3.2p4: There shall be no ... pointers to references ...
|
|
||||||
Diag(D.getIdentifierLoc(), diag::err_illegal_decl_pointer_to_reference,
|
|
||||||
D.getIdentifier()->getName());
|
|
||||||
D.setInvalidType(true);
|
|
||||||
T = Context.IntTy;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the pointer typequals to the pointer object.
|
|
||||||
T = Context.getPointerType(T).getQualifiedType(DeclType.Ptr.TypeQuals);
|
|
||||||
break;
|
|
||||||
case DeclaratorChunk::Reference:
|
|
||||||
if (const ReferenceType *RT = T->getAsReferenceType()) {
|
|
||||||
// C++ 8.3.2p4: There shall be no references to references ...
|
|
||||||
Diag(D.getIdentifierLoc(),
|
|
||||||
diag::err_illegal_decl_reference_to_reference,
|
|
||||||
D.getIdentifier()->getName());
|
|
||||||
D.setInvalidType(true);
|
|
||||||
T = RT->getReferenceeType();
|
|
||||||
}
|
|
||||||
|
|
||||||
T = Context.getReferenceType(T);
|
|
||||||
break;
|
|
||||||
case DeclaratorChunk::Array: {
|
|
||||||
const DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr;
|
|
||||||
Expr *ArraySize = static_cast<Expr*>(ATI.NumElts);
|
|
||||||
ArrayType::ArraySizeModifier ASM;
|
|
||||||
if (ATI.isStar)
|
|
||||||
ASM = ArrayType::Star;
|
|
||||||
else if (ATI.hasStatic)
|
|
||||||
ASM = ArrayType::Static;
|
|
||||||
else
|
|
||||||
ASM = ArrayType::Normal;
|
|
||||||
|
|
||||||
// C99 6.7.5.2p1: If the element type is an incomplete or function type,
|
|
||||||
// reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
|
|
||||||
if (T->isIncompleteType()) {
|
|
||||||
Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_incomplete_type,
|
|
||||||
T.getAsString());
|
|
||||||
T = Context.IntTy;
|
|
||||||
D.setInvalidType(true);
|
|
||||||
} else if (T->isFunctionType()) {
|
|
||||||
Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_functions,
|
|
||||||
D.getIdentifier()->getName());
|
|
||||||
T = Context.getPointerType(T);
|
|
||||||
D.setInvalidType(true);
|
|
||||||
} else if (const ReferenceType *RT = T->getAsReferenceType()) {
|
|
||||||
// C++ 8.3.2p4: There shall be no ... arrays of references ...
|
|
||||||
Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_references,
|
|
||||||
D.getIdentifier()->getName());
|
|
||||||
T = RT->getReferenceeType();
|
|
||||||
D.setInvalidType(true);
|
|
||||||
} else if (const RecordType *EltTy = T->getAsRecordType()) {
|
|
||||||
// If the element type is a struct or union that contains a variadic
|
|
||||||
// array, reject it: C99 6.7.2.1p2.
|
|
||||||
if (EltTy->getDecl()->hasFlexibleArrayMember()) {
|
|
||||||
Diag(DeclType.Loc, diag::err_flexible_array_in_array,
|
|
||||||
T.getAsString());
|
|
||||||
T = Context.IntTy;
|
|
||||||
D.setInvalidType(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// C99 6.7.5.2p1: The size expression shall have integer type.
|
|
||||||
if (ArraySize && !ArraySize->getType()->isIntegerType()) {
|
|
||||||
Diag(ArraySize->getLocStart(), diag::err_array_size_non_int,
|
|
||||||
ArraySize->getType().getAsString(), ArraySize->getSourceRange());
|
|
||||||
D.setInvalidType(true);
|
|
||||||
}
|
|
||||||
llvm::APSInt ConstVal(32);
|
|
||||||
// If no expression was provided, we consider it a VLA.
|
|
||||||
if (!ArraySize || !ArraySize->isIntegerConstantExpr(ConstVal, Context))
|
|
||||||
T = Context.getVariableArrayType(T, ArraySize, ASM, ATI.TypeQuals);
|
|
||||||
else {
|
|
||||||
// C99 6.7.5.2p1: If the expression is a constant expression, it shall
|
|
||||||
// have a value greater than zero.
|
|
||||||
if (ConstVal.isSigned()) {
|
|
||||||
if (ConstVal.isNegative()) {
|
|
||||||
Diag(ArraySize->getLocStart(),
|
|
||||||
diag::err_typecheck_negative_array_size,
|
|
||||||
ArraySize->getSourceRange());
|
|
||||||
D.setInvalidType(true);
|
|
||||||
} else if (ConstVal == 0) {
|
|
||||||
// GCC accepts zero sized static arrays.
|
|
||||||
Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size,
|
|
||||||
ArraySize->getSourceRange());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
T = Context.getConstantArrayType(T, ConstVal, ASM, ATI.TypeQuals);
|
|
||||||
}
|
|
||||||
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
|
|
||||||
if (!getLangOptions().C99 &&
|
|
||||||
(ASM != ArrayType::Normal ||
|
|
||||||
(ArraySize && !ArraySize->isIntegerConstantExpr(Context))))
|
|
||||||
Diag(D.getIdentifierLoc(), diag::ext_vla);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DeclaratorChunk::Function:
|
|
||||||
// If the function declarator has a prototype (i.e. it is not () and
|
|
||||||
// does not have a K&R-style identifier list), then the arguments are part
|
|
||||||
// of the type, otherwise the argument list is ().
|
|
||||||
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
|
|
||||||
if (!FTI.hasPrototype) {
|
|
||||||
// Simple void foo(), where the incoming T is the result type.
|
|
||||||
T = Context.getFunctionTypeNoProto(T);
|
|
||||||
|
|
||||||
// C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition.
|
|
||||||
if (FTI.NumArgs != 0)
|
|
||||||
Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Otherwise, we have a function with an argument list that is
|
|
||||||
// potentially variadic.
|
|
||||||
llvm::SmallVector<QualType, 16> ArgTys;
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
|
|
||||||
QualType ArgTy = QualType::getFromOpaquePtr(FTI.ArgInfo[i].TypeInfo);
|
|
||||||
assert(!ArgTy.isNull() && "Couldn't parse type?");
|
|
||||||
//
|
|
||||||
// Perform the default function/array conversion (C99 6.7.5.3p[7,8]).
|
|
||||||
// This matches the conversion that is done in
|
|
||||||
// Sema::ParseParamDeclarator(). Without this conversion, the
|
|
||||||
// argument type in the function prototype *will not* match the
|
|
||||||
// type in ParmVarDecl (which makes the code generator unhappy).
|
|
||||||
//
|
|
||||||
// FIXME: We still apparently need the conversion in
|
|
||||||
// Sema::ParseParamDeclarator(). This doesn't make any sense, since
|
|
||||||
// it should be driving off the type being created here.
|
|
||||||
//
|
|
||||||
// FIXME: If a source translation tool needs to see the original type,
|
|
||||||
// then we need to consider storing both types somewhere...
|
|
||||||
//
|
|
||||||
if (const ArrayType *AT = ArgTy->getAsArrayType())
|
|
||||||
ArgTy = Context.getPointerType(AT->getElementType());
|
|
||||||
else if (ArgTy->isFunctionType())
|
|
||||||
ArgTy = Context.getPointerType(ArgTy);
|
|
||||||
// Look for 'void'. void is allowed only as a single argument to a
|
|
||||||
// function with no other parameters (C99 6.7.5.3p10). We record
|
|
||||||
// int(void) as a FunctionTypeProto with an empty argument list.
|
|
||||||
else if (ArgTy->isVoidType()) {
|
|
||||||
// If this is something like 'float(int, void)', reject it. 'void'
|
|
||||||
// is an incomplete type (C99 6.2.5p19) and function decls cannot
|
|
||||||
// have arguments of incomplete type.
|
|
||||||
if (FTI.NumArgs != 1 || FTI.isVariadic) {
|
|
||||||
Diag(DeclType.Loc, diag::err_void_only_param);
|
|
||||||
ArgTy = Context.IntTy;
|
|
||||||
FTI.ArgInfo[i].TypeInfo = ArgTy.getAsOpaquePtr();
|
|
||||||
} else if (FTI.ArgInfo[i].Ident) {
|
|
||||||
// Reject, but continue to parse 'int(void abc)'.
|
|
||||||
Diag(FTI.ArgInfo[i].IdentLoc,
|
|
||||||
diag::err_param_with_void_type);
|
|
||||||
ArgTy = Context.IntTy;
|
|
||||||
FTI.ArgInfo[i].TypeInfo = ArgTy.getAsOpaquePtr();
|
|
||||||
} else {
|
|
||||||
// Reject, but continue to parse 'float(const void)'.
|
|
||||||
if (ArgTy.getQualifiers())
|
|
||||||
Diag(DeclType.Loc, diag::err_void_param_qualified);
|
|
||||||
|
|
||||||
// Do not add 'void' to the ArgTys list.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ArgTys.push_back(ArgTy);
|
|
||||||
}
|
|
||||||
T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(),
|
|
||||||
FTI.isVariadic);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return T;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sema::TypeResult Sema::ParseTypeName(Scope *S, Declarator &D) {
|
|
||||||
// C99 6.7.6: Type names have no identifier. This is already validated by
|
|
||||||
// the parser.
|
|
||||||
assert(D.getIdentifier() == 0 && "Type name should have no identifier!");
|
|
||||||
|
|
||||||
QualType T = GetTypeForDeclarator(D, S);
|
|
||||||
|
|
||||||
assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
|
|
||||||
|
|
||||||
// In this context, we *do not* check D.getInvalidType(). If the declarator
|
|
||||||
// type was invalid, GetTypeForDeclarator() still returns a "valid" type,
|
|
||||||
// though it will not reflect the user specified type.
|
|
||||||
return T.getAsOpaquePtr();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called from Parser::ParseParenDeclarator().
|
|
||||||
Sema::TypeResult Sema::ParseParamDeclaratorType(Scope *S, Declarator &D) {
|
|
||||||
// Note: parameters have identifiers, but we don't care about them here, we
|
|
||||||
// just want the type converted.
|
|
||||||
QualType T = GetTypeForDeclarator(D, S);
|
|
||||||
|
|
||||||
assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
|
|
||||||
|
|
||||||
// In this context, we *do not* check D.getInvalidType(). If the declarator
|
|
||||||
// type was invalid, GetTypeForDeclarator() still returns a "valid" type,
|
|
||||||
// though it will not reflect the user specified type.
|
|
||||||
return T.getAsOpaquePtr();
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
//===---------------------------------------------------------------------===//
|
|
||||||
// Minor random things that can be improved
|
|
||||||
//===---------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
Lexer-related diagnostics should point to the problematic character, not the
|
|
||||||
start of the token. For example:
|
|
||||||
|
|
||||||
int y = 0000\
|
|
||||||
00080;
|
|
||||||
|
|
||||||
diag.c:4:9: error: invalid digit '8' in octal constant
|
|
||||||
int y = 0000\
|
|
||||||
^
|
|
||||||
|
|
||||||
should be:
|
|
||||||
|
|
||||||
diag.c:4:9: error: invalid digit '8' in octal constant
|
|
||||||
00080;
|
|
||||||
^
|
|
||||||
|
|
||||||
This specific diagnostic is implemented, but others should be updated.
|
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,880 +0,0 @@
|
|||||||
// !$*UTF8*$!
|
|
||||||
{
|
|
||||||
archiveVersion = 1;
|
|
||||||
classes = {
|
|
||||||
};
|
|
||||||
objectVersion = 42;
|
|
||||||
objects = {
|
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
|
||||||
1A30A9E90B93A4C800201A91 /* ExprCXX.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A30A9E80B93A4C800201A91 /* ExprCXX.h */; };
|
|
||||||
1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A7342470C7B57D500122F56 /* CGObjC.cpp */; };
|
|
||||||
1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */; };
|
|
||||||
1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; };
|
|
||||||
1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; };
|
|
||||||
35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */; };
|
|
||||||
355CF6840C90A8D400A08AA3 /* DeadStores.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 355CF6830C90A8D400A08AA3 /* DeadStores.cpp */; };
|
|
||||||
356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */; };
|
|
||||||
84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */; };
|
|
||||||
84D9A88C0C1A581300AC7ABC /* AttributeList.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84D9A88B0C1A581300AC7ABC /* AttributeList.h */; };
|
|
||||||
DE01DA490B12ADA300AC22CE /* PPCallbacks.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE01DA480B12ADA300AC22CE /* PPCallbacks.h */; };
|
|
||||||
DE06756C0C051CFE00EBBFD8 /* ParseExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */; };
|
|
||||||
DE06B73E0A8307640050E87E /* LangOptions.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06B73D0A8307640050E87E /* LangOptions.h */; };
|
|
||||||
DE06BECB0A854E4B0050E87E /* Scope.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06BECA0A854E4B0050E87E /* Scope.h */; };
|
|
||||||
DE06D4310A8BB52D0050E87E /* Parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE06D42F0A8BB52D0050E87E /* Parser.cpp */; };
|
|
||||||
DE06E8140A8FF9330050E87E /* Action.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06E8130A8FF9330050E87E /* Action.h */; };
|
|
||||||
DE0FCA630A95859D00248FD5 /* Expr.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE0FCA620A95859D00248FD5 /* Expr.h */; };
|
|
||||||
DE0FCB340A9C21F100248FD5 /* Expr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE0FCB330A9C21F100248FD5 /* Expr.cpp */; };
|
|
||||||
DE1733000B068B700080B521 /* ASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE1732FF0B068B700080B521 /* ASTContext.cpp */; };
|
|
||||||
DE17336E0B068DC20080B521 /* DeclSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE17336D0B068DC20080B521 /* DeclSpec.cpp */; };
|
|
||||||
DE1733700B068DC60080B521 /* DeclSpec.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE17336F0B068DC60080B521 /* DeclSpec.h */; };
|
|
||||||
DE1F22030A7D852A00FBF588 /* Parser.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE1F22020A7D852A00FBF588 /* Parser.h */; };
|
|
||||||
DE224FF80C7AA98800D370A5 /* CGExprComplex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE224FF70C7AA98800D370A5 /* CGExprComplex.cpp */; };
|
|
||||||
DE2252700C7E82D000D370A5 /* CGExprScalar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE22526F0C7E82D000D370A5 /* CGExprScalar.cpp */; };
|
|
||||||
DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE2255FB0C8004E600D370A5 /* ParseDeclCXX.cpp */; };
|
|
||||||
DE344AB80AE5DF6D00DBC861 /* HeaderSearch.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */; };
|
|
||||||
DE344B540AE5E46C00DBC861 /* HeaderSearch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */; };
|
|
||||||
DE3450D70AEB543100DBC861 /* DirectoryLookup.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3450D60AEB543100DBC861 /* DirectoryLookup.h */; };
|
|
||||||
DE3451580AEC176100DBC861 /* MacroExpander.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3451570AEC176100DBC861 /* MacroExpander.cpp */; };
|
|
||||||
DE3452410AEF1A2D00DBC861 /* Stmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3452400AEF1A2D00DBC861 /* Stmt.cpp */; };
|
|
||||||
DE3452810AEF1B1800DBC861 /* Stmt.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3452800AEF1B1800DBC861 /* Stmt.h */; };
|
|
||||||
DE345C1A0AFC658B00DBC861 /* StmtVisitor.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE345C190AFC658B00DBC861 /* StmtVisitor.h */; };
|
|
||||||
DE345F220AFD347900DBC861 /* StmtNodes.def in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE345F210AFD347900DBC861 /* StmtNodes.def */; };
|
|
||||||
DE3460000AFDCC1900DBC861 /* ParseObjc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE345FFF0AFDCC1900DBC861 /* ParseObjc.cpp */; };
|
|
||||||
DE3460050AFDCC6500DBC861 /* ParseInit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3460040AFDCC6500DBC861 /* ParseInit.cpp */; };
|
|
||||||
DE34600B0AFDCCBF00DBC861 /* ParseStmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE34600A0AFDCCBF00DBC861 /* ParseStmt.cpp */; };
|
|
||||||
DE34600F0AFDCCCE00DBC861 /* ParseDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE34600E0AFDCCCE00DBC861 /* ParseDecl.cpp */; };
|
|
||||||
DE3460130AFDCCDA00DBC861 /* ParseExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3460120AFDCCDA00DBC861 /* ParseExpr.cpp */; };
|
|
||||||
DE3461270AFE68BE00DBC861 /* MinimalAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3461260AFE68BE00DBC861 /* MinimalAction.cpp */; };
|
|
||||||
DE34621D0AFEB19B00DBC861 /* StmtPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */; };
|
|
||||||
DE3464220B03040900DBC861 /* Type.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3464210B03040900DBC861 /* Type.h */; };
|
|
||||||
DE4264FC0C113592005A861D /* CGDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4264FB0C113592005A861D /* CGDecl.cpp */; };
|
|
||||||
DE46BF280AE0A82D00CC047C /* TargetInfo.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE46BF270AE0A82D00CC047C /* TargetInfo.h */; };
|
|
||||||
DE4772FA0C10EAE5002239E8 /* CGStmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4772F90C10EAE5002239E8 /* CGStmt.cpp */; };
|
|
||||||
DE4772FC0C10EAEC002239E8 /* CGExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4772FB0C10EAEC002239E8 /* CGExpr.cpp */; };
|
|
||||||
DE5932D10AD60FF400BC794C /* clang.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE5932CD0AD60FF400BC794C /* clang.cpp */; };
|
|
||||||
DE5932D20AD60FF400BC794C /* clang.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE5932CE0AD60FF400BC794C /* clang.h */; };
|
|
||||||
DE5932D30AD60FF400BC794C /* PrintParserCallbacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE5932CF0AD60FF400BC794C /* PrintParserCallbacks.cpp */; };
|
|
||||||
DE5932D40AD60FF400BC794C /* PrintPreprocessedOutput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE5932D00AD60FF400BC794C /* PrintPreprocessedOutput.cpp */; };
|
|
||||||
DE67E70B0C020EC500F66BC5 /* SemaType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E70A0C020EC500F66BC5 /* SemaType.cpp */; };
|
|
||||||
DE67E70D0C020ECA00F66BC5 /* SemaStmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */; };
|
|
||||||
DE67E70F0C020ECF00F66BC5 /* SemaExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */; };
|
|
||||||
DE67E7110C020ED400F66BC5 /* SemaExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */; };
|
|
||||||
DE67E7130C020ED900F66BC5 /* SemaDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */; };
|
|
||||||
DE67E7150C020EDF00F66BC5 /* Sema.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE67E7140C020EDF00F66BC5 /* Sema.h */; };
|
|
||||||
DE67E7170C020EE400F66BC5 /* Sema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E7160C020EE400F66BC5 /* Sema.cpp */; };
|
|
||||||
DE67E71A0C020F4F00F66BC5 /* ASTStreamer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E7190C020F4F00F66BC5 /* ASTStreamer.cpp */; };
|
|
||||||
DE67E7280C02109800F66BC5 /* ASTStreamer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE67E7270C02109800F66BC5 /* ASTStreamer.h */; };
|
|
||||||
DE6951C70C4D1F5D00A5826B /* RecordLayout.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE6951C60C4D1F5D00A5826B /* RecordLayout.h */; };
|
|
||||||
DE6954640C5121BD00A5826B /* Token.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE6954630C5121BD00A5826B /* Token.h */; };
|
|
||||||
DE75ED290B044DC90020CF81 /* ASTContext.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE75ED280B044DC90020CF81 /* ASTContext.h */; };
|
|
||||||
DE75EDF10B06880E0020CF81 /* Type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE75EDF00B06880E0020CF81 /* Type.cpp */; };
|
|
||||||
DE927FFD0C055DE900231DA4 /* LLVMCodegen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE927FFC0C055DE900231DA4 /* LLVMCodegen.cpp */; };
|
|
||||||
DE928B130C05659200231DA4 /* ModuleBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE928B120C05659200231DA4 /* ModuleBuilder.cpp */; };
|
|
||||||
DE928B200C0565B000231DA4 /* ModuleBuilder.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE928B1F0C0565B000231DA4 /* ModuleBuilder.h */; };
|
|
||||||
DE928B7D0C0A615100231DA4 /* CodeGenModule.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE928B7C0C0A615100231DA4 /* CodeGenModule.h */; };
|
|
||||||
DE928B7F0C0A615600231DA4 /* CodeGenModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE928B7E0C0A615600231DA4 /* CodeGenModule.cpp */; };
|
|
||||||
DE928B810C0A615B00231DA4 /* CodeGenFunction.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE928B800C0A615B00231DA4 /* CodeGenFunction.h */; };
|
|
||||||
DE928B830C0A616000231DA4 /* CodeGenFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */; };
|
|
||||||
DEAEE98B0A5A2B970045101B /* MultipleIncludeOpt.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */; };
|
|
||||||
DEAEED4B0A5AF89A0045101B /* NOTES.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEAEED4A0A5AF89A0045101B /* NOTES.txt */; };
|
|
||||||
DEB0AEB90C2087A700718A22 /* TextDiagnostics.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEB0AEB80C2087A700718A22 /* TextDiagnostics.h */; };
|
|
||||||
DEB0AEBB0C2087AB00718A22 /* TextDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB0AEBA0C2087AB00718A22 /* TextDiagnostics.cpp */; };
|
|
||||||
DEC63B1A0C7B940200DBF169 /* CFG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEC63B190C7B940200DBF169 /* CFG.cpp */; };
|
|
||||||
DEC63B1C0C7B940600DBF169 /* CFG.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC63B1B0C7B940600DBF169 /* CFG.h */; };
|
|
||||||
DEC82DC40C32D50A00BAC245 /* DiagChecker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEC82DC30C32D50A00BAC245 /* DiagChecker.cpp */; };
|
|
||||||
DEC8D9910A9433CD00353FCA /* Decl.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC8D9900A9433CD00353FCA /* Decl.h */; };
|
|
||||||
DEC8D9A40A94346E00353FCA /* AST.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC8D9A30A94346E00353FCA /* AST.h */; };
|
|
||||||
DED626C90AE0C065001E80A4 /* TargetInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED626C80AE0C065001E80A4 /* TargetInfo.cpp */; };
|
|
||||||
DED627030AE0C51D001E80A4 /* Targets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED627020AE0C51D001E80A4 /* Targets.cpp */; };
|
|
||||||
DED62ABB0AE2EDF1001E80A4 /* Decl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */; };
|
|
||||||
DED676D10B6C786700AAD4A3 /* Builtins.def in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED676D00B6C786700AAD4A3 /* Builtins.def */; };
|
|
||||||
DED676FA0B6C797B00AAD4A3 /* Builtins.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED676F90B6C797B00AAD4A3 /* Builtins.h */; };
|
|
||||||
DED677C90B6C854100AAD4A3 /* Builtins.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED677C80B6C854100AAD4A3 /* Builtins.cpp */; };
|
|
||||||
DED67AEE0B6DB92A00AAD4A3 /* X86Builtins.def in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED67AED0B6DB92A00AAD4A3 /* X86Builtins.def */; };
|
|
||||||
DED67AF00B6DB92F00AAD4A3 /* PPCBuiltins.def in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED67AEF0B6DB92F00AAD4A3 /* PPCBuiltins.def */; };
|
|
||||||
DED7D7410A524295003AD0FB /* Diagnostic.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7310A524295003AD0FB /* Diagnostic.h */; };
|
|
||||||
DED7D7420A524295003AD0FB /* DiagnosticKinds.def in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7320A524295003AD0FB /* DiagnosticKinds.def */; };
|
|
||||||
DED7D7430A524295003AD0FB /* FileManager.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7330A524295003AD0FB /* FileManager.h */; };
|
|
||||||
DED7D7450A524295003AD0FB /* SourceLocation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7350A524295003AD0FB /* SourceLocation.h */; };
|
|
||||||
DED7D7460A524295003AD0FB /* SourceManager.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7360A524295003AD0FB /* SourceManager.h */; };
|
|
||||||
DED7D7470A524295003AD0FB /* TokenKinds.def in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7370A524295003AD0FB /* TokenKinds.def */; };
|
|
||||||
DED7D7480A524295003AD0FB /* TokenKinds.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7380A524295003AD0FB /* TokenKinds.h */; };
|
|
||||||
DED7D7490A524295003AD0FB /* IdentifierTable.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D73A0A524295003AD0FB /* IdentifierTable.h */; };
|
|
||||||
DED7D74A0A524295003AD0FB /* Lexer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D73B0A524295003AD0FB /* Lexer.h */; };
|
|
||||||
DED7D74C0A524295003AD0FB /* MacroExpander.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D73D0A524295003AD0FB /* MacroExpander.h */; };
|
|
||||||
DED7D74D0A524295003AD0FB /* MacroInfo.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D73E0A524295003AD0FB /* MacroInfo.h */; };
|
|
||||||
DED7D74E0A524295003AD0FB /* Pragma.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D73F0A524295003AD0FB /* Pragma.h */; };
|
|
||||||
DED7D74F0A524295003AD0FB /* Preprocessor.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7400A524295003AD0FB /* Preprocessor.h */; };
|
|
||||||
DED7D77A0A5242C7003AD0FB /* Diagnostic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D75D0A5242C7003AD0FB /* Diagnostic.cpp */; };
|
|
||||||
DED7D77B0A5242C7003AD0FB /* FileManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D75E0A5242C7003AD0FB /* FileManager.cpp */; };
|
|
||||||
DED7D7890A5242C7003AD0FB /* SourceManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D76D0A5242C7003AD0FB /* SourceManager.cpp */; };
|
|
||||||
DED7D78A0A5242C7003AD0FB /* TokenKinds.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D76E0A5242C7003AD0FB /* TokenKinds.cpp */; };
|
|
||||||
DED7D7C20A5242E6003AD0FB /* IdentifierTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D79D0A5242E6003AD0FB /* IdentifierTable.cpp */; };
|
|
||||||
DED7D7C30A5242E6003AD0FB /* Lexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D79E0A5242E6003AD0FB /* Lexer.cpp */; };
|
|
||||||
DED7D7C50A5242E6003AD0FB /* MacroInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D7A00A5242E6003AD0FB /* MacroInfo.cpp */; };
|
|
||||||
DED7D7C70A5242E6003AD0FB /* PPExpressions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D7A20A5242E6003AD0FB /* PPExpressions.cpp */; };
|
|
||||||
DED7D7C80A5242E6003AD0FB /* Pragma.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D7A30A5242E6003AD0FB /* Pragma.cpp */; };
|
|
||||||
DED7D7C90A5242E6003AD0FB /* Preprocessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D7A40A5242E6003AD0FB /* Preprocessor.cpp */; };
|
|
||||||
DED7D7D80A524302003AD0FB /* README.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7D70A524302003AD0FB /* README.txt */; };
|
|
||||||
DED7D9180A52518C003AD0FB /* ScratchBuffer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D9170A52518C003AD0FB /* ScratchBuffer.h */; };
|
|
||||||
DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */; };
|
|
||||||
DEEBBD440C19C5D200A9FE82 /* TODO.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEEBBD430C19C5D200A9FE82 /* TODO.txt */; };
|
|
||||||
DEEBC3BA0C2363B800A9FE82 /* CodeGenTypes.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEEBC3B90C2363B800A9FE82 /* CodeGenTypes.h */; };
|
|
||||||
DEEBC3BC0C2363BC00A9FE82 /* CodeGenTypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEEBC3BB0C2363BC00A9FE82 /* CodeGenTypes.cpp */; };
|
|
||||||
DEEBCBE30C33702C00A9FE82 /* TextDiagnosticBuffer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEEBCBE20C33702C00A9FE82 /* TextDiagnosticBuffer.h */; };
|
|
||||||
DEEBCBE50C33703100A9FE82 /* TextDiagnosticBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEEBCBE40C33703100A9FE82 /* TextDiagnosticBuffer.cpp */; };
|
|
||||||
DEF2E9320C5FB9FB000C4259 /* ASTStreamers.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEF2E9310C5FB9FB000C4259 /* ASTStreamers.h */; };
|
|
||||||
DEF2E9340C5FBA02000C4259 /* ASTStreamers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2E9330C5FBA02000C4259 /* ASTStreamers.cpp */; };
|
|
||||||
DEF2E95F0C5FBD74000C4259 /* InternalsManual.html in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */; };
|
|
||||||
DEF2EDA70C6A4252000C4259 /* StmtDumper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */; };
|
|
||||||
DEF2EFF30C6CDD74000C4259 /* CGExprAgg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */; };
|
|
||||||
DEF2F0100C6CFED5000C4259 /* SemaChecking.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */; };
|
|
||||||
F0226FD20C18084500141F42 /* TextDiagnosticPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F0226FD00C18084500141F42 /* TextDiagnosticPrinter.cpp */; };
|
|
||||||
F0226FD30C18084500141F42 /* TextDiagnosticPrinter.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F0226FD10C18084500141F42 /* TextDiagnosticPrinter.h */; };
|
|
||||||
/* End PBXBuildFile section */
|
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
|
||||||
8DD76F690486A84900D96B5E /* CopyFiles */ = {
|
|
||||||
isa = PBXCopyFilesBuildPhase;
|
|
||||||
buildActionMask = 8;
|
|
||||||
dstPath = /usr/share/man/man1/;
|
|
||||||
dstSubfolderSpec = 0;
|
|
||||||
files = (
|
|
||||||
DED7D7410A524295003AD0FB /* Diagnostic.h in CopyFiles */,
|
|
||||||
DED7D7420A524295003AD0FB /* DiagnosticKinds.def in CopyFiles */,
|
|
||||||
DED7D7430A524295003AD0FB /* FileManager.h in CopyFiles */,
|
|
||||||
DED7D7450A524295003AD0FB /* SourceLocation.h in CopyFiles */,
|
|
||||||
DED7D7460A524295003AD0FB /* SourceManager.h in CopyFiles */,
|
|
||||||
DED7D7470A524295003AD0FB /* TokenKinds.def in CopyFiles */,
|
|
||||||
DED7D7480A524295003AD0FB /* TokenKinds.h in CopyFiles */,
|
|
||||||
DED7D7490A524295003AD0FB /* IdentifierTable.h in CopyFiles */,
|
|
||||||
DED7D74A0A524295003AD0FB /* Lexer.h in CopyFiles */,
|
|
||||||
DED7D74C0A524295003AD0FB /* MacroExpander.h in CopyFiles */,
|
|
||||||
DED7D74D0A524295003AD0FB /* MacroInfo.h in CopyFiles */,
|
|
||||||
DED7D74E0A524295003AD0FB /* Pragma.h in CopyFiles */,
|
|
||||||
DED7D74F0A524295003AD0FB /* Preprocessor.h in CopyFiles */,
|
|
||||||
DED7D7D80A524302003AD0FB /* README.txt in CopyFiles */,
|
|
||||||
DED7D9180A52518C003AD0FB /* ScratchBuffer.h in CopyFiles */,
|
|
||||||
DEAEE98B0A5A2B970045101B /* MultipleIncludeOpt.h in CopyFiles */,
|
|
||||||
DEAEED4B0A5AF89A0045101B /* NOTES.txt in CopyFiles */,
|
|
||||||
DE1F22030A7D852A00FBF588 /* Parser.h in CopyFiles */,
|
|
||||||
DE06B73E0A8307640050E87E /* LangOptions.h in CopyFiles */,
|
|
||||||
DE06BECB0A854E4B0050E87E /* Scope.h in CopyFiles */,
|
|
||||||
DE06E8140A8FF9330050E87E /* Action.h in CopyFiles */,
|
|
||||||
DEC8D9910A9433CD00353FCA /* Decl.h in CopyFiles */,
|
|
||||||
DEC8D9A40A94346E00353FCA /* AST.h in CopyFiles */,
|
|
||||||
DE0FCA630A95859D00248FD5 /* Expr.h in CopyFiles */,
|
|
||||||
DE5932D20AD60FF400BC794C /* clang.h in CopyFiles */,
|
|
||||||
DE46BF280AE0A82D00CC047C /* TargetInfo.h in CopyFiles */,
|
|
||||||
DE344AB80AE5DF6D00DBC861 /* HeaderSearch.h in CopyFiles */,
|
|
||||||
DE3450D70AEB543100DBC861 /* DirectoryLookup.h in CopyFiles */,
|
|
||||||
DE3452810AEF1B1800DBC861 /* Stmt.h in CopyFiles */,
|
|
||||||
DE345C1A0AFC658B00DBC861 /* StmtVisitor.h in CopyFiles */,
|
|
||||||
DE345F220AFD347900DBC861 /* StmtNodes.def in CopyFiles */,
|
|
||||||
DE3464220B03040900DBC861 /* Type.h in CopyFiles */,
|
|
||||||
DE75ED290B044DC90020CF81 /* ASTContext.h in CopyFiles */,
|
|
||||||
DE1733700B068DC60080B521 /* DeclSpec.h in CopyFiles */,
|
|
||||||
DE01DA490B12ADA300AC22CE /* PPCallbacks.h in CopyFiles */,
|
|
||||||
DED676D10B6C786700AAD4A3 /* Builtins.def in CopyFiles */,
|
|
||||||
DED676FA0B6C797B00AAD4A3 /* Builtins.h in CopyFiles */,
|
|
||||||
DED67AEE0B6DB92A00AAD4A3 /* X86Builtins.def in CopyFiles */,
|
|
||||||
DED67AF00B6DB92F00AAD4A3 /* PPCBuiltins.def in CopyFiles */,
|
|
||||||
1A30A9E90B93A4C800201A91 /* ExprCXX.h in CopyFiles */,
|
|
||||||
1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */,
|
|
||||||
DE67E7150C020EDF00F66BC5 /* Sema.h in CopyFiles */,
|
|
||||||
DE67E7280C02109800F66BC5 /* ASTStreamer.h in CopyFiles */,
|
|
||||||
DE928B200C0565B000231DA4 /* ModuleBuilder.h in CopyFiles */,
|
|
||||||
DE928B7D0C0A615100231DA4 /* CodeGenModule.h in CopyFiles */,
|
|
||||||
DE928B810C0A615B00231DA4 /* CodeGenFunction.h in CopyFiles */,
|
|
||||||
F0226FD30C18084500141F42 /* TextDiagnosticPrinter.h in CopyFiles */,
|
|
||||||
DEEBBD440C19C5D200A9FE82 /* TODO.txt in CopyFiles */,
|
|
||||||
84D9A88C0C1A581300AC7ABC /* AttributeList.h in CopyFiles */,
|
|
||||||
DEB0AEB90C2087A700718A22 /* TextDiagnostics.h in CopyFiles */,
|
|
||||||
DEEBC3BA0C2363B800A9FE82 /* CodeGenTypes.h in CopyFiles */,
|
|
||||||
DEEBCBE30C33702C00A9FE82 /* TextDiagnosticBuffer.h in CopyFiles */,
|
|
||||||
DE6951C70C4D1F5D00A5826B /* RecordLayout.h in CopyFiles */,
|
|
||||||
DE6954640C5121BD00A5826B /* Token.h in CopyFiles */,
|
|
||||||
DEF2E9320C5FB9FB000C4259 /* ASTStreamers.h in CopyFiles */,
|
|
||||||
DEF2E95F0C5FBD74000C4259 /* InternalsManual.html in CopyFiles */,
|
|
||||||
DEC63B1C0C7B940600DBF169 /* CFG.h in CopyFiles */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 1;
|
|
||||||
};
|
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
|
||||||
1A30A9E80B93A4C800201A91 /* ExprCXX.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ExprCXX.h; path = clang/AST/ExprCXX.h; sourceTree = "<group>"; };
|
|
||||||
1A7342470C7B57D500122F56 /* CGObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjC.cpp; path = CodeGen/CGObjC.cpp; sourceTree = "<group>"; };
|
|
||||||
1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = "<group>"; };
|
|
||||||
1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = "<group>"; };
|
|
||||||
1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; };
|
|
||||||
3523B4D30C985C53001D6CC3 /* CFGStmtVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFGStmtVisitor.h; path = clang/Analysis/CFGStmtVisitor.h; sourceTree = "<group>"; };
|
|
||||||
3523B4D50C985DAE001D6CC3 /* DataflowStmtVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataflowStmtVisitor.h; path = clang/Analysis/DataflowStmtVisitor.h; sourceTree = "<group>"; };
|
|
||||||
35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExprCXX.cpp; path = AST/ExprCXX.cpp; sourceTree = "<group>"; };
|
|
||||||
3547129D0C88881300B3E1D5 /* PrettyPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrettyPrinter.h; path = clang/AST/PrettyPrinter.h; sourceTree = "<group>"; };
|
|
||||||
355CF6820C90A8B600A08AA3 /* LocalCheckers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LocalCheckers.h; path = clang/Analysis/LocalCheckers.h; sourceTree = "<group>"; };
|
|
||||||
355CF6830C90A8D400A08AA3 /* DeadStores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeadStores.cpp; path = Analysis/DeadStores.cpp; sourceTree = "<group>"; };
|
|
||||||
356EF9B20C8F7DBA006650F5 /* LiveVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LiveVariables.h; path = clang/Analysis/LiveVariables.h; sourceTree = "<group>"; };
|
|
||||||
356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LiveVariables.cpp; path = Analysis/LiveVariables.cpp; sourceTree = "<group>"; };
|
|
||||||
84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = Parse/AttributeList.cpp; sourceTree = "<group>"; };
|
|
||||||
84D9A88B0C1A581300AC7ABC /* AttributeList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = AttributeList.h; path = clang/Parse/AttributeList.h; sourceTree = "<group>"; };
|
|
||||||
8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = "<group>"; };
|
|
||||||
DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = Parse/ParseExprCXX.cpp; sourceTree = "<group>"; };
|
|
||||||
DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = "<group>"; };
|
|
||||||
DE06BECA0A854E4B0050E87E /* Scope.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Scope.h; path = clang/Parse/Scope.h; sourceTree = "<group>"; };
|
|
||||||
DE06D42F0A8BB52D0050E87E /* Parser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Parser.cpp; path = Parse/Parser.cpp; sourceTree = "<group>"; };
|
|
||||||
DE06E8130A8FF9330050E87E /* Action.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Action.h; path = clang/Parse/Action.h; sourceTree = "<group>"; };
|
|
||||||
DE0FCA620A95859D00248FD5 /* Expr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Expr.h; path = clang/AST/Expr.h; sourceTree = "<group>"; };
|
|
||||||
DE0FCB330A9C21F100248FD5 /* Expr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Expr.cpp; path = AST/Expr.cpp; sourceTree = "<group>"; };
|
|
||||||
DE1732FF0B068B700080B521 /* ASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ASTContext.cpp; path = AST/ASTContext.cpp; sourceTree = "<group>"; };
|
|
||||||
DE17336D0B068DC20080B521 /* DeclSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DeclSpec.cpp; path = Parse/DeclSpec.cpp; sourceTree = "<group>"; };
|
|
||||||
DE17336F0B068DC60080B521 /* DeclSpec.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DeclSpec.h; path = clang/Parse/DeclSpec.h; sourceTree = "<group>"; };
|
|
||||||
DE1F22020A7D852A00FBF588 /* Parser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Parser.h; path = clang/Parse/Parser.h; sourceTree = "<group>"; };
|
|
||||||
DE224FF70C7AA98800D370A5 /* CGExprComplex.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprComplex.cpp; path = CodeGen/CGExprComplex.cpp; sourceTree = "<group>"; };
|
|
||||||
DE22526F0C7E82D000D370A5 /* CGExprScalar.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprScalar.cpp; path = CodeGen/CGExprScalar.cpp; sourceTree = "<group>"; };
|
|
||||||
DE2255FB0C8004E600D370A5 /* ParseDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseDeclCXX.cpp; path = Parse/ParseDeclCXX.cpp; sourceTree = "<group>"; };
|
|
||||||
DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HeaderSearch.h; sourceTree = "<group>"; };
|
|
||||||
DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = HeaderSearch.cpp; sourceTree = "<group>"; };
|
|
||||||
DE3450D60AEB543100DBC861 /* DirectoryLookup.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DirectoryLookup.h; sourceTree = "<group>"; };
|
|
||||||
DE3451570AEC176100DBC861 /* MacroExpander.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MacroExpander.cpp; sourceTree = "<group>"; };
|
|
||||||
DE3452400AEF1A2D00DBC861 /* Stmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Stmt.cpp; path = AST/Stmt.cpp; sourceTree = "<group>"; };
|
|
||||||
DE3452800AEF1B1800DBC861 /* Stmt.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Stmt.h; path = clang/AST/Stmt.h; sourceTree = "<group>"; };
|
|
||||||
DE345C190AFC658B00DBC861 /* StmtVisitor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = StmtVisitor.h; path = clang/AST/StmtVisitor.h; sourceTree = "<group>"; };
|
|
||||||
DE345F210AFD347900DBC861 /* StmtNodes.def */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = StmtNodes.def; path = clang/AST/StmtNodes.def; sourceTree = "<group>"; };
|
|
||||||
DE345FFF0AFDCC1900DBC861 /* ParseObjc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseObjc.cpp; path = Parse/ParseObjc.cpp; sourceTree = "<group>"; };
|
|
||||||
DE3460040AFDCC6500DBC861 /* ParseInit.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseInit.cpp; path = Parse/ParseInit.cpp; sourceTree = "<group>"; };
|
|
||||||
DE34600A0AFDCCBF00DBC861 /* ParseStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseStmt.cpp; path = Parse/ParseStmt.cpp; sourceTree = "<group>"; };
|
|
||||||
DE34600E0AFDCCCE00DBC861 /* ParseDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseDecl.cpp; path = Parse/ParseDecl.cpp; sourceTree = "<group>"; };
|
|
||||||
DE3460120AFDCCDA00DBC861 /* ParseExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExpr.cpp; path = Parse/ParseExpr.cpp; sourceTree = "<group>"; };
|
|
||||||
DE3461260AFE68BE00DBC861 /* MinimalAction.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = MinimalAction.cpp; path = Parse/MinimalAction.cpp; sourceTree = "<group>"; };
|
|
||||||
DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StmtPrinter.cpp; path = AST/StmtPrinter.cpp; sourceTree = "<group>"; };
|
|
||||||
DE3464210B03040900DBC861 /* Type.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Type.h; path = clang/AST/Type.h; sourceTree = "<group>"; };
|
|
||||||
DE4264FB0C113592005A861D /* CGDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGDecl.cpp; path = CodeGen/CGDecl.cpp; sourceTree = "<group>"; };
|
|
||||||
DE46BF270AE0A82D00CC047C /* TargetInfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = TargetInfo.h; sourceTree = "<group>"; };
|
|
||||||
DE4772F90C10EAE5002239E8 /* CGStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGStmt.cpp; path = CodeGen/CGStmt.cpp; sourceTree = "<group>"; };
|
|
||||||
DE4772FB0C10EAEC002239E8 /* CGExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExpr.cpp; path = CodeGen/CGExpr.cpp; sourceTree = "<group>"; };
|
|
||||||
DE5932CD0AD60FF400BC794C /* clang.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = clang.cpp; path = Driver/clang.cpp; sourceTree = "<group>"; };
|
|
||||||
DE5932CE0AD60FF400BC794C /* clang.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = clang.h; path = Driver/clang.h; sourceTree = "<group>"; };
|
|
||||||
DE5932CF0AD60FF400BC794C /* PrintParserCallbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PrintParserCallbacks.cpp; path = Driver/PrintParserCallbacks.cpp; sourceTree = "<group>"; };
|
|
||||||
DE5932D00AD60FF400BC794C /* PrintPreprocessedOutput.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PrintPreprocessedOutput.cpp; path = Driver/PrintPreprocessedOutput.cpp; sourceTree = "<group>"; };
|
|
||||||
DE67E70A0C020EC500F66BC5 /* SemaType.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaType.cpp; path = Sema/SemaType.cpp; sourceTree = "<group>"; };
|
|
||||||
DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaStmt.cpp; path = Sema/SemaStmt.cpp; sourceTree = "<group>"; };
|
|
||||||
DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExprCXX.cpp; path = Sema/SemaExprCXX.cpp; sourceTree = "<group>"; };
|
|
||||||
DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExpr.cpp; path = Sema/SemaExpr.cpp; sourceTree = "<group>"; };
|
|
||||||
DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDecl.cpp; path = Sema/SemaDecl.cpp; sourceTree = "<group>"; };
|
|
||||||
DE67E7140C020EDF00F66BC5 /* Sema.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Sema.h; path = Sema/Sema.h; sourceTree = "<group>"; };
|
|
||||||
DE67E7160C020EE400F66BC5 /* Sema.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Sema.cpp; path = Sema/Sema.cpp; sourceTree = "<group>"; };
|
|
||||||
DE67E7190C020F4F00F66BC5 /* ASTStreamer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ASTStreamer.cpp; path = Sema/ASTStreamer.cpp; sourceTree = "<group>"; };
|
|
||||||
DE67E7270C02109800F66BC5 /* ASTStreamer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ASTStreamer.h; path = clang/Sema/ASTStreamer.h; sourceTree = "<group>"; };
|
|
||||||
DE6951C60C4D1F5D00A5826B /* RecordLayout.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = RecordLayout.h; path = clang/AST/RecordLayout.h; sourceTree = "<group>"; };
|
|
||||||
DE6954630C5121BD00A5826B /* Token.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Token.h; sourceTree = "<group>"; };
|
|
||||||
DE75ED280B044DC90020CF81 /* ASTContext.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ASTContext.h; path = clang/AST/ASTContext.h; sourceTree = "<group>"; };
|
|
||||||
DE75EDF00B06880E0020CF81 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Type.cpp; path = AST/Type.cpp; sourceTree = "<group>"; };
|
|
||||||
DE927FFC0C055DE900231DA4 /* LLVMCodegen.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = LLVMCodegen.cpp; path = Driver/LLVMCodegen.cpp; sourceTree = "<group>"; };
|
|
||||||
DE928B120C05659200231DA4 /* ModuleBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleBuilder.cpp; path = CodeGen/ModuleBuilder.cpp; sourceTree = "<group>"; };
|
|
||||||
DE928B1F0C0565B000231DA4 /* ModuleBuilder.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ModuleBuilder.h; path = clang/CodeGen/ModuleBuilder.h; sourceTree = "<group>"; };
|
|
||||||
DE928B7C0C0A615100231DA4 /* CodeGenModule.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CodeGenModule.h; path = CodeGen/CodeGenModule.h; sourceTree = "<group>"; };
|
|
||||||
DE928B7E0C0A615600231DA4 /* CodeGenModule.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenModule.cpp; path = CodeGen/CodeGenModule.cpp; sourceTree = "<group>"; };
|
|
||||||
DE928B800C0A615B00231DA4 /* CodeGenFunction.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CodeGenFunction.h; path = CodeGen/CodeGenFunction.h; sourceTree = "<group>"; };
|
|
||||||
DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenFunction.cpp; path = CodeGen/CodeGenFunction.cpp; sourceTree = "<group>"; };
|
|
||||||
DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MultipleIncludeOpt.h; sourceTree = "<group>"; };
|
|
||||||
DEAEED4A0A5AF89A0045101B /* NOTES.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = NOTES.txt; sourceTree = "<group>"; };
|
|
||||||
DEB0AEB80C2087A700718A22 /* TextDiagnostics.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = TextDiagnostics.h; path = Driver/TextDiagnostics.h; sourceTree = "<group>"; };
|
|
||||||
DEB0AEBA0C2087AB00718A22 /* TextDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnostics.cpp; path = Driver/TextDiagnostics.cpp; sourceTree = "<group>"; };
|
|
||||||
DEC63B190C7B940200DBF169 /* CFG.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CFG.cpp; path = AST/CFG.cpp; sourceTree = "<group>"; };
|
|
||||||
DEC63B1B0C7B940600DBF169 /* CFG.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CFG.h; path = clang/AST/CFG.h; sourceTree = "<group>"; };
|
|
||||||
DEC82DC30C32D50A00BAC245 /* DiagChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DiagChecker.cpp; path = Driver/DiagChecker.cpp; sourceTree = "<group>"; };
|
|
||||||
DEC8D9900A9433CD00353FCA /* Decl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Decl.h; path = clang/AST/Decl.h; sourceTree = "<group>"; };
|
|
||||||
DEC8D9A30A94346E00353FCA /* AST.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = AST.h; path = clang/AST/AST.h; sourceTree = "<group>"; };
|
|
||||||
DED626C80AE0C065001E80A4 /* TargetInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TargetInfo.cpp; sourceTree = "<group>"; };
|
|
||||||
DED627020AE0C51D001E80A4 /* Targets.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Targets.cpp; path = Driver/Targets.cpp; sourceTree = "<group>"; };
|
|
||||||
DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Decl.cpp; path = AST/Decl.cpp; sourceTree = "<group>"; usesTabs = 1; };
|
|
||||||
DED676D00B6C786700AAD4A3 /* Builtins.def */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = Builtins.def; path = clang/AST/Builtins.def; sourceTree = "<group>"; };
|
|
||||||
DED676F90B6C797B00AAD4A3 /* Builtins.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Builtins.h; path = clang/AST/Builtins.h; sourceTree = "<group>"; };
|
|
||||||
DED677C80B6C854100AAD4A3 /* Builtins.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Builtins.cpp; path = AST/Builtins.cpp; sourceTree = "<group>"; };
|
|
||||||
DED67AED0B6DB92A00AAD4A3 /* X86Builtins.def */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = X86Builtins.def; path = Driver/X86Builtins.def; sourceTree = "<group>"; };
|
|
||||||
DED67AEF0B6DB92F00AAD4A3 /* PPCBuiltins.def */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = PPCBuiltins.def; path = Driver/PPCBuiltins.def; sourceTree = "<group>"; };
|
|
||||||
DED7D7310A524295003AD0FB /* Diagnostic.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Diagnostic.h; sourceTree = "<group>"; };
|
|
||||||
DED7D7320A524295003AD0FB /* DiagnosticKinds.def */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = DiagnosticKinds.def; sourceTree = "<group>"; };
|
|
||||||
DED7D7330A524295003AD0FB /* FileManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FileManager.h; sourceTree = "<group>"; };
|
|
||||||
DED7D7350A524295003AD0FB /* SourceLocation.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SourceLocation.h; sourceTree = "<group>"; };
|
|
||||||
DED7D7360A524295003AD0FB /* SourceManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SourceManager.h; sourceTree = "<group>"; };
|
|
||||||
DED7D7370A524295003AD0FB /* TokenKinds.def */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = TokenKinds.def; sourceTree = "<group>"; };
|
|
||||||
DED7D7380A524295003AD0FB /* TokenKinds.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = TokenKinds.h; sourceTree = "<group>"; };
|
|
||||||
DED7D73A0A524295003AD0FB /* IdentifierTable.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = IdentifierTable.h; sourceTree = "<group>"; };
|
|
||||||
DED7D73B0A524295003AD0FB /* Lexer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Lexer.h; sourceTree = "<group>"; };
|
|
||||||
DED7D73D0A524295003AD0FB /* MacroExpander.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MacroExpander.h; sourceTree = "<group>"; };
|
|
||||||
DED7D73E0A524295003AD0FB /* MacroInfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MacroInfo.h; sourceTree = "<group>"; };
|
|
||||||
DED7D73F0A524295003AD0FB /* Pragma.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Pragma.h; sourceTree = "<group>"; };
|
|
||||||
DED7D7400A524295003AD0FB /* Preprocessor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Preprocessor.h; sourceTree = "<group>"; };
|
|
||||||
DED7D75D0A5242C7003AD0FB /* Diagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Diagnostic.cpp; sourceTree = "<group>"; };
|
|
||||||
DED7D75E0A5242C7003AD0FB /* FileManager.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = FileManager.cpp; sourceTree = "<group>"; };
|
|
||||||
DED7D76D0A5242C7003AD0FB /* SourceManager.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SourceManager.cpp; sourceTree = "<group>"; };
|
|
||||||
DED7D76E0A5242C7003AD0FB /* TokenKinds.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TokenKinds.cpp; sourceTree = "<group>"; };
|
|
||||||
DED7D79D0A5242E6003AD0FB /* IdentifierTable.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = IdentifierTable.cpp; sourceTree = "<group>"; };
|
|
||||||
DED7D79E0A5242E6003AD0FB /* Lexer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Lexer.cpp; sourceTree = "<group>"; };
|
|
||||||
DED7D7A00A5242E6003AD0FB /* MacroInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MacroInfo.cpp; sourceTree = "<group>"; };
|
|
||||||
DED7D7A20A5242E6003AD0FB /* PPExpressions.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PPExpressions.cpp; sourceTree = "<group>"; };
|
|
||||||
DED7D7A30A5242E6003AD0FB /* Pragma.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Pragma.cpp; sourceTree = "<group>"; };
|
|
||||||
DED7D7A40A5242E6003AD0FB /* Preprocessor.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Preprocessor.cpp; sourceTree = "<group>"; };
|
|
||||||
DED7D7D70A524302003AD0FB /* README.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = README.txt; sourceTree = "<group>"; };
|
|
||||||
DED7D9170A52518C003AD0FB /* ScratchBuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ScratchBuffer.h; sourceTree = "<group>"; };
|
|
||||||
DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ScratchBuffer.cpp; sourceTree = "<group>"; };
|
|
||||||
DEEBBD430C19C5D200A9FE82 /* TODO.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = TODO.txt; sourceTree = "<group>"; };
|
|
||||||
DEEBC3B90C2363B800A9FE82 /* CodeGenTypes.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CodeGenTypes.h; path = CodeGen/CodeGenTypes.h; sourceTree = "<group>"; };
|
|
||||||
DEEBC3BB0C2363BC00A9FE82 /* CodeGenTypes.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenTypes.cpp; path = CodeGen/CodeGenTypes.cpp; sourceTree = "<group>"; };
|
|
||||||
DEEBCBE20C33702C00A9FE82 /* TextDiagnosticBuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = TextDiagnosticBuffer.h; path = Driver/TextDiagnosticBuffer.h; sourceTree = "<group>"; };
|
|
||||||
DEEBCBE40C33703100A9FE82 /* TextDiagnosticBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnosticBuffer.cpp; path = Driver/TextDiagnosticBuffer.cpp; sourceTree = "<group>"; };
|
|
||||||
DEF2E9310C5FB9FB000C4259 /* ASTStreamers.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ASTStreamers.h; path = Driver/ASTStreamers.h; sourceTree = "<group>"; };
|
|
||||||
DEF2E9330C5FBA02000C4259 /* ASTStreamers.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ASTStreamers.cpp; path = Driver/ASTStreamers.cpp; sourceTree = "<group>"; };
|
|
||||||
DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.html; name = InternalsManual.html; path = docs/InternalsManual.html; sourceTree = "<group>"; };
|
|
||||||
DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StmtDumper.cpp; path = AST/StmtDumper.cpp; sourceTree = "<group>"; };
|
|
||||||
DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprAgg.cpp; path = CodeGen/CGExprAgg.cpp; sourceTree = "<group>"; };
|
|
||||||
DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaChecking.cpp; path = Sema/SemaChecking.cpp; sourceTree = "<group>"; };
|
|
||||||
F0226FD00C18084500141F42 /* TextDiagnosticPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnosticPrinter.cpp; path = Driver/TextDiagnosticPrinter.cpp; sourceTree = "<group>"; };
|
|
||||||
F0226FD10C18084500141F42 /* TextDiagnosticPrinter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = TextDiagnosticPrinter.h; path = Driver/TextDiagnosticPrinter.h; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
|
||||||
8DD76F660486A84900D96B5E /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXFrameworksBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
|
||||||
08FB7794FE84155DC02AAC07 /* clang */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DED7D72E0A524295003AD0FB /* include */,
|
|
||||||
08FB7795FE84155DC02AAC07 /* Source */,
|
|
||||||
DEAEECAE0A5AF0FA0045101B /* Driver */,
|
|
||||||
C6859E8C029090F304C91782 /* Documentation */,
|
|
||||||
1AB674ADFE9D54B511CA2CBB /* Products */,
|
|
||||||
);
|
|
||||||
name = clang;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
08FB7795FE84155DC02AAC07 /* Source */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DED7D7500A5242C7003AD0FB /* Basic */,
|
|
||||||
DED7D78C0A5242E6003AD0FB /* Lex */,
|
|
||||||
DE1F22600A7D8C9B00FBF588 /* Parse */,
|
|
||||||
DEC8D9920A9433F400353FCA /* AST */,
|
|
||||||
DE67E7070C020EAB00F66BC5 /* Sema */,
|
|
||||||
DE927FCC0C0557CD00231DA4 /* CodeGen */,
|
|
||||||
356EF9B30C8F7DCA006650F5 /* Analysis */,
|
|
||||||
);
|
|
||||||
name = Source;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
1AB674ADFE9D54B511CA2CBB /* Products */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
8DD76F6C0486A84900D96B5E /* clang */,
|
|
||||||
);
|
|
||||||
name = Products;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
355CF6850C90A8D600A08AA3 /* LocalCheckers */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
355CF6830C90A8D400A08AA3 /* DeadStores.cpp */,
|
|
||||||
);
|
|
||||||
name = LocalCheckers;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
356EF9AF0C8F7DA4006650F5 /* Analysis */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
3523B4D50C985DAE001D6CC3 /* DataflowStmtVisitor.h */,
|
|
||||||
3523B4D30C985C53001D6CC3 /* CFGStmtVisitor.h */,
|
|
||||||
355CF6820C90A8B600A08AA3 /* LocalCheckers.h */,
|
|
||||||
356EF9B20C8F7DBA006650F5 /* LiveVariables.h */,
|
|
||||||
);
|
|
||||||
name = Analysis;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
356EF9B30C8F7DCA006650F5 /* Analysis */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */,
|
|
||||||
355CF6850C90A8D600A08AA3 /* LocalCheckers */,
|
|
||||||
);
|
|
||||||
name = Analysis;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
C6859E8C029090F304C91782 /* Documentation */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DEAEED4A0A5AF89A0045101B /* NOTES.txt */,
|
|
||||||
DED7D7D70A524302003AD0FB /* README.txt */,
|
|
||||||
DEEBBD430C19C5D200A9FE82 /* TODO.txt */,
|
|
||||||
DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */,
|
|
||||||
);
|
|
||||||
name = Documentation;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DE1F21F20A7D84E800FBF588 /* Parse */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
84D9A88B0C1A581300AC7ABC /* AttributeList.h */,
|
|
||||||
DE06E8130A8FF9330050E87E /* Action.h */,
|
|
||||||
DE17336F0B068DC60080B521 /* DeclSpec.h */,
|
|
||||||
DE1F22020A7D852A00FBF588 /* Parser.h */,
|
|
||||||
DE06BECA0A854E4B0050E87E /* Scope.h */,
|
|
||||||
);
|
|
||||||
name = Parse;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DE1F22600A7D8C9B00FBF588 /* Parse */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */,
|
|
||||||
DE3461260AFE68BE00DBC861 /* MinimalAction.cpp */,
|
|
||||||
DE06D42F0A8BB52D0050E87E /* Parser.cpp */,
|
|
||||||
DE3460040AFDCC6500DBC861 /* ParseInit.cpp */,
|
|
||||||
DE34600E0AFDCCCE00DBC861 /* ParseDecl.cpp */,
|
|
||||||
DE2255FB0C8004E600D370A5 /* ParseDeclCXX.cpp */,
|
|
||||||
DE3460120AFDCCDA00DBC861 /* ParseExpr.cpp */,
|
|
||||||
DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */,
|
|
||||||
DE34600A0AFDCCBF00DBC861 /* ParseStmt.cpp */,
|
|
||||||
DE345FFF0AFDCC1900DBC861 /* ParseObjc.cpp */,
|
|
||||||
DE17336D0B068DC20080B521 /* DeclSpec.cpp */,
|
|
||||||
);
|
|
||||||
name = Parse;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DE67E7070C020EAB00F66BC5 /* Sema */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DE67E7190C020F4F00F66BC5 /* ASTStreamer.cpp */,
|
|
||||||
DE67E7140C020EDF00F66BC5 /* Sema.h */,
|
|
||||||
DE67E7160C020EE400F66BC5 /* Sema.cpp */,
|
|
||||||
DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */,
|
|
||||||
DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */,
|
|
||||||
DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */,
|
|
||||||
DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */,
|
|
||||||
DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */,
|
|
||||||
DE67E70A0C020EC500F66BC5 /* SemaType.cpp */,
|
|
||||||
);
|
|
||||||
name = Sema;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DE67E7260C02108300F66BC5 /* Sema */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DE67E7270C02109800F66BC5 /* ASTStreamer.h */,
|
|
||||||
);
|
|
||||||
name = Sema;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DE927FCC0C0557CD00231DA4 /* CodeGen */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DE928B800C0A615B00231DA4 /* CodeGenFunction.h */,
|
|
||||||
DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */,
|
|
||||||
DE928B7C0C0A615100231DA4 /* CodeGenModule.h */,
|
|
||||||
DE928B7E0C0A615600231DA4 /* CodeGenModule.cpp */,
|
|
||||||
DEEBC3BB0C2363BC00A9FE82 /* CodeGenTypes.cpp */,
|
|
||||||
DEEBC3B90C2363B800A9FE82 /* CodeGenTypes.h */,
|
|
||||||
1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */,
|
|
||||||
DE4264FB0C113592005A861D /* CGDecl.cpp */,
|
|
||||||
DE4772FB0C10EAEC002239E8 /* CGExpr.cpp */,
|
|
||||||
DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */,
|
|
||||||
DE224FF70C7AA98800D370A5 /* CGExprComplex.cpp */,
|
|
||||||
DE22526F0C7E82D000D370A5 /* CGExprScalar.cpp */,
|
|
||||||
1A7342470C7B57D500122F56 /* CGObjC.cpp */,
|
|
||||||
DE4772F90C10EAE5002239E8 /* CGStmt.cpp */,
|
|
||||||
DE928B120C05659200231DA4 /* ModuleBuilder.cpp */,
|
|
||||||
);
|
|
||||||
name = CodeGen;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DE928B140C05659A00231DA4 /* CodeGen */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DE928B1F0C0565B000231DA4 /* ModuleBuilder.h */,
|
|
||||||
);
|
|
||||||
name = CodeGen;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DEAEECAE0A5AF0FA0045101B /* Driver */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DE5932CD0AD60FF400BC794C /* clang.cpp */,
|
|
||||||
DE5932CE0AD60FF400BC794C /* clang.h */,
|
|
||||||
DEF2E9330C5FBA02000C4259 /* ASTStreamers.cpp */,
|
|
||||||
DEF2E9310C5FB9FB000C4259 /* ASTStreamers.h */,
|
|
||||||
DED67AEF0B6DB92F00AAD4A3 /* PPCBuiltins.def */,
|
|
||||||
DED67AED0B6DB92A00AAD4A3 /* X86Builtins.def */,
|
|
||||||
DEC82DC30C32D50A00BAC245 /* DiagChecker.cpp */,
|
|
||||||
DE927FFC0C055DE900231DA4 /* LLVMCodegen.cpp */,
|
|
||||||
DE5932CF0AD60FF400BC794C /* PrintParserCallbacks.cpp */,
|
|
||||||
DE5932D00AD60FF400BC794C /* PrintPreprocessedOutput.cpp */,
|
|
||||||
DED627020AE0C51D001E80A4 /* Targets.cpp */,
|
|
||||||
DEB0AEBA0C2087AB00718A22 /* TextDiagnostics.cpp */,
|
|
||||||
DEB0AEB80C2087A700718A22 /* TextDiagnostics.h */,
|
|
||||||
F0226FD00C18084500141F42 /* TextDiagnosticPrinter.cpp */,
|
|
||||||
F0226FD10C18084500141F42 /* TextDiagnosticPrinter.h */,
|
|
||||||
DEEBCBE40C33703100A9FE82 /* TextDiagnosticBuffer.cpp */,
|
|
||||||
DEEBCBE20C33702C00A9FE82 /* TextDiagnosticBuffer.h */,
|
|
||||||
);
|
|
||||||
name = Driver;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DEC8D98B0A9433BC00353FCA /* AST */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DEC8D9A30A94346E00353FCA /* AST.h */,
|
|
||||||
DE75ED280B044DC90020CF81 /* ASTContext.h */,
|
|
||||||
DED676D00B6C786700AAD4A3 /* Builtins.def */,
|
|
||||||
DED676F90B6C797B00AAD4A3 /* Builtins.h */,
|
|
||||||
DEC63B1B0C7B940600DBF169 /* CFG.h */,
|
|
||||||
DEC8D9900A9433CD00353FCA /* Decl.h */,
|
|
||||||
DE0FCA620A95859D00248FD5 /* Expr.h */,
|
|
||||||
1A30A9E80B93A4C800201A91 /* ExprCXX.h */,
|
|
||||||
DE6951C60C4D1F5D00A5826B /* RecordLayout.h */,
|
|
||||||
3547129D0C88881300B3E1D5 /* PrettyPrinter.h */,
|
|
||||||
DE3452800AEF1B1800DBC861 /* Stmt.h */,
|
|
||||||
DE345F210AFD347900DBC861 /* StmtNodes.def */,
|
|
||||||
DE345C190AFC658B00DBC861 /* StmtVisitor.h */,
|
|
||||||
DE3464210B03040900DBC861 /* Type.h */,
|
|
||||||
);
|
|
||||||
name = AST;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DEC8D9920A9433F400353FCA /* AST */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DE1732FF0B068B700080B521 /* ASTContext.cpp */,
|
|
||||||
DED677C80B6C854100AAD4A3 /* Builtins.cpp */,
|
|
||||||
DEC63B190C7B940200DBF169 /* CFG.cpp */,
|
|
||||||
DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */,
|
|
||||||
DE0FCB330A9C21F100248FD5 /* Expr.cpp */,
|
|
||||||
35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */,
|
|
||||||
DE3452400AEF1A2D00DBC861 /* Stmt.cpp */,
|
|
||||||
DE75EDF00B06880E0020CF81 /* Type.cpp */,
|
|
||||||
DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */,
|
|
||||||
DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */,
|
|
||||||
);
|
|
||||||
name = AST;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DED7D72E0A524295003AD0FB /* include */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DED7D7300A524295003AD0FB /* Basic */,
|
|
||||||
DED7D7390A524295003AD0FB /* Lex */,
|
|
||||||
DE1F21F20A7D84E800FBF588 /* Parse */,
|
|
||||||
DEC8D98B0A9433BC00353FCA /* AST */,
|
|
||||||
DE67E7260C02108300F66BC5 /* Sema */,
|
|
||||||
DE928B140C05659A00231DA4 /* CodeGen */,
|
|
||||||
356EF9AF0C8F7DA4006650F5 /* Analysis */,
|
|
||||||
);
|
|
||||||
path = include;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DED7D7300A524295003AD0FB /* Basic */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DED7D7310A524295003AD0FB /* Diagnostic.h */,
|
|
||||||
DED7D7320A524295003AD0FB /* DiagnosticKinds.def */,
|
|
||||||
DED7D7330A524295003AD0FB /* FileManager.h */,
|
|
||||||
DE06B73D0A8307640050E87E /* LangOptions.h */,
|
|
||||||
DED7D7350A524295003AD0FB /* SourceLocation.h */,
|
|
||||||
DED7D7360A524295003AD0FB /* SourceManager.h */,
|
|
||||||
DE46BF270AE0A82D00CC047C /* TargetInfo.h */,
|
|
||||||
DED7D7370A524295003AD0FB /* TokenKinds.def */,
|
|
||||||
DED7D7380A524295003AD0FB /* TokenKinds.h */,
|
|
||||||
);
|
|
||||||
name = Basic;
|
|
||||||
path = clang/Basic;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DED7D7390A524295003AD0FB /* Lex */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DE3450D60AEB543100DBC861 /* DirectoryLookup.h */,
|
|
||||||
DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */,
|
|
||||||
DED7D73A0A524295003AD0FB /* IdentifierTable.h */,
|
|
||||||
DED7D73B0A524295003AD0FB /* Lexer.h */,
|
|
||||||
1A869A6E0BA2164C008DA07A /* LiteralSupport.h */,
|
|
||||||
DED7D73D0A524295003AD0FB /* MacroExpander.h */,
|
|
||||||
DED7D73E0A524295003AD0FB /* MacroInfo.h */,
|
|
||||||
DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */,
|
|
||||||
DE01DA480B12ADA300AC22CE /* PPCallbacks.h */,
|
|
||||||
DED7D73F0A524295003AD0FB /* Pragma.h */,
|
|
||||||
DED7D7400A524295003AD0FB /* Preprocessor.h */,
|
|
||||||
DED7D9170A52518C003AD0FB /* ScratchBuffer.h */,
|
|
||||||
DE6954630C5121BD00A5826B /* Token.h */,
|
|
||||||
);
|
|
||||||
name = Lex;
|
|
||||||
path = clang/Lex;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DED7D7500A5242C7003AD0FB /* Basic */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DED7D75D0A5242C7003AD0FB /* Diagnostic.cpp */,
|
|
||||||
DED7D75E0A5242C7003AD0FB /* FileManager.cpp */,
|
|
||||||
DED7D76D0A5242C7003AD0FB /* SourceManager.cpp */,
|
|
||||||
DED7D76E0A5242C7003AD0FB /* TokenKinds.cpp */,
|
|
||||||
DED626C80AE0C065001E80A4 /* TargetInfo.cpp */,
|
|
||||||
);
|
|
||||||
path = Basic;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DED7D78C0A5242E6003AD0FB /* Lex */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */,
|
|
||||||
DED7D79D0A5242E6003AD0FB /* IdentifierTable.cpp */,
|
|
||||||
DED7D79E0A5242E6003AD0FB /* Lexer.cpp */,
|
|
||||||
1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */,
|
|
||||||
DE3451570AEC176100DBC861 /* MacroExpander.cpp */,
|
|
||||||
DED7D7A00A5242E6003AD0FB /* MacroInfo.cpp */,
|
|
||||||
DED7D7A20A5242E6003AD0FB /* PPExpressions.cpp */,
|
|
||||||
DED7D7A30A5242E6003AD0FB /* Pragma.cpp */,
|
|
||||||
DED7D7A40A5242E6003AD0FB /* Preprocessor.cpp */,
|
|
||||||
DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */,
|
|
||||||
);
|
|
||||||
path = Lex;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
|
||||||
8DD76F620486A84900D96B5E /* clang */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "clang" */;
|
|
||||||
buildPhases = (
|
|
||||||
8DD76F640486A84900D96B5E /* Sources */,
|
|
||||||
8DD76F660486A84900D96B5E /* Frameworks */,
|
|
||||||
8DD76F690486A84900D96B5E /* CopyFiles */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = clang;
|
|
||||||
productInstallPath = "$(HOME)/bin";
|
|
||||||
productName = clang;
|
|
||||||
productReference = 8DD76F6C0486A84900D96B5E /* clang */;
|
|
||||||
productType = "com.apple.product-type.tool";
|
|
||||||
};
|
|
||||||
/* End PBXNativeTarget section */
|
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
|
||||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
|
||||||
isa = PBXProject;
|
|
||||||
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
|
|
||||||
hasScannedForEncodings = 1;
|
|
||||||
mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
|
|
||||||
projectDirPath = "";
|
|
||||||
projectRoot = "";
|
|
||||||
targets = (
|
|
||||||
8DD76F620486A84900D96B5E /* clang */,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
/* End PBXProject section */
|
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
|
||||||
8DD76F640486A84900D96B5E /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
DED7D77A0A5242C7003AD0FB /* Diagnostic.cpp in Sources */,
|
|
||||||
DED7D77B0A5242C7003AD0FB /* FileManager.cpp in Sources */,
|
|
||||||
DED7D7890A5242C7003AD0FB /* SourceManager.cpp in Sources */,
|
|
||||||
DED7D78A0A5242C7003AD0FB /* TokenKinds.cpp in Sources */,
|
|
||||||
DED7D7C20A5242E6003AD0FB /* IdentifierTable.cpp in Sources */,
|
|
||||||
DED7D7C30A5242E6003AD0FB /* Lexer.cpp in Sources */,
|
|
||||||
DED7D7C50A5242E6003AD0FB /* MacroInfo.cpp in Sources */,
|
|
||||||
DED7D7C70A5242E6003AD0FB /* PPExpressions.cpp in Sources */,
|
|
||||||
DED7D7C80A5242E6003AD0FB /* Pragma.cpp in Sources */,
|
|
||||||
DED7D7C90A5242E6003AD0FB /* Preprocessor.cpp in Sources */,
|
|
||||||
DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */,
|
|
||||||
DE06D4310A8BB52D0050E87E /* Parser.cpp in Sources */,
|
|
||||||
DE0FCB340A9C21F100248FD5 /* Expr.cpp in Sources */,
|
|
||||||
DE5932D10AD60FF400BC794C /* clang.cpp in Sources */,
|
|
||||||
DE5932D30AD60FF400BC794C /* PrintParserCallbacks.cpp in Sources */,
|
|
||||||
DE5932D40AD60FF400BC794C /* PrintPreprocessedOutput.cpp in Sources */,
|
|
||||||
DED626C90AE0C065001E80A4 /* TargetInfo.cpp in Sources */,
|
|
||||||
DED627030AE0C51D001E80A4 /* Targets.cpp in Sources */,
|
|
||||||
DED62ABB0AE2EDF1001E80A4 /* Decl.cpp in Sources */,
|
|
||||||
DE344B540AE5E46C00DBC861 /* HeaderSearch.cpp in Sources */,
|
|
||||||
DE3451580AEC176100DBC861 /* MacroExpander.cpp in Sources */,
|
|
||||||
DE3452410AEF1A2D00DBC861 /* Stmt.cpp in Sources */,
|
|
||||||
DE3460000AFDCC1900DBC861 /* ParseObjc.cpp in Sources */,
|
|
||||||
DE3460050AFDCC6500DBC861 /* ParseInit.cpp in Sources */,
|
|
||||||
DE34600B0AFDCCBF00DBC861 /* ParseStmt.cpp in Sources */,
|
|
||||||
DE34600F0AFDCCCE00DBC861 /* ParseDecl.cpp in Sources */,
|
|
||||||
DE3460130AFDCCDA00DBC861 /* ParseExpr.cpp in Sources */,
|
|
||||||
DE3461270AFE68BE00DBC861 /* MinimalAction.cpp in Sources */,
|
|
||||||
DE34621D0AFEB19B00DBC861 /* StmtPrinter.cpp in Sources */,
|
|
||||||
DE75EDF10B06880E0020CF81 /* Type.cpp in Sources */,
|
|
||||||
DE1733000B068B700080B521 /* ASTContext.cpp in Sources */,
|
|
||||||
DE17336E0B068DC20080B521 /* DeclSpec.cpp in Sources */,
|
|
||||||
DED677C90B6C854100AAD4A3 /* Builtins.cpp in Sources */,
|
|
||||||
1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */,
|
|
||||||
DE67E70B0C020EC500F66BC5 /* SemaType.cpp in Sources */,
|
|
||||||
DE67E70D0C020ECA00F66BC5 /* SemaStmt.cpp in Sources */,
|
|
||||||
DE67E70F0C020ECF00F66BC5 /* SemaExprCXX.cpp in Sources */,
|
|
||||||
DE67E7110C020ED400F66BC5 /* SemaExpr.cpp in Sources */,
|
|
||||||
DE67E7130C020ED900F66BC5 /* SemaDecl.cpp in Sources */,
|
|
||||||
DE67E7170C020EE400F66BC5 /* Sema.cpp in Sources */,
|
|
||||||
DE67E71A0C020F4F00F66BC5 /* ASTStreamer.cpp in Sources */,
|
|
||||||
DE06756C0C051CFE00EBBFD8 /* ParseExprCXX.cpp in Sources */,
|
|
||||||
DE927FFD0C055DE900231DA4 /* LLVMCodegen.cpp in Sources */,
|
|
||||||
DE928B130C05659200231DA4 /* ModuleBuilder.cpp in Sources */,
|
|
||||||
DE928B7F0C0A615600231DA4 /* CodeGenModule.cpp in Sources */,
|
|
||||||
DE928B830C0A616000231DA4 /* CodeGenFunction.cpp in Sources */,
|
|
||||||
DE4772FA0C10EAE5002239E8 /* CGStmt.cpp in Sources */,
|
|
||||||
DE4772FC0C10EAEC002239E8 /* CGExpr.cpp in Sources */,
|
|
||||||
DE4264FC0C113592005A861D /* CGDecl.cpp in Sources */,
|
|
||||||
F0226FD20C18084500141F42 /* TextDiagnosticPrinter.cpp in Sources */,
|
|
||||||
84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */,
|
|
||||||
DEB0AEBB0C2087AB00718A22 /* TextDiagnostics.cpp in Sources */,
|
|
||||||
DEEBC3BC0C2363BC00A9FE82 /* CodeGenTypes.cpp in Sources */,
|
|
||||||
DEC82DC40C32D50A00BAC245 /* DiagChecker.cpp in Sources */,
|
|
||||||
DEEBCBE50C33703100A9FE82 /* TextDiagnosticBuffer.cpp in Sources */,
|
|
||||||
DEF2E9340C5FBA02000C4259 /* ASTStreamers.cpp in Sources */,
|
|
||||||
DEF2EDA70C6A4252000C4259 /* StmtDumper.cpp in Sources */,
|
|
||||||
DEF2EFF30C6CDD74000C4259 /* CGExprAgg.cpp in Sources */,
|
|
||||||
DEF2F0100C6CFED5000C4259 /* SemaChecking.cpp in Sources */,
|
|
||||||
1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */,
|
|
||||||
DE224FF80C7AA98800D370A5 /* CGExprComplex.cpp in Sources */,
|
|
||||||
1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */,
|
|
||||||
DEC63B1A0C7B940200DBF169 /* CFG.cpp in Sources */,
|
|
||||||
DE2252700C7E82D000D370A5 /* CGExprScalar.cpp in Sources */,
|
|
||||||
35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */,
|
|
||||||
DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */,
|
|
||||||
356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */,
|
|
||||||
355CF6840C90A8D400A08AA3 /* DeadStores.cpp in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXSourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
|
||||||
1DEB923208733DC60010E9CD /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ARCHS = i386;
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
GCC_CW_ASM_SYNTAX = NO;
|
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
|
||||||
GCC_ENABLE_CPP_EXCEPTIONS = NO;
|
|
||||||
GCC_ENABLE_CPP_RTTI = NO;
|
|
||||||
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
|
||||||
GCC_ENABLE_PASCAL_STRINGS = NO;
|
|
||||||
GCC_ENABLE_SYMBOL_SEPARATION = NO;
|
|
||||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
|
||||||
GCC_MODEL_TUNING = G5;
|
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = "__STDC_LIMIT_MACROS=1";
|
|
||||||
GCC_STRICT_ALIASING = YES;
|
|
||||||
GCC_THREADSAFE_STATICS = NO;
|
|
||||||
GCC_USE_GCC3_PFE_SUPPORT = NO;
|
|
||||||
HEADER_SEARCH_PATHS = (
|
|
||||||
"~/llvm/tools/clang/include",
|
|
||||||
"~/llvm/include",
|
|
||||||
"$(HEADER_SEARCH_PATHS)",
|
|
||||||
);
|
|
||||||
INSTALL_PATH = "$(HOME)/bin";
|
|
||||||
LIBRARY_SEARCH_PATHS = "~/llvm/Debug/lib";
|
|
||||||
OTHER_LDFLAGS = (
|
|
||||||
"-lLLVMSupport",
|
|
||||||
"-lLLVMSystem",
|
|
||||||
);
|
|
||||||
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
|
|
||||||
PRODUCT_NAME = clang;
|
|
||||||
ZERO_LINK = NO;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
1DEB923308733DC60010E9CD /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ARCHS = i386;
|
|
||||||
GCC_CW_ASM_SYNTAX = NO;
|
|
||||||
GCC_ENABLE_CPP_EXCEPTIONS = NO;
|
|
||||||
GCC_ENABLE_CPP_RTTI = NO;
|
|
||||||
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
|
||||||
GCC_ENABLE_PASCAL_STRINGS = NO;
|
|
||||||
GCC_ENABLE_SYMBOL_SEPARATION = NO;
|
|
||||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
|
||||||
GCC_MODEL_TUNING = G5;
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = "__STDC_LIMIT_MACROS=1";
|
|
||||||
GCC_STRICT_ALIASING = YES;
|
|
||||||
GCC_THREADSAFE_STATICS = NO;
|
|
||||||
GCC_USE_GCC3_PFE_SUPPORT = NO;
|
|
||||||
HEADER_SEARCH_PATHS = (
|
|
||||||
"~/llvm/tools/clang/include",
|
|
||||||
"~/llvm/include",
|
|
||||||
"$(HEADER_SEARCH_PATHS)",
|
|
||||||
);
|
|
||||||
INSTALL_PATH = "$(HOME)/bin";
|
|
||||||
LIBRARY_SEARCH_PATHS = "~/llvm/Debug/lib";
|
|
||||||
OTHER_LDFLAGS = (
|
|
||||||
"-lLLVMSupport",
|
|
||||||
"-lLLVMSystem",
|
|
||||||
);
|
|
||||||
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
|
|
||||||
PRODUCT_NAME = clang;
|
|
||||||
ZERO_LINK = NO;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
1DEB923608733DC60010E9CD /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
PREBINDING = NO;
|
|
||||||
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
1DEB923708733DC60010E9CD /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
PREBINDING = NO;
|
|
||||||
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
/* End XCBuildConfiguration section */
|
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
|
||||||
1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "clang" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
1DEB923208733DC60010E9CD /* Debug */,
|
|
||||||
1DEB923308733DC60010E9CD /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
1DEB923608733DC60010E9CD /* Debug */,
|
|
||||||
1DEB923708733DC60010E9CD /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
/* End XCConfigurationList section */
|
|
||||||
};
|
|
||||||
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user