mirror of https://github.com/microsoft/clang.git
Stage two of getting CFE top correct.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@39734 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
a5f182095b
commit
5f016e2cb5
|
@ -0,0 +1,531 @@
|
|||
//===--- ASTContext.cpp - Context to hold long-lived AST nodes ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Chris Lattner and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the ASTContext interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
using namespace clang;
|
||||
|
||||
enum FloatingRank {
|
||||
FloatRank, DoubleRank, LongDoubleRank
|
||||
};
|
||||
|
||||
ASTContext::~ASTContext() {
|
||||
// Deallocate all the types.
|
||||
while (!Types.empty()) {
|
||||
if (FunctionTypeProto *FT = dyn_cast<FunctionTypeProto>(Types.back())) {
|
||||
// Destroy the object, but don't call delete. These are malloc'd.
|
||||
FT->~FunctionTypeProto();
|
||||
free(FT);
|
||||
} else {
|
||||
delete Types.back();
|
||||
}
|
||||
Types.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void ASTContext::PrintStats() const {
|
||||
fprintf(stderr, "*** AST Context Stats:\n");
|
||||
fprintf(stderr, " %d types total.\n", (int)Types.size());
|
||||
unsigned NumBuiltin = 0, NumPointer = 0, NumArray = 0, NumFunctionP = 0;
|
||||
unsigned NumFunctionNP = 0, NumTypeName = 0, NumTagged = 0, NumReference = 0;
|
||||
|
||||
unsigned NumTagStruct = 0, NumTagUnion = 0, NumTagEnum = 0, NumTagClass = 0;
|
||||
|
||||
for (unsigned i = 0, e = Types.size(); i != e; ++i) {
|
||||
Type *T = Types[i];
|
||||
if (isa<BuiltinType>(T))
|
||||
++NumBuiltin;
|
||||
else if (isa<PointerType>(T))
|
||||
++NumPointer;
|
||||
else if (isa<ReferenceType>(T))
|
||||
++NumReference;
|
||||
else if (isa<ArrayType>(T))
|
||||
++NumArray;
|
||||
else if (isa<FunctionTypeNoProto>(T))
|
||||
++NumFunctionNP;
|
||||
else if (isa<FunctionTypeProto>(T))
|
||||
++NumFunctionP;
|
||||
else if (isa<TypedefType>(T))
|
||||
++NumTypeName;
|
||||
else if (TagType *TT = dyn_cast<TagType>(T)) {
|
||||
++NumTagged;
|
||||
switch (TT->getDecl()->getKind()) {
|
||||
default: assert(0 && "Unknown tagged type!");
|
||||
case Decl::Struct: ++NumTagStruct; break;
|
||||
case Decl::Union: ++NumTagUnion; break;
|
||||
case Decl::Class: ++NumTagClass; break;
|
||||
case Decl::Enum: ++NumTagEnum; break;
|
||||
}
|
||||
} else {
|
||||
assert(0 && "Unknown type!");
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, " %d builtin types\n", NumBuiltin);
|
||||
fprintf(stderr, " %d pointer types\n", NumPointer);
|
||||
fprintf(stderr, " %d reference types\n", NumReference);
|
||||
fprintf(stderr, " %d array types\n", NumArray);
|
||||
fprintf(stderr, " %d function types with proto\n", NumFunctionP);
|
||||
fprintf(stderr, " %d function types with no proto\n", NumFunctionNP);
|
||||
fprintf(stderr, " %d typename (typedef) types\n", NumTypeName);
|
||||
fprintf(stderr, " %d tagged types\n", NumTagged);
|
||||
fprintf(stderr, " %d struct types\n", NumTagStruct);
|
||||
fprintf(stderr, " %d union types\n", NumTagUnion);
|
||||
fprintf(stderr, " %d class types\n", NumTagClass);
|
||||
fprintf(stderr, " %d enum types\n", NumTagEnum);
|
||||
fprintf(stderr, "Total bytes = %d\n", int(NumBuiltin*sizeof(BuiltinType)+
|
||||
NumPointer*sizeof(PointerType)+NumArray*sizeof(ArrayType)+
|
||||
NumFunctionP*sizeof(FunctionTypeProto)+
|
||||
NumFunctionNP*sizeof(FunctionTypeNoProto)+
|
||||
NumTypeName*sizeof(TypedefType)+NumTagged*sizeof(TagType)));
|
||||
}
|
||||
|
||||
|
||||
void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) {
|
||||
Types.push_back((R = QualType(new BuiltinType(K),0)).getTypePtr());
|
||||
}
|
||||
|
||||
|
||||
void ASTContext::InitBuiltinTypes() {
|
||||
assert(VoidTy.isNull() && "Context reinitialized?");
|
||||
|
||||
// C99 6.2.5p19.
|
||||
InitBuiltinType(VoidTy, BuiltinType::Void);
|
||||
|
||||
// C99 6.2.5p2.
|
||||
InitBuiltinType(BoolTy, BuiltinType::Bool);
|
||||
// C99 6.2.5p3.
|
||||
if (Target.isCharSigned(SourceLocation()))
|
||||
InitBuiltinType(CharTy, BuiltinType::Char_S);
|
||||
else
|
||||
InitBuiltinType(CharTy, BuiltinType::Char_U);
|
||||
// C99 6.2.5p4.
|
||||
InitBuiltinType(SignedCharTy, BuiltinType::SChar);
|
||||
InitBuiltinType(ShortTy, BuiltinType::Short);
|
||||
InitBuiltinType(IntTy, BuiltinType::Int);
|
||||
InitBuiltinType(LongTy, BuiltinType::Long);
|
||||
InitBuiltinType(LongLongTy, BuiltinType::LongLong);
|
||||
|
||||
// C99 6.2.5p6.
|
||||
InitBuiltinType(UnsignedCharTy, BuiltinType::UChar);
|
||||
InitBuiltinType(UnsignedShortTy, BuiltinType::UShort);
|
||||
InitBuiltinType(UnsignedIntTy, BuiltinType::UInt);
|
||||
InitBuiltinType(UnsignedLongTy, BuiltinType::ULong);
|
||||
InitBuiltinType(UnsignedLongLongTy, BuiltinType::ULongLong);
|
||||
|
||||
// C99 6.2.5p10.
|
||||
InitBuiltinType(FloatTy, BuiltinType::Float);
|
||||
InitBuiltinType(DoubleTy, BuiltinType::Double);
|
||||
InitBuiltinType(LongDoubleTy, BuiltinType::LongDouble);
|
||||
|
||||
// C99 6.2.5p11.
|
||||
FloatComplexTy = getComplexType(FloatTy);
|
||||
DoubleComplexTy = getComplexType(DoubleTy);
|
||||
LongDoubleComplexTy = getComplexType(LongDoubleTy);
|
||||
}
|
||||
|
||||
/// getComplexType - Return the uniqued reference to the type for a complex
|
||||
/// number with the specified element type.
|
||||
QualType ASTContext::getComplexType(QualType T) {
|
||||
// Unique pointers, to guarantee there is only one pointer of a particular
|
||||
// structure.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
ComplexType::Profile(ID, T);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (ComplexType *CT = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(CT, 0);
|
||||
|
||||
// If the pointee type isn't canonical, this won't be a canonical type either,
|
||||
// so fill in the canonical type field.
|
||||
QualType Canonical;
|
||||
if (!T->isCanonical()) {
|
||||
Canonical = getComplexType(T.getCanonicalType());
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
ComplexType *NewIP = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(NewIP == 0 && "Shouldn't be in the map!");
|
||||
}
|
||||
ComplexType *New = new ComplexType(T, Canonical);
|
||||
Types.push_back(New);
|
||||
ComplexTypes.InsertNode(New, InsertPos);
|
||||
return QualType(New, 0);
|
||||
}
|
||||
|
||||
|
||||
/// getPointerType - Return the uniqued reference to the type for a pointer to
|
||||
/// the specified type.
|
||||
QualType ASTContext::getPointerType(QualType T) {
|
||||
// Unique pointers, to guarantee there is only one pointer of a particular
|
||||
// structure.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
PointerType::Profile(ID, T);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (PointerType *PT = PointerTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(PT, 0);
|
||||
|
||||
// If the pointee type isn't canonical, this won't be a canonical type either,
|
||||
// so fill in the canonical type field.
|
||||
QualType Canonical;
|
||||
if (!T->isCanonical()) {
|
||||
Canonical = getPointerType(T.getCanonicalType());
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(NewIP == 0 && "Shouldn't be in the map!");
|
||||
}
|
||||
PointerType *New = new PointerType(T, Canonical);
|
||||
Types.push_back(New);
|
||||
PointerTypes.InsertNode(New, InsertPos);
|
||||
return QualType(New, 0);
|
||||
}
|
||||
|
||||
/// getReferenceType - Return the uniqued reference to the type for a reference
|
||||
/// to the specified type.
|
||||
QualType ASTContext::getReferenceType(QualType T) {
|
||||
// Unique pointers, to guarantee there is only one pointer of a particular
|
||||
// structure.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
ReferenceType::Profile(ID, T);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (ReferenceType *RT = ReferenceTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(RT, 0);
|
||||
|
||||
// If the referencee type isn't canonical, this won't be a canonical type
|
||||
// either, so fill in the canonical type field.
|
||||
QualType Canonical;
|
||||
if (!T->isCanonical()) {
|
||||
Canonical = getReferenceType(T.getCanonicalType());
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
ReferenceType *NewIP = ReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(NewIP == 0 && "Shouldn't be in the map!");
|
||||
}
|
||||
|
||||
ReferenceType *New = new ReferenceType(T, Canonical);
|
||||
Types.push_back(New);
|
||||
ReferenceTypes.InsertNode(New, InsertPos);
|
||||
return QualType(New, 0);
|
||||
}
|
||||
|
||||
/// getArrayType - Return the unique reference to the type for an array of the
|
||||
/// specified element type.
|
||||
QualType ASTContext::getArrayType(QualType EltTy,ArrayType::ArraySizeModifier ASM,
|
||||
unsigned EltTypeQuals, Expr *NumElts) {
|
||||
// Unique array types, to guarantee there is only one array of a particular
|
||||
// structure.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
ArrayType::Profile(ID, ASM, EltTypeQuals, EltTy, NumElts);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (ArrayType *ATP = ArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(ATP, 0);
|
||||
|
||||
// If the element type isn't canonical, this won't be a canonical type either,
|
||||
// so fill in the canonical type field.
|
||||
QualType Canonical;
|
||||
if (!EltTy->isCanonical()) {
|
||||
Canonical = getArrayType(EltTy.getCanonicalType(), ASM, EltTypeQuals,
|
||||
NumElts);
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
ArrayType *NewIP = ArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(NewIP == 0 && "Shouldn't be in the map!");
|
||||
}
|
||||
|
||||
ArrayType *New = new ArrayType(EltTy, ASM, EltTypeQuals, Canonical, NumElts);
|
||||
ArrayTypes.InsertNode(New, InsertPos);
|
||||
Types.push_back(New);
|
||||
return QualType(New, 0);
|
||||
}
|
||||
|
||||
/// convertToVectorType - Return the unique reference to a vector type of
|
||||
/// the specified element type and size. VectorType can be a pointer, array,
|
||||
/// function, or built-in type (i.e. _Bool, integer, or float).
|
||||
QualType ASTContext::convertToVectorType(QualType vecType, unsigned NumElts) {
|
||||
BuiltinType *baseType;
|
||||
|
||||
baseType = dyn_cast<BuiltinType>(vecType.getCanonicalType().getTypePtr());
|
||||
assert(baseType != 0 &&
|
||||
"convertToVectorType(): Complex vector types unimplemented");
|
||||
|
||||
// Check if we've already instantiated a vector of this type.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
VectorType::Profile(ID, vecType, NumElts);
|
||||
void *InsertPos = 0;
|
||||
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(VTP, 0);
|
||||
|
||||
// If the element type isn't canonical, this won't be a canonical type either,
|
||||
// so fill in the canonical type field.
|
||||
QualType Canonical;
|
||||
if (!vecType->isCanonical()) {
|
||||
Canonical = convertToVectorType(vecType.getCanonicalType(), NumElts);
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(NewIP == 0 && "Shouldn't be in the map!");
|
||||
}
|
||||
VectorType *New = new VectorType(vecType, NumElts, Canonical);
|
||||
VectorTypes.InsertNode(New, InsertPos);
|
||||
Types.push_back(New);
|
||||
return QualType(New, 0);
|
||||
}
|
||||
|
||||
/// getFunctionTypeNoProto - Return a K&R style C function type like 'int()'.
|
||||
///
|
||||
QualType ASTContext::getFunctionTypeNoProto(QualType ResultTy) {
|
||||
// Unique functions, to guarantee there is only one function of a particular
|
||||
// structure.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
FunctionTypeNoProto::Profile(ID, ResultTy);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (FunctionTypeNoProto *FT =
|
||||
FunctionTypeNoProtos.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(FT, 0);
|
||||
|
||||
QualType Canonical;
|
||||
if (!ResultTy->isCanonical()) {
|
||||
Canonical = getFunctionTypeNoProto(ResultTy.getCanonicalType());
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
FunctionTypeNoProto *NewIP =
|
||||
FunctionTypeNoProtos.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(NewIP == 0 && "Shouldn't be in the map!");
|
||||
}
|
||||
|
||||
FunctionTypeNoProto *New = new FunctionTypeNoProto(ResultTy, Canonical);
|
||||
Types.push_back(New);
|
||||
FunctionTypeProtos.InsertNode(New, InsertPos);
|
||||
return QualType(New, 0);
|
||||
}
|
||||
|
||||
/// getFunctionType - Return a normal function type with a typed argument
|
||||
/// list. isVariadic indicates whether the argument list includes '...'.
|
||||
QualType ASTContext::getFunctionType(QualType ResultTy, QualType *ArgArray,
|
||||
unsigned NumArgs, bool isVariadic) {
|
||||
// Unique functions, to guarantee there is only one function of a particular
|
||||
// structure.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
FunctionTypeProto::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (FunctionTypeProto *FTP =
|
||||
FunctionTypeProtos.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(FTP, 0);
|
||||
|
||||
// Determine whether the type being created is already canonical or not.
|
||||
bool isCanonical = ResultTy->isCanonical();
|
||||
for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
|
||||
if (!ArgArray[i]->isCanonical())
|
||||
isCanonical = false;
|
||||
|
||||
// If this type isn't canonical, get the canonical version of it.
|
||||
QualType Canonical;
|
||||
if (!isCanonical) {
|
||||
llvm::SmallVector<QualType, 16> CanonicalArgs;
|
||||
CanonicalArgs.reserve(NumArgs);
|
||||
for (unsigned i = 0; i != NumArgs; ++i)
|
||||
CanonicalArgs.push_back(ArgArray[i].getCanonicalType());
|
||||
|
||||
Canonical = getFunctionType(ResultTy.getCanonicalType(),
|
||||
&CanonicalArgs[0], NumArgs,
|
||||
isVariadic);
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
FunctionTypeProto *NewIP =
|
||||
FunctionTypeProtos.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(NewIP == 0 && "Shouldn't be in the map!");
|
||||
}
|
||||
|
||||
// FunctionTypeProto objects are not allocated with new because they have a
|
||||
// variable size array (for parameter types) at the end of them.
|
||||
FunctionTypeProto *FTP =
|
||||
(FunctionTypeProto*)malloc(sizeof(FunctionTypeProto) +
|
||||
(NumArgs-1)*sizeof(QualType));
|
||||
new (FTP) FunctionTypeProto(ResultTy, ArgArray, NumArgs, isVariadic,
|
||||
Canonical);
|
||||
Types.push_back(FTP);
|
||||
FunctionTypeProtos.InsertNode(FTP, InsertPos);
|
||||
return QualType(FTP, 0);
|
||||
}
|
||||
|
||||
/// getTypedefType - Return the unique reference to the type for the
|
||||
/// specified typename decl.
|
||||
QualType ASTContext::getTypedefType(TypedefDecl *Decl) {
|
||||
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
|
||||
|
||||
QualType Canonical = Decl->getUnderlyingType().getCanonicalType();
|
||||
Decl->TypeForDecl = new TypedefType(Decl, Canonical);
|
||||
Types.push_back(Decl->TypeForDecl);
|
||||
return QualType(Decl->TypeForDecl, 0);
|
||||
}
|
||||
|
||||
/// getTagDeclType - Return the unique reference to the type for the
|
||||
/// specified TagDecl (struct/union/class/enum) decl.
|
||||
QualType ASTContext::getTagDeclType(TagDecl *Decl) {
|
||||
// The decl stores the type cache.
|
||||
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
|
||||
|
||||
Decl->TypeForDecl = new TagType(Decl, QualType());
|
||||
Types.push_back(Decl->TypeForDecl);
|
||||
return QualType(Decl->TypeForDecl, 0);
|
||||
}
|
||||
|
||||
/// getSizeType - Return the unique type for "size_t" (C99 7.17), the result
|
||||
/// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and
|
||||
/// needs to agree with the definition in <stddef.h>.
|
||||
QualType ASTContext::getSizeType() const {
|
||||
// On Darwin, size_t is defined as a "long unsigned int".
|
||||
// FIXME: should derive from "Target".
|
||||
return UnsignedLongTy;
|
||||
}
|
||||
|
||||
/// getIntegerBitwidth - Return the bitwidth of the specified integer type
|
||||
/// according to the target. 'Loc' specifies the source location that
|
||||
/// requires evaluation of this property.
|
||||
unsigned ASTContext::getIntegerBitwidth(QualType T, SourceLocation Loc) {
|
||||
if (const TagType *TT = dyn_cast<TagType>(T.getCanonicalType())) {
|
||||
assert(TT->getDecl()->getKind() == Decl::Enum && "not an int or enum");
|
||||
assert(0 && "FIXME: getIntegerBitwidth(enum) unimplemented!");
|
||||
}
|
||||
|
||||
const BuiltinType *BT = cast<BuiltinType>(T.getCanonicalType());
|
||||
switch (BT->getKind()) {
|
||||
default: assert(0 && "getIntegerBitwidth(): not a built-in integer");
|
||||
case BuiltinType::Bool: return Target.getBoolWidth(Loc);
|
||||
case BuiltinType::Char_S:
|
||||
case BuiltinType::Char_U:
|
||||
case BuiltinType::SChar:
|
||||
case BuiltinType::UChar: return Target.getCharWidth(Loc);
|
||||
case BuiltinType::Short:
|
||||
case BuiltinType::UShort: return Target.getShortWidth(Loc);
|
||||
case BuiltinType::Int:
|
||||
case BuiltinType::UInt: return Target.getIntWidth(Loc);
|
||||
case BuiltinType::Long:
|
||||
case BuiltinType::ULong: return Target.getLongWidth(Loc);
|
||||
case BuiltinType::LongLong:
|
||||
case BuiltinType::ULongLong: return Target.getLongLongWidth(Loc);
|
||||
}
|
||||
}
|
||||
|
||||
/// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This
|
||||
/// routine will assert if passed a built-in type that isn't an integer or enum.
|
||||
static int getIntegerRank(QualType t) {
|
||||
if (const TagType *TT = dyn_cast<TagType>(t.getCanonicalType())) {
|
||||
assert(TT->getDecl()->getKind() == Decl::Enum && "not an int or enum");
|
||||
return 4;
|
||||
}
|
||||
|
||||
const BuiltinType *BT = cast<BuiltinType>(t.getCanonicalType());
|
||||
switch (BT->getKind()) {
|
||||
default:
|
||||
assert(0 && "getIntegerRank(): not a built-in integer");
|
||||
case BuiltinType::Bool:
|
||||
return 1;
|
||||
case BuiltinType::Char_S:
|
||||
case BuiltinType::Char_U:
|
||||
case BuiltinType::SChar:
|
||||
case BuiltinType::UChar:
|
||||
return 2;
|
||||
case BuiltinType::Short:
|
||||
case BuiltinType::UShort:
|
||||
return 3;
|
||||
case BuiltinType::Int:
|
||||
case BuiltinType::UInt:
|
||||
return 4;
|
||||
case BuiltinType::Long:
|
||||
case BuiltinType::ULong:
|
||||
return 5;
|
||||
case BuiltinType::LongLong:
|
||||
case BuiltinType::ULongLong:
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
/// getFloatingRank - Return a relative rank for floating point types.
|
||||
/// This routine will assert if passed a built-in type that isn't a float.
|
||||
static int getFloatingRank(QualType T) {
|
||||
T = T.getCanonicalType();
|
||||
if (ComplexType *CT = dyn_cast<ComplexType>(T))
|
||||
return getFloatingRank(CT->getElementType());
|
||||
|
||||
switch (cast<BuiltinType>(T)->getKind()) {
|
||||
default: assert(0 && "getFloatingPointRank(): not a floating type");
|
||||
case BuiltinType::Float: return FloatRank;
|
||||
case BuiltinType::Double: return DoubleRank;
|
||||
case BuiltinType::LongDouble: return LongDoubleRank;
|
||||
}
|
||||
}
|
||||
|
||||
// maxComplexType - the following code handles 3 different combinations:
|
||||
// complex/complex, complex/float, float/complex.
|
||||
// When both operands are complex, the shorter operand is converted to the
|
||||
// type of the longer, and that is the type of the result. This corresponds
|
||||
// to what is done when combining two real floating-point operands.
|
||||
// The fun begins when size promotion occur across type domains. g
|
||||
// getFloatingRank & convertFloatingRankToComplexType handle this without
|
||||
// enumerating all permutations.
|
||||
// It also allows us to add new types without breakage.
|
||||
// From H&S 6.3.4: When one operand is complex and the other is a real
|
||||
// floating-point type, the less precise type is converted, within it's
|
||||
// real or complex domain, to the precision of the other type. For example,
|
||||
// when combining a "long double" with a "double _Complex", the
|
||||
// "double _Complex" is promoted to "long double _Complex".
|
||||
|
||||
QualType ASTContext::maxComplexType(QualType lt, QualType rt) const {
|
||||
switch (std::max(getFloatingRank(lt), getFloatingRank(rt))) {
|
||||
default: assert(0 && "convertRankToComplex(): illegal value for rank");
|
||||
case FloatRank: return FloatComplexTy;
|
||||
case DoubleRank: return DoubleComplexTy;
|
||||
case LongDoubleRank: return LongDoubleComplexTy;
|
||||
}
|
||||
}
|
||||
|
||||
// maxFloatingType - handles the simple case, both operands are floats.
|
||||
QualType ASTContext::maxFloatingType(QualType lt, QualType rt) {
|
||||
return getFloatingRank(lt) > getFloatingRank(rt) ? lt : rt;
|
||||
}
|
||||
|
||||
// maxIntegerType - Returns the highest ranked integer type. Handles 3 case:
|
||||
// unsigned/unsigned, signed/signed, signed/unsigned. C99 6.3.1.8p1.
|
||||
QualType ASTContext::maxIntegerType(QualType lhs, QualType rhs) {
|
||||
if (lhs == rhs) return lhs;
|
||||
|
||||
bool t1Unsigned = lhs->isUnsignedIntegerType();
|
||||
bool t2Unsigned = rhs->isUnsignedIntegerType();
|
||||
|
||||
if ((t1Unsigned && t2Unsigned) || (!t1Unsigned && !t2Unsigned))
|
||||
return getIntegerRank(lhs) >= getIntegerRank(rhs) ? lhs : rhs;
|
||||
|
||||
// We have two integer types with differing signs
|
||||
QualType unsignedType = t1Unsigned ? lhs : rhs;
|
||||
QualType signedType = t1Unsigned ? rhs : lhs;
|
||||
|
||||
if (getIntegerRank(unsignedType) >= getIntegerRank(signedType))
|
||||
return unsignedType;
|
||||
else {
|
||||
// FIXME: Need to check if the signed type can represent all values of the
|
||||
// unsigned type. If it can, then the result is the signed type.
|
||||
// If it can't, then the result is the unsigned version of the signed type.
|
||||
// Should probably add a helper that returns a signed integer type from
|
||||
// an unsigned (and vice versa). C99 6.3.1.8.
|
||||
return signedType;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
//===--- Builtins.cpp - Builtin function implementation -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Chris Lattner and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements various things for builtin functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Builtins.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Lex/IdentifierTable.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
using namespace clang;
|
||||
|
||||
static const Builtin::Info BuiltinInfo[] = {
|
||||
{ "not a builtin function", 0, 0 },
|
||||
#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS },
|
||||
#include "clang/AST/Builtins.def"
|
||||
};
|
||||
|
||||
const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const {
|
||||
if (ID < Builtin::FirstTSBuiltin)
|
||||
return BuiltinInfo[ID];
|
||||
assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!");
|
||||
return TSRecords[ID - Builtin::FirstTSBuiltin];
|
||||
}
|
||||
|
||||
|
||||
/// InitializeBuiltins - Mark the identifiers for all the builtins with their
|
||||
/// appropriate builtin ID # and mark any non-portable builtin identifiers as
|
||||
/// such.
|
||||
void Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
|
||||
const TargetInfo &Target) {
|
||||
// Step #1: mark all target-independent builtins with their ID's.
|
||||
for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
|
||||
Table.get(BuiltinInfo[i].Name).setBuiltinID(i);
|
||||
|
||||
// Step #2: handle target builtins.
|
||||
std::vector<const char *> NonPortableBuiltins;
|
||||
Target.getTargetBuiltins(TSRecords, NumTSRecords, NonPortableBuiltins);
|
||||
|
||||
// Step #2a: Register target-specific builtins.
|
||||
for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
|
||||
Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin);
|
||||
|
||||
// Step #2b: Mark non-portable builtins as such.
|
||||
for (unsigned i = 0, e = NonPortableBuiltins.size(); i != e; ++i)
|
||||
Table.get(NonPortableBuiltins[i]).setNonPortableBuiltin(true);
|
||||
}
|
||||
|
||||
/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the
|
||||
/// pointer over the consumed characters. This returns the resultant type.
|
||||
static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context) {
|
||||
// Modifiers.
|
||||
bool Long = false, LongLong = false, Signed = false, Unsigned = false;
|
||||
|
||||
// Read the modifiers first.
|
||||
bool Done = false;
|
||||
while (!Done) {
|
||||
switch (*Str++) {
|
||||
default: Done = true; --Str; break;
|
||||
case 'S':
|
||||
assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!");
|
||||
assert(!Signed && "Can't use 'S' modifier multiple times!");
|
||||
Signed = true;
|
||||
break;
|
||||
case 'U':
|
||||
assert(!Signed && "Can't use both 'S' and 'U' modifiers!");
|
||||
assert(!Unsigned && "Can't use 'S' modifier multiple times!");
|
||||
Unsigned = true;
|
||||
break;
|
||||
case 'L':
|
||||
assert(!LongLong && "Can't have LLL modifier");
|
||||
if (Long)
|
||||
LongLong = true;
|
||||
else
|
||||
Long = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the base type.
|
||||
switch (*Str++) {
|
||||
default: assert(0 && "Unknown builtin type letter!");
|
||||
case 'v':
|
||||
assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'f'!");
|
||||
return Context.VoidTy;
|
||||
case 'f':
|
||||
assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'f'!");
|
||||
return Context.FloatTy;
|
||||
case 'd':
|
||||
assert(!LongLong && !Signed && !Unsigned && "Bad modifiers used with 'd'!");
|
||||
if (Long)
|
||||
return Context.LongDoubleTy;
|
||||
return Context.DoubleTy;
|
||||
case 's':
|
||||
assert(!LongLong && "Bad modifiers used with 's'!");
|
||||
if (Unsigned)
|
||||
return Context.UnsignedShortTy;
|
||||
return Context.ShortTy;
|
||||
//case 'i':
|
||||
}
|
||||
}
|
||||
|
||||
/// GetBuiltinType - Return the type for the specified builtin.
|
||||
QualType Builtin::Context::GetBuiltinType(unsigned id, ASTContext &Context)const{
|
||||
const char *TypeStr = GetRecord(id).Type;
|
||||
|
||||
llvm::SmallVector<QualType, 8> ArgTypes;
|
||||
|
||||
QualType ResType = DecodeTypeFromStr(TypeStr, Context);
|
||||
while (TypeStr[0] && TypeStr[0] != '.')
|
||||
ArgTypes.push_back(DecodeTypeFromStr(TypeStr, Context));
|
||||
|
||||
assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
|
||||
"'.' should only occur at end of builtin type list!");
|
||||
|
||||
return Context.getFunctionType(ResType, &ArgTypes[0], ArgTypes.size(),
|
||||
TypeStr[0] == '.');
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
//===--- Decl.cpp - Declaration AST Node Implementation -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Chris Lattner and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the Decl class and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/Lex/IdentifierTable.h"
|
||||
using namespace clang;
|
||||
|
||||
// temporary statistics gathering
|
||||
static unsigned nFuncs = 0;
|
||||
static unsigned nBlockVars = 0;
|
||||
static unsigned nFileVars = 0;
|
||||
static unsigned nParmVars = 0;
|
||||
static unsigned nSUC = 0;
|
||||
static unsigned nEnumConst = 0;
|
||||
static unsigned nEnumDecls = 0;
|
||||
static unsigned nTypedef = 0;
|
||||
static unsigned nFieldDecls = 0;
|
||||
static bool StatSwitch = false;
|
||||
|
||||
bool Decl::CollectingStats(bool enable) {
|
||||
if (enable) StatSwitch = true;
|
||||
return StatSwitch;
|
||||
}
|
||||
|
||||
void Decl::PrintStats() {
|
||||
fprintf(stderr, "*** Decl Stats:\n");
|
||||
fprintf(stderr, " %d decls total.\n",
|
||||
int(nFuncs+nBlockVars+nFileVars+nParmVars+nFieldDecls+nSUC+
|
||||
nEnumDecls+nEnumConst+nTypedef));
|
||||
fprintf(stderr, " %d function decls, %d each (%d bytes)\n",
|
||||
nFuncs, (int)sizeof(FunctionDecl), int(nFuncs*sizeof(FunctionDecl)));
|
||||
fprintf(stderr, " %d block variable decls, %d each (%d bytes)\n",
|
||||
nBlockVars, (int)sizeof(BlockVarDecl),
|
||||
int(nBlockVars*sizeof(BlockVarDecl)));
|
||||
fprintf(stderr, " %d file variable decls, %d each (%d bytes)\n",
|
||||
nFileVars, (int)sizeof(FileVarDecl),
|
||||
int(nFileVars*sizeof(FileVarDecl)));
|
||||
fprintf(stderr, " %d parameter variable decls, %d each (%d bytes)\n",
|
||||
nParmVars, (int)sizeof(ParmVarDecl),
|
||||
int(nParmVars*sizeof(ParmVarDecl)));
|
||||
fprintf(stderr, " %d field decls, %d each (%d bytes)\n",
|
||||
nFieldDecls, (int)sizeof(FieldDecl),
|
||||
int(nFieldDecls*sizeof(FieldDecl)));
|
||||
fprintf(stderr, " %d struct/union/class decls, %d each (%d bytes)\n",
|
||||
nSUC, (int)sizeof(RecordDecl),
|
||||
int(nSUC*sizeof(RecordDecl)));
|
||||
fprintf(stderr, " %d enum decls, %d each (%d bytes)\n",
|
||||
nEnumDecls, (int)sizeof(EnumDecl),
|
||||
int(nEnumDecls*sizeof(EnumDecl)));
|
||||
fprintf(stderr, " %d enum constant decls, %d each (%d bytes)\n",
|
||||
nEnumConst, (int)sizeof(EnumConstantDecl),
|
||||
int(nEnumConst*sizeof(EnumConstantDecl)));
|
||||
fprintf(stderr, " %d typedef decls, %d each (%d bytes)\n",
|
||||
nTypedef, (int)sizeof(TypedefDecl),int(nTypedef*sizeof(TypedefDecl)));
|
||||
fprintf(stderr, "Total bytes = %d\n",
|
||||
int(nFuncs*sizeof(FunctionDecl)+nBlockVars*sizeof(BlockVarDecl)+
|
||||
nFileVars*sizeof(FileVarDecl)+nParmVars*sizeof(ParmVarDecl)+
|
||||
nFieldDecls*sizeof(FieldDecl)+nSUC*sizeof(RecordDecl)+
|
||||
nEnumDecls*sizeof(EnumDecl)+nEnumConst*sizeof(EnumConstantDecl)+
|
||||
nTypedef*sizeof(TypedefDecl)));
|
||||
}
|
||||
|
||||
void Decl::addDeclKind(const Kind k) {
|
||||
switch (k) {
|
||||
case Typedef:
|
||||
nTypedef++;
|
||||
break;
|
||||
case Function:
|
||||
nFuncs++;
|
||||
break;
|
||||
case BlockVariable:
|
||||
nBlockVars++;
|
||||
break;
|
||||
case FileVariable:
|
||||
nFileVars++;
|
||||
break;
|
||||
case ParmVariable:
|
||||
nParmVars++;
|
||||
break;
|
||||
case EnumConstant:
|
||||
nEnumConst++;
|
||||
break;
|
||||
case Field:
|
||||
nFieldDecls++;
|
||||
break;
|
||||
case Struct:
|
||||
case Union:
|
||||
case Class:
|
||||
nSUC++;
|
||||
break;
|
||||
case Enum:
|
||||
nEnumDecls++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Out-of-line virtual method providing a home for Decl.
|
||||
Decl::~Decl() {
|
||||
}
|
||||
|
||||
const char *Decl::getName() const {
|
||||
if (const IdentifierInfo *II = getIdentifier())
|
||||
return II->getName();
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
FunctionDecl::~FunctionDecl() {
|
||||
delete[] ParamInfo;
|
||||
}
|
||||
|
||||
unsigned FunctionDecl::getNumParams() const {
|
||||
return cast<FunctionTypeProto>(getType().getTypePtr())->getNumArgs();
|
||||
}
|
||||
|
||||
void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) {
|
||||
assert(ParamInfo == 0 && "Already has param info!");
|
||||
assert(NumParams == getNumParams() && "Parameter count mismatch!");
|
||||
|
||||
// Zero params -> null pointer.
|
||||
if (NumParams) {
|
||||
ParamInfo = new ParmVarDecl*[NumParams];
|
||||
memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// defineBody - When created, RecordDecl's correspond to a forward declared
|
||||
/// record. This method is used to mark the decl as being defined, with the
|
||||
/// specified contents.
|
||||
void RecordDecl::defineBody(FieldDecl **members, unsigned numMembers) {
|
||||
assert(!isDefinition() && "Cannot redefine record!");
|
||||
setDefinition(true);
|
||||
NumMembers = numMembers;
|
||||
if (numMembers) {
|
||||
Members = new FieldDecl*[numMembers];
|
||||
memcpy(Members, members, numMembers*sizeof(Decl*));
|
||||
}
|
||||
}
|
||||
|
||||
FieldDecl* RecordDecl::getMember(IdentifierInfo *name) {
|
||||
if (Members == 0 || NumMembers < 0)
|
||||
return 0;
|
||||
|
||||
// linear search. When C++ classes come along, will likely need to revisit.
|
||||
for (int i = 0; i < NumMembers; ++i) {
|
||||
if (Members[i]->getIdentifier() == name)
|
||||
return Members[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,536 @@
|
|||
//===--- Expr.cpp - Expression AST Node Implementation --------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Chris Lattner and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the Expr class and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Lex/IdentifierTable.h"
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Primary Expressions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
StringLiteral::StringLiteral(const char *strData, unsigned byteLength,
|
||||
bool Wide, QualType t, SourceLocation firstLoc,
|
||||
SourceLocation lastLoc) :
|
||||
Expr(StringLiteralClass, t) {
|
||||
// OPTIMIZE: could allocate this appended to the StringLiteral.
|
||||
char *AStrData = new char[byteLength];
|
||||
memcpy(AStrData, strData, byteLength);
|
||||
StrData = AStrData;
|
||||
ByteLength = byteLength;
|
||||
IsWide = Wide;
|
||||
firstTokLoc = firstLoc;
|
||||
lastTokLoc = lastLoc;
|
||||
}
|
||||
|
||||
StringLiteral::~StringLiteral() {
|
||||
delete[] StrData;
|
||||
}
|
||||
|
||||
bool UnaryOperator::isPostfix(Opcode Op) {
|
||||
switch (Op) {
|
||||
case PostInc:
|
||||
case PostDec:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
|
||||
/// corresponds to, e.g. "sizeof" or "[pre]++".
|
||||
const char *UnaryOperator::getOpcodeStr(Opcode Op) {
|
||||
switch (Op) {
|
||||
default: assert(0 && "Unknown unary operator");
|
||||
case PostInc: return "++";
|
||||
case PostDec: return "--";
|
||||
case PreInc: return "++";
|
||||
case PreDec: return "--";
|
||||
case AddrOf: return "&";
|
||||
case Deref: return "*";
|
||||
case Plus: return "+";
|
||||
case Minus: return "-";
|
||||
case Not: return "~";
|
||||
case LNot: return "!";
|
||||
case Real: return "__real";
|
||||
case Imag: return "__imag";
|
||||
case SizeOf: return "sizeof";
|
||||
case AlignOf: return "alignof";
|
||||
case Extension: return "__extension__";
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Postfix Operators.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CallExpr::CallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t,
|
||||
SourceLocation rparenloc)
|
||||
: Expr(CallExprClass, t), Fn(fn), NumArgs(numargs) {
|
||||
Args = new Expr*[numargs];
|
||||
for (unsigned i = 0; i != numargs; ++i)
|
||||
Args[i] = args[i];
|
||||
RParenLoc = rparenloc;
|
||||
}
|
||||
|
||||
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
|
||||
/// corresponds to, e.g. "<<=".
|
||||
const char *BinaryOperator::getOpcodeStr(Opcode Op) {
|
||||
switch (Op) {
|
||||
default: assert(0 && "Unknown binary operator");
|
||||
case Mul: return "*";
|
||||
case Div: return "/";
|
||||
case Rem: return "%";
|
||||
case Add: return "+";
|
||||
case Sub: return "-";
|
||||
case Shl: return "<<";
|
||||
case Shr: return ">>";
|
||||
case LT: return "<";
|
||||
case GT: return ">";
|
||||
case LE: return "<=";
|
||||
case GE: return ">=";
|
||||
case EQ: return "==";
|
||||
case NE: return "!=";
|
||||
case And: return "&";
|
||||
case Xor: return "^";
|
||||
case Or: return "|";
|
||||
case LAnd: return "&&";
|
||||
case LOr: return "||";
|
||||
case Assign: return "=";
|
||||
case MulAssign: return "*=";
|
||||
case DivAssign: return "/=";
|
||||
case RemAssign: return "%=";
|
||||
case AddAssign: return "+=";
|
||||
case SubAssign: return "-=";
|
||||
case ShlAssign: return "<<=";
|
||||
case ShrAssign: return ">>=";
|
||||
case AndAssign: return "&=";
|
||||
case XorAssign: return "^=";
|
||||
case OrAssign: return "|=";
|
||||
case Comma: return ",";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Generic Expression Routines
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// hasLocalSideEffect - Return true if this immediate expression has side
|
||||
/// effects, not counting any sub-expressions.
|
||||
bool Expr::hasLocalSideEffect() const {
|
||||
switch (getStmtClass()) {
|
||||
default:
|
||||
return false;
|
||||
case ParenExprClass:
|
||||
return cast<ParenExpr>(this)->getSubExpr()->hasLocalSideEffect();
|
||||
case UnaryOperatorClass: {
|
||||
const UnaryOperator *UO = cast<UnaryOperator>(this);
|
||||
|
||||
switch (UO->getOpcode()) {
|
||||
default: return false;
|
||||
case UnaryOperator::PostInc:
|
||||
case UnaryOperator::PostDec:
|
||||
case UnaryOperator::PreInc:
|
||||
case UnaryOperator::PreDec:
|
||||
return true; // ++/--
|
||||
|
||||
case UnaryOperator::Deref:
|
||||
// Dereferencing a volatile pointer is a side-effect.
|
||||
return getType().isVolatileQualified();
|
||||
case UnaryOperator::Real:
|
||||
case UnaryOperator::Imag:
|
||||
// accessing a piece of a volatile complex is a side-effect.
|
||||
return UO->getSubExpr()->getType().isVolatileQualified();
|
||||
|
||||
case UnaryOperator::Extension:
|
||||
return UO->getSubExpr()->hasLocalSideEffect();
|
||||
}
|
||||
}
|
||||
case BinaryOperatorClass:
|
||||
return cast<BinaryOperator>(this)->isAssignmentOp();
|
||||
|
||||
case MemberExprClass:
|
||||
case ArraySubscriptExprClass:
|
||||
// If the base pointer or element is to a volatile pointer/field, accessing
|
||||
// if is a side effect.
|
||||
return getType().isVolatileQualified();
|
||||
|
||||
case CallExprClass:
|
||||
// TODO: check attributes for pure/const. "void foo() { strlen("bar"); }"
|
||||
// should warn.
|
||||
return true;
|
||||
|
||||
case CastExprClass:
|
||||
// If this is a cast to void, check the operand. Otherwise, the result of
|
||||
// the cast is unused.
|
||||
if (getType()->isVoidType())
|
||||
return cast<CastExpr>(this)->getSubExpr()->hasLocalSideEffect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an
|
||||
/// incomplete type other than void. Nonarray expressions that can be lvalues:
|
||||
/// - name, where name must be a variable
|
||||
/// - e[i]
|
||||
/// - (e), where e must be an lvalue
|
||||
/// - e.name, where e must be an lvalue
|
||||
/// - e->name
|
||||
/// - *e, the type of e cannot be a function type
|
||||
/// - string-constant
|
||||
///
|
||||
Expr::isLvalueResult Expr::isLvalue() {
|
||||
// first, check the type (C99 6.3.2.1)
|
||||
if (isa<FunctionType>(TR.getCanonicalType())) // from isObjectType()
|
||||
return LV_NotObjectType;
|
||||
|
||||
if (TR->isIncompleteType() && TR->isVoidType())
|
||||
return LV_IncompleteVoidType;
|
||||
|
||||
// the type looks fine, now check the expression
|
||||
switch (getStmtClass()) {
|
||||
case StringLiteralClass: // C99 6.5.1p4
|
||||
case ArraySubscriptExprClass: // C99 6.5.3p4 (e1[e2] == (*((e1)+(e2))))
|
||||
// For vectors, make sure base is an lvalue (i.e. not a function call).
|
||||
if (cast<ArraySubscriptExpr>(this)->getBase()->getType()->isVectorType())
|
||||
return cast<ArraySubscriptExpr>(this)->getBase()->isLvalue();
|
||||
return LV_Valid;
|
||||
case DeclRefExprClass: // C99 6.5.1p2
|
||||
if (isa<VarDecl>(cast<DeclRefExpr>(this)->getDecl()))
|
||||
return LV_Valid;
|
||||
break;
|
||||
case MemberExprClass: // C99 6.5.2.3p4
|
||||
const MemberExpr *m = cast<MemberExpr>(this);
|
||||
return m->isArrow() ? LV_Valid : m->getBase()->isLvalue();
|
||||
case UnaryOperatorClass: // C99 6.5.3p4
|
||||
if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref)
|
||||
return LV_Valid;
|
||||
break;
|
||||
case ParenExprClass: // C99 6.5.1p5
|
||||
return cast<ParenExpr>(this)->getSubExpr()->isLvalue();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return LV_InvalidExpression;
|
||||
}
|
||||
|
||||
/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
|
||||
/// does not have an incomplete type, does not have a const-qualified type, and
|
||||
/// if it is a structure or union, does not have any member (including,
|
||||
/// recursively, any member or element of all contained aggregates or unions)
|
||||
/// with a const-qualified type.
|
||||
Expr::isModifiableLvalueResult Expr::isModifiableLvalue() {
|
||||
isLvalueResult lvalResult = isLvalue();
|
||||
|
||||
switch (lvalResult) {
|
||||
case LV_Valid: break;
|
||||
case LV_NotObjectType: return MLV_NotObjectType;
|
||||
case LV_IncompleteVoidType: return MLV_IncompleteVoidType;
|
||||
case LV_InvalidExpression: return MLV_InvalidExpression;
|
||||
}
|
||||
if (TR.isConstQualified())
|
||||
return MLV_ConstQualified;
|
||||
if (TR->isArrayType())
|
||||
return MLV_ArrayType;
|
||||
if (TR->isIncompleteType())
|
||||
return MLV_IncompleteType;
|
||||
|
||||
if (const RecordType *r = dyn_cast<RecordType>(TR.getCanonicalType())) {
|
||||
if (r->hasConstFields())
|
||||
return MLV_ConstQualified;
|
||||
}
|
||||
return MLV_Valid;
|
||||
}
|
||||
|
||||
/// isIntegerConstantExpr - this recursive routine will test if an expression is
|
||||
/// an integer constant expression. Note: With the introduction of VLA's in
|
||||
/// C99 the result of the sizeof operator is no longer always a constant
|
||||
/// expression. The generalization of the wording to include any subexpression
|
||||
/// that is not evaluated (C99 6.6p3) means that nonconstant subexpressions
|
||||
/// can appear as operands to other operators (e.g. &&, ||, ?:). For instance,
|
||||
/// "0 || f()" can be treated as a constant expression. In C90 this expression,
|
||||
/// occurring in a context requiring a constant, would have been a constraint
|
||||
/// violation. FIXME: This routine currently implements C90 semantics.
|
||||
/// To properly implement C99 semantics this routine will need to evaluate
|
||||
/// expressions involving operators previously mentioned.
|
||||
|
||||
/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero,
|
||||
/// comma, etc
|
||||
///
|
||||
/// FIXME: This should ext-warn on overflow during evaluation! ISO C does not
|
||||
/// permit this.
|
||||
bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, SourceLocation *Loc,
|
||||
bool isEvaluated) const {
|
||||
switch (getStmtClass()) {
|
||||
default:
|
||||
if (Loc) *Loc = getLocStart();
|
||||
return false;
|
||||
case ParenExprClass:
|
||||
return cast<ParenExpr>(this)->getSubExpr()->
|
||||
isIntegerConstantExpr(Result, Loc, isEvaluated);
|
||||
case IntegerLiteralClass:
|
||||
Result = cast<IntegerLiteral>(this)->getValue();
|
||||
break;
|
||||
case CharacterLiteralClass:
|
||||
// FIXME: This doesn't set the right width etc.
|
||||
Result.zextOrTrunc(32); // FIXME: NOT RIGHT IN GENERAL.
|
||||
Result = cast<CharacterLiteral>(this)->getValue();
|
||||
break;
|
||||
case DeclRefExprClass:
|
||||
if (const EnumConstantDecl *D =
|
||||
dyn_cast<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl())) {
|
||||
Result = D->getInitVal();
|
||||
break;
|
||||
}
|
||||
if (Loc) *Loc = getLocStart();
|
||||
return false;
|
||||
case UnaryOperatorClass: {
|
||||
const UnaryOperator *Exp = cast<UnaryOperator>(this);
|
||||
|
||||
// Get the operand value. If this is sizeof/alignof, do not evalute the
|
||||
// operand. This affects C99 6.6p3.
|
||||
if (Exp->isSizeOfAlignOfOp()) isEvaluated = false;
|
||||
if (!Exp->getSubExpr()->isIntegerConstantExpr(Result, Loc, isEvaluated))
|
||||
return false;
|
||||
|
||||
switch (Exp->getOpcode()) {
|
||||
// Address, indirect, pre/post inc/dec, etc are not valid constant exprs.
|
||||
// See C99 6.6p3.
|
||||
default:
|
||||
if (Loc) *Loc = Exp->getOperatorLoc();
|
||||
return false;
|
||||
case UnaryOperator::Extension:
|
||||
return true;
|
||||
case UnaryOperator::SizeOf:
|
||||
case UnaryOperator::AlignOf:
|
||||
// sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
|
||||
if (!Exp->getSubExpr()->getType()->isConstantSizeType(Loc))
|
||||
return false;
|
||||
|
||||
// FIXME: Evaluate sizeof/alignof.
|
||||
Result.zextOrTrunc(32); // FIXME: NOT RIGHT IN GENERAL.
|
||||
Result = 1; // FIXME: Obviously bogus
|
||||
break;
|
||||
case UnaryOperator::LNot: {
|
||||
bool Val = Result != 0;
|
||||
Result.zextOrTrunc(32); // FIXME: NOT RIGHT IN GENERAL.
|
||||
Result = Val;
|
||||
break;
|
||||
}
|
||||
case UnaryOperator::Plus:
|
||||
// FIXME: Do usual unary promotions here!
|
||||
break;
|
||||
case UnaryOperator::Minus:
|
||||
// FIXME: Do usual unary promotions here!
|
||||
Result = -Result;
|
||||
break;
|
||||
case UnaryOperator::Not:
|
||||
// FIXME: Do usual unary promotions here!
|
||||
Result = ~Result;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SizeOfAlignOfTypeExprClass: {
|
||||
const SizeOfAlignOfTypeExpr *Exp = cast<SizeOfAlignOfTypeExpr>(this);
|
||||
// alignof always evaluates to a constant.
|
||||
if (Exp->isSizeOf() && !Exp->getArgumentType()->isConstantSizeType(Loc))
|
||||
return false;
|
||||
|
||||
// FIXME: Evaluate sizeof/alignof.
|
||||
Result.zextOrTrunc(32); // FIXME: NOT RIGHT IN GENERAL.
|
||||
Result = 1; // FIXME: Obviously bogus
|
||||
break;
|
||||
}
|
||||
case BinaryOperatorClass: {
|
||||
const BinaryOperator *Exp = cast<BinaryOperator>(this);
|
||||
|
||||
// The LHS of a constant expr is always evaluated and needed.
|
||||
if (!Exp->getLHS()->isIntegerConstantExpr(Result, Loc, isEvaluated))
|
||||
return false;
|
||||
|
||||
llvm::APSInt RHS(Result);
|
||||
|
||||
// The short-circuiting &&/|| operators don't necessarily evaluate their
|
||||
// RHS. Make sure to pass isEvaluated down correctly.
|
||||
if (Exp->isLogicalOp()) {
|
||||
bool RHSEval;
|
||||
if (Exp->getOpcode() == BinaryOperator::LAnd)
|
||||
RHSEval = Result != 0;
|
||||
else {
|
||||
assert(Exp->getOpcode() == BinaryOperator::LOr &&"Unexpected logical");
|
||||
RHSEval = Result == 0;
|
||||
}
|
||||
|
||||
if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Loc,
|
||||
isEvaluated & RHSEval))
|
||||
return false;
|
||||
} else {
|
||||
if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Loc, isEvaluated))
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: These should all do the standard promotions, etc.
|
||||
switch (Exp->getOpcode()) {
|
||||
default:
|
||||
if (Loc) *Loc = getLocStart();
|
||||
return false;
|
||||
case BinaryOperator::Mul:
|
||||
Result *= RHS;
|
||||
break;
|
||||
case BinaryOperator::Div:
|
||||
if (RHS == 0) {
|
||||
if (!isEvaluated) break;
|
||||
if (Loc) *Loc = getLocStart();
|
||||
return false;
|
||||
}
|
||||
Result /= RHS;
|
||||
break;
|
||||
case BinaryOperator::Rem:
|
||||
if (RHS == 0) {
|
||||
if (!isEvaluated) break;
|
||||
if (Loc) *Loc = getLocStart();
|
||||
return false;
|
||||
}
|
||||
Result %= RHS;
|
||||
break;
|
||||
case BinaryOperator::Add: Result += RHS; break;
|
||||
case BinaryOperator::Sub: Result -= RHS; break;
|
||||
case BinaryOperator::Shl:
|
||||
Result <<= RHS.getLimitedValue(Result.getBitWidth()-1);
|
||||
break;
|
||||
case BinaryOperator::Shr:
|
||||
Result >>= RHS.getLimitedValue(Result.getBitWidth()-1);
|
||||
break;
|
||||
case BinaryOperator::LT: Result = Result < RHS; break;
|
||||
case BinaryOperator::GT: Result = Result > RHS; break;
|
||||
case BinaryOperator::LE: Result = Result <= RHS; break;
|
||||
case BinaryOperator::GE: Result = Result >= RHS; break;
|
||||
case BinaryOperator::EQ: Result = Result == RHS; break;
|
||||
case BinaryOperator::NE: Result = Result != RHS; break;
|
||||
case BinaryOperator::And: Result &= RHS; break;
|
||||
case BinaryOperator::Xor: Result ^= RHS; break;
|
||||
case BinaryOperator::Or: Result |= RHS; break;
|
||||
case BinaryOperator::LAnd:
|
||||
Result = Result != 0 && RHS != 0;
|
||||
break;
|
||||
case BinaryOperator::LOr:
|
||||
Result = Result != 0 || RHS != 0;
|
||||
break;
|
||||
|
||||
case BinaryOperator::Comma:
|
||||
// C99 6.6p3: "shall not contain assignment, ..., or comma operators,
|
||||
// *except* when they are contained within a subexpression that is not
|
||||
// evaluated". Note that Assignment can never happen due to constraints
|
||||
// on the LHS subexpr, so we don't need to check it here.
|
||||
if (isEvaluated) {
|
||||
if (Loc) *Loc = getLocStart();
|
||||
return false;
|
||||
}
|
||||
|
||||
// The result of the constant expr is the RHS.
|
||||
Result = RHS;
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(!Exp->isAssignmentOp() && "LHS can't be a constant expr!");
|
||||
break;
|
||||
}
|
||||
case CastExprClass: {
|
||||
const CastExpr *Exp = cast<CastExpr>(this);
|
||||
// C99 6.6p6: shall only convert arithmetic types to integer types.
|
||||
if (!Exp->getSubExpr()->getType()->isArithmeticType() ||
|
||||
!Exp->getDestType()->isIntegerType()) {
|
||||
if (Loc) *Loc = Exp->getSubExpr()->getLocStart();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle simple integer->integer casts.
|
||||
if (Exp->getSubExpr()->getType()->isIntegerType()) {
|
||||
if (!Exp->getSubExpr()->isIntegerConstantExpr(Result, Loc, isEvaluated))
|
||||
return false;
|
||||
// FIXME: do the conversion on Result.
|
||||
break;
|
||||
}
|
||||
|
||||
// Allow floating constants that are the immediate operands of casts or that
|
||||
// are parenthesized.
|
||||
const Expr *Operand = Exp->getSubExpr();
|
||||
while (const ParenExpr *PE = dyn_cast<ParenExpr>(Operand))
|
||||
Operand = PE->getSubExpr();
|
||||
|
||||
if (const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(Operand)) {
|
||||
// FIXME: Evaluate this correctly!
|
||||
Result = (int)FL->getValue();
|
||||
break;
|
||||
}
|
||||
if (Loc) *Loc = Operand->getLocStart();
|
||||
return false;
|
||||
}
|
||||
case ConditionalOperatorClass: {
|
||||
const ConditionalOperator *Exp = cast<ConditionalOperator>(this);
|
||||
|
||||
if (!Exp->getCond()->isIntegerConstantExpr(Result, Loc, isEvaluated))
|
||||
return false;
|
||||
|
||||
const Expr *TrueExp = Exp->getLHS();
|
||||
const Expr *FalseExp = Exp->getRHS();
|
||||
if (Result == 0) std::swap(TrueExp, FalseExp);
|
||||
|
||||
// Evaluate the false one first, discard the result.
|
||||
if (!FalseExp->isIntegerConstantExpr(Result, Loc, false))
|
||||
return false;
|
||||
// Evalute the true one, capture the result.
|
||||
if (!TrueExp->isIntegerConstantExpr(Result, Loc, isEvaluated))
|
||||
return false;
|
||||
// FIXME: promotions on result.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cases that are valid constant exprs fall through to here.
|
||||
Result.setIsUnsigned(getType()->isUnsignedIntegerType());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an
|
||||
/// integer constant expression with the value zero, or if this is one that is
|
||||
/// cast to void*.
|
||||
bool Expr::isNullPointerConstant() const {
|
||||
// Strip off a cast to void*, if it exists.
|
||||
if (const CastExpr *CE = dyn_cast<CastExpr>(this)) {
|
||||
// Check that it is a cast to void*.
|
||||
if (const PointerType *PT = dyn_cast<PointerType>(CE->getType())) {
|
||||
QualType Pointee = PT->getPointeeType();
|
||||
if (Pointee.getQualifiers() == 0 && Pointee->isVoidType() && // to void*
|
||||
CE->getSubExpr()->getType()->isIntegerType()) // from int.
|
||||
return CE->getSubExpr()->isNullPointerConstant();
|
||||
}
|
||||
} else if (const ParenExpr *PE = dyn_cast<ParenExpr>(this)) {
|
||||
// Accept ((void*)0) as a null pointer constant, as many other
|
||||
// implementations do.
|
||||
return PE->getSubExpr()->isNullPointerConstant();
|
||||
}
|
||||
|
||||
// This expression must be an integer type.
|
||||
if (!getType()->isIntegerType())
|
||||
return false;
|
||||
|
||||
// If we have an integer constant expression, we need to *evaluate* it and
|
||||
// test for the value 0.
|
||||
llvm::APSInt Val(32);
|
||||
return isIntegerConstantExpr(Val, 0, true) && Val == 0;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
##===- clang/AST/Makefile ----------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file was developed by Chris Lattner and is distributed under
|
||||
# the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# This implements the AST library for the C-Language front-end.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../..
|
||||
LIBRARYNAME := clangAST
|
||||
BUILD_ARCHIVE = 1
|
||||
CXXFLAGS = -fno-rtti
|
||||
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Chris Lattner and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the Stmt class and statement subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Lex/IdentifierTable.h"
|
||||
using namespace clang;
|
||||
|
||||
// Implement all the AST node visit methods using the StmtNodes.def database.
|
||||
#define STMT(N, CLASS, PARENT) \
|
||||
void CLASS::visit(StmtVisitor &V) { return V.Visit##CLASS(this); }
|
||||
|
||||
STMT(0, Stmt, )
|
||||
#include "clang/AST/StmtNodes.def"
|
||||
|
||||
static struct StmtClassNameTable {
|
||||
int enumValue;
|
||||
const char *className;
|
||||
unsigned counter;
|
||||
unsigned size;
|
||||
} sNames[] = {
|
||||
#define STMT(N, CLASS, PARENT) { N, #CLASS, 0, sizeof(CLASS) },
|
||||
#include "clang/AST/StmtNodes.def"
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
const char *Stmt::getStmtClassName() const {
|
||||
for (int i = 0; sNames[i].className; i++) {
|
||||
if (sClass == sNames[i].enumValue)
|
||||
return sNames[i].className;
|
||||
}
|
||||
return 0; // should never happen....
|
||||
}
|
||||
|
||||
void Stmt::PrintStats() {
|
||||
unsigned sum = 0;
|
||||
fprintf(stderr, "*** Stmt/Expr Stats:\n");
|
||||
for (int i = 0; sNames[i].className; i++) {
|
||||
sum += sNames[i].counter;
|
||||
}
|
||||
fprintf(stderr, " %d stmts/exprs total.\n", sum);
|
||||
sum = 0;
|
||||
for (int i = 0; sNames[i].className; i++) {
|
||||
fprintf(stderr, " %d %s, %d each (%d bytes)\n",
|
||||
sNames[i].counter, sNames[i].className, sNames[i].size, sNames[i].counter*sNames[i].size);
|
||||
sum += sNames[i].counter*sNames[i].size;
|
||||
}
|
||||
fprintf(stderr, "Total bytes = %d\n", sum);
|
||||
}
|
||||
|
||||
void Stmt::addStmtClass(StmtClass s) {
|
||||
for (int i = 0; sNames[i].className; i++) {
|
||||
if (s == sNames[i].enumValue)
|
||||
sNames[i].counter++;
|
||||
}
|
||||
}
|
||||
|
||||
static bool StatSwitch = false;
|
||||
|
||||
bool Stmt::CollectingStats(bool enable) {
|
||||
if (enable) StatSwitch = true;
|
||||
return StatSwitch;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *LabelStmt::getName() const {
|
||||
return getID()->getName();
|
||||
}
|
||||
|
|
@ -0,0 +1,436 @@
|
|||
//===--- StmtPrinter.cpp - Printing implementation for Stmt ASTs ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Chris Lattner and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the Stmt::dump/Stmt::print methods.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/Lex/IdentifierTable.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <iostream>
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// StmtPrinter Visitor
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor {
|
||||
std::ostream &OS;
|
||||
unsigned IndentLevel;
|
||||
public:
|
||||
StmtPrinter(std::ostream &os) : OS(os), IndentLevel(0) {}
|
||||
|
||||
void PrintStmt(Stmt *S, int SubIndent = 1) {
|
||||
IndentLevel += SubIndent;
|
||||
if (S && isa<Expr>(S)) {
|
||||
// If this is an expr used in a stmt context, indent and newline it.
|
||||
Indent();
|
||||
S->visit(*this);
|
||||
OS << ";\n";
|
||||
} else if (S) {
|
||||
S->visit(*this);
|
||||
} else {
|
||||
Indent() << "<<<NULL STATEMENT>>>\n";
|
||||
}
|
||||
IndentLevel -= SubIndent;
|
||||
}
|
||||
|
||||
void PrintRawCompoundStmt(CompoundStmt *S);
|
||||
void PrintRawDecl(Decl *D);
|
||||
void PrintRawIfStmt(IfStmt *If);
|
||||
|
||||
void PrintExpr(Expr *E) {
|
||||
if (E)
|
||||
E->visit(*this);
|
||||
else
|
||||
OS << "<null expr>";
|
||||
}
|
||||
|
||||
std::ostream &Indent(int Delta = 0) const {
|
||||
for (int i = 0, e = IndentLevel+Delta; i < e; ++i)
|
||||
OS << " ";
|
||||
return OS;
|
||||
}
|
||||
|
||||
virtual void VisitStmt(Stmt *Node);
|
||||
#define STMT(N, CLASS, PARENT) \
|
||||
virtual void Visit##CLASS(CLASS *Node);
|
||||
#include "clang/AST/StmtNodes.def"
|
||||
};
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Stmt printing methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void StmtPrinter::VisitStmt(Stmt *Node) {
|
||||
Indent() << "<<unknown stmt type>>\n";
|
||||
}
|
||||
|
||||
/// PrintRawCompoundStmt - Print a compound stmt without indenting the {, and
|
||||
/// with no newline after the }.
|
||||
void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) {
|
||||
OS << "{\n";
|
||||
for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end();
|
||||
I != E; ++I)
|
||||
PrintStmt(*I);
|
||||
|
||||
Indent() << "}";
|
||||
}
|
||||
|
||||
void StmtPrinter::PrintRawDecl(Decl *D) {
|
||||
// FIXME: Need to complete/beautify this... this code simply shows the
|
||||
// nodes are where they need to be.
|
||||
if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
|
||||
OS << "typedef " << localType->getUnderlyingType().getAsString();
|
||||
OS << " " << localType->getName();
|
||||
} else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
|
||||
// Emit storage class for vardecls.
|
||||
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
|
||||
switch (V->getStorageClass()) {
|
||||
default: assert(0 && "Unknown storage class!");
|
||||
case VarDecl::None: break;
|
||||
case VarDecl::Extern: OS << "extern "; break;
|
||||
case VarDecl::Static: OS << "static "; break;
|
||||
case VarDecl::Auto: OS << "auto "; break;
|
||||
case VarDecl::Register: OS << "register "; break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Name = VD->getName();
|
||||
VD->getType().getAsStringInternal(Name);
|
||||
OS << Name;
|
||||
|
||||
// FIXME: Initializer for vardecl
|
||||
} else {
|
||||
// FIXME: "struct x;"
|
||||
assert(0 && "Unexpected decl");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void StmtPrinter::VisitNullStmt(NullStmt *Node) {
|
||||
Indent() << ";\n";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitDeclStmt(DeclStmt *Node) {
|
||||
for (Decl *D = Node->getDecl(); D; D = D->getNextDeclarator()) {
|
||||
Indent();
|
||||
PrintRawDecl(D);
|
||||
OS << ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) {
|
||||
Indent();
|
||||
PrintRawCompoundStmt(Node);
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCaseStmt(CaseStmt *Node) {
|
||||
Indent(-1) << "case ";
|
||||
PrintExpr(Node->getLHS());
|
||||
if (Node->getRHS()) {
|
||||
OS << " ... ";
|
||||
PrintExpr(Node->getRHS());
|
||||
}
|
||||
OS << ":\n";
|
||||
|
||||
PrintStmt(Node->getSubStmt(), 0);
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitDefaultStmt(DefaultStmt *Node) {
|
||||
Indent(-1) << "default:\n";
|
||||
PrintStmt(Node->getSubStmt(), 0);
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitLabelStmt(LabelStmt *Node) {
|
||||
Indent(-1) << Node->getName() << ":\n";
|
||||
PrintStmt(Node->getSubStmt(), 0);
|
||||
}
|
||||
|
||||
void StmtPrinter::PrintRawIfStmt(IfStmt *If) {
|
||||
OS << "if ";
|
||||
PrintExpr(If->getCond());
|
||||
|
||||
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) {
|
||||
OS << ' ';
|
||||
PrintRawCompoundStmt(CS);
|
||||
OS << (If->getElse() ? ' ' : '\n');
|
||||
} else {
|
||||
OS << '\n';
|
||||
PrintStmt(If->getThen());
|
||||
if (If->getElse()) Indent();
|
||||
}
|
||||
|
||||
if (Stmt *Else = If->getElse()) {
|
||||
OS << "else";
|
||||
|
||||
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Else)) {
|
||||
OS << ' ';
|
||||
PrintRawCompoundStmt(CS);
|
||||
OS << '\n';
|
||||
} else if (IfStmt *ElseIf = dyn_cast<IfStmt>(Else)) {
|
||||
OS << ' ';
|
||||
PrintRawIfStmt(ElseIf);
|
||||
} else {
|
||||
OS << '\n';
|
||||
PrintStmt(If->getElse());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitIfStmt(IfStmt *If) {
|
||||
Indent();
|
||||
PrintRawIfStmt(If);
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) {
|
||||
Indent() << "switch (";
|
||||
PrintExpr(Node->getCond());
|
||||
OS << ")";
|
||||
|
||||
// Pretty print compoundstmt bodies (very common).
|
||||
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
|
||||
OS << " ";
|
||||
PrintRawCompoundStmt(CS);
|
||||
OS << "\n";
|
||||
} else {
|
||||
OS << "\n";
|
||||
PrintStmt(Node->getBody());
|
||||
}
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitWhileStmt(WhileStmt *Node) {
|
||||
Indent() << "while (";
|
||||
PrintExpr(Node->getCond());
|
||||
OS << ")\n";
|
||||
PrintStmt(Node->getBody());
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitDoStmt(DoStmt *Node) {
|
||||
Indent() << "do\n";
|
||||
PrintStmt(Node->getBody());
|
||||
Indent() << "while ";
|
||||
PrintExpr(Node->getCond());
|
||||
OS << ";\n";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitForStmt(ForStmt *Node) {
|
||||
Indent() << "for (";
|
||||
if (Node->getInit()) {
|
||||
if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getInit()))
|
||||
PrintRawDecl(DS->getDecl());
|
||||
else
|
||||
PrintExpr(cast<Expr>(Node->getInit()));
|
||||
}
|
||||
OS << "; ";
|
||||
if (Node->getCond())
|
||||
PrintExpr(Node->getCond());
|
||||
OS << "; ";
|
||||
if (Node->getInc())
|
||||
PrintExpr(Node->getInc());
|
||||
OS << ")\n";
|
||||
PrintStmt(Node->getBody());
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitGotoStmt(GotoStmt *Node) {
|
||||
Indent() << "goto " << Node->getLabel()->getName() << ";\n";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitIndirectGotoStmt(IndirectGotoStmt *Node) {
|
||||
Indent() << "goto *";
|
||||
PrintExpr(Node->getTarget());
|
||||
OS << ";\n";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) {
|
||||
Indent() << "continue;\n";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitBreakStmt(BreakStmt *Node) {
|
||||
Indent() << "break;\n";
|
||||
}
|
||||
|
||||
|
||||
void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) {
|
||||
Indent() << "return";
|
||||
if (Node->getRetValue()) {
|
||||
OS << " ";
|
||||
PrintExpr(Node->getRetValue());
|
||||
}
|
||||
OS << ";\n";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Expr printing methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void StmtPrinter::VisitExpr(Expr *Node) {
|
||||
OS << "<<unknown expr type>>";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
|
||||
OS << Node->getDecl()->getName();
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
|
||||
// FIXME: print value.
|
||||
OS << "x";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
|
||||
bool isSigned = Node->getType()->isSignedIntegerType();
|
||||
OS << Node->getValue().toString(10, isSigned);
|
||||
|
||||
// Emit suffixes. Integer literals are always a builtin integer type.
|
||||
switch (cast<BuiltinType>(Node->getType().getCanonicalType())->getKind()) {
|
||||
default: assert(0 && "Unexpected type for integer literal!");
|
||||
case BuiltinType::Int: break; // no suffix.
|
||||
case BuiltinType::UInt: OS << 'U'; break;
|
||||
case BuiltinType::Long: OS << 'L'; break;
|
||||
case BuiltinType::ULong: OS << "UL"; break;
|
||||
case BuiltinType::LongLong: OS << "LL"; break;
|
||||
case BuiltinType::ULongLong: OS << "ULL"; break;
|
||||
}
|
||||
}
|
||||
void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) {
|
||||
// FIXME: print value.
|
||||
OS << "~1.0~";
|
||||
}
|
||||
void StmtPrinter::VisitStringLiteral(StringLiteral *Str) {
|
||||
if (Str->isWide()) OS << 'L';
|
||||
OS << '"';
|
||||
|
||||
// FIXME: this doesn't print wstrings right.
|
||||
for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) {
|
||||
switch (Str->getStrData()[i]) {
|
||||
default: OS << Str->getStrData()[i]; break;
|
||||
// Handle some common ones to make dumps prettier.
|
||||
case '\\': OS << "\\\\"; break;
|
||||
case '"': OS << "\\\""; break;
|
||||
case '\n': OS << "\\n"; break;
|
||||
case '\t': OS << "\\t"; break;
|
||||
case '\a': OS << "\\a"; break;
|
||||
case '\b': OS << "\\b"; break;
|
||||
}
|
||||
}
|
||||
OS << '"';
|
||||
}
|
||||
void StmtPrinter::VisitParenExpr(ParenExpr *Node) {
|
||||
OS << "(";
|
||||
PrintExpr(Node->getSubExpr());
|
||||
OS << ")";
|
||||
}
|
||||
void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) {
|
||||
if (!Node->isPostfix())
|
||||
OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
|
||||
PrintExpr(Node->getSubExpr());
|
||||
|
||||
if (Node->isPostfix())
|
||||
OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
|
||||
|
||||
}
|
||||
void StmtPrinter::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) {
|
||||
OS << (Node->isSizeOf() ? "sizeof(" : "__alignof(");
|
||||
OS << Node->getArgumentType().getAsString() << ")";
|
||||
}
|
||||
void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
|
||||
PrintExpr(Node->getBase());
|
||||
OS << "[";
|
||||
PrintExpr(Node->getIdx());
|
||||
OS << "]";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCallExpr(CallExpr *Call) {
|
||||
PrintExpr(Call->getCallee());
|
||||
OS << "(";
|
||||
for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) {
|
||||
if (i) OS << ", ";
|
||||
PrintExpr(Call->getArg(i));
|
||||
}
|
||||
OS << ")";
|
||||
}
|
||||
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
|
||||
PrintExpr(Node->getBase());
|
||||
OS << (Node->isArrow() ? "->" : ".");
|
||||
|
||||
FieldDecl *Field = Node->getMemberDecl();
|
||||
assert(Field && "MemberExpr should alway reference a field!");
|
||||
OS << Field->getName();
|
||||
}
|
||||
void StmtPrinter::VisitCastExpr(CastExpr *Node) {
|
||||
OS << "(" << Node->getDestType().getAsString() << ")";
|
||||
PrintExpr(Node->getSubExpr());
|
||||
}
|
||||
void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) {
|
||||
PrintExpr(Node->getLHS());
|
||||
OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
|
||||
PrintExpr(Node->getRHS());
|
||||
}
|
||||
void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) {
|
||||
PrintExpr(Node->getCond());
|
||||
OS << " ? ";
|
||||
PrintExpr(Node->getLHS());
|
||||
OS << " : ";
|
||||
PrintExpr(Node->getRHS());
|
||||
}
|
||||
|
||||
// GNU extensions.
|
||||
|
||||
void StmtPrinter::VisitAddrLabel(AddrLabel *Node) {
|
||||
OS << "&&" << Node->getLabel()->getName();
|
||||
|
||||
}
|
||||
|
||||
// C++
|
||||
|
||||
void StmtPrinter::VisitCXXCastExpr(CXXCastExpr *Node) {
|
||||
switch (Node->getOpcode()) {
|
||||
default:
|
||||
assert(0 && "Not a C++ cast expression");
|
||||
abort();
|
||||
case CXXCastExpr::ConstCast: OS << "const_cast<"; break;
|
||||
case CXXCastExpr::DynamicCast: OS << "dynamic_cast<"; break;
|
||||
case CXXCastExpr::ReinterpretCast: OS << "reinterpret_cast<"; break;
|
||||
case CXXCastExpr::StaticCast: OS << "static_cast<"; break;
|
||||
}
|
||||
|
||||
OS << Node->getDestType().getAsString() << ">(";
|
||||
PrintExpr(Node->getSubExpr());
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
|
||||
OS << (Node->getValue() ? "true" : "false");
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Stmt method implementations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void Stmt::dump() const {
|
||||
// FIXME: eliminate use of <iostream>
|
||||
print(std::cerr);
|
||||
}
|
||||
|
||||
void Stmt::print(std::ostream &OS) const {
|
||||
if (this == 0) {
|
||||
OS << "<NULL>";
|
||||
return;
|
||||
}
|
||||
|
||||
StmtPrinter P(OS);
|
||||
const_cast<Stmt*>(this)->visit(P);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
//===--- StmtVisitor.cpp - Visitor for Stmt subclasses --------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Chris Lattner and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the StmtVisitor class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
using namespace clang;
|
||||
|
||||
StmtVisitor::~StmtVisitor() {
|
||||
// Out-of-line virtual dtor.
|
||||
}
|
||||
|
||||
// Implement all of the delegation visitor methods.
|
||||
#define STMT(N, FROM, TO) \
|
||||
void StmtVisitor::Visit##FROM(FROM *Node) { Visit##TO(Node); }
|
||||
#include "clang/AST/StmtNodes.def"
|
||||
|
|
@ -0,0 +1,593 @@
|
|||
//===--- Type.cpp - Type representation and manipulation ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Chris Lattner and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements type-related functionality.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Lex/IdentifierTable.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
using namespace clang;
|
||||
|
||||
Type::~Type() {}
|
||||
|
||||
/// isVoidType - Helper method to determine if this is the 'void' type.
|
||||
bool Type::isVoidType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() == BuiltinType::Void;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isObjectType() const {
|
||||
if (isa<FunctionType>(CanonicalType))
|
||||
return false;
|
||||
else if (CanonicalType->isIncompleteType())
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Type::isDerivedType() const {
|
||||
switch (CanonicalType->getTypeClass()) {
|
||||
case Pointer:
|
||||
case Array:
|
||||
case FunctionProto:
|
||||
case FunctionNoProto:
|
||||
case Reference:
|
||||
return true;
|
||||
case Tagged: {
|
||||
const TagType *TT = cast<TagType>(CanonicalType);
|
||||
const Decl::Kind Kind = TT->getDecl()->getKind();
|
||||
return Kind == Decl::Struct || Kind == Decl::Union;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Type::isFunctionType() const {
|
||||
return isa<FunctionType>(CanonicalType);
|
||||
}
|
||||
|
||||
bool Type::isPointerType() const {
|
||||
return isa<PointerType>(CanonicalType);
|
||||
}
|
||||
|
||||
bool Type::isReferenceType() const {
|
||||
return isa<ReferenceType>(CanonicalType);
|
||||
}
|
||||
|
||||
bool Type::isArrayType() const {
|
||||
return isa<ArrayType>(CanonicalType);
|
||||
}
|
||||
|
||||
bool Type::isStructureType() const {
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
|
||||
if (TT->getDecl()->getKind() == Decl::Struct)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isUnionType() const {
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
|
||||
if (TT->getDecl()->getKind() == Decl::Union)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// C99 6.2.7p1: If both are complete types, then the following additional
|
||||
// requirements apply...FIXME (handle compatibility across source files).
|
||||
bool Type::tagTypesAreCompatible(QualType lhs, QualType rhs) {
|
||||
TagDecl *ldecl = cast<TagType>(lhs.getCanonicalType())->getDecl();
|
||||
TagDecl *rdecl = cast<TagType>(rhs.getCanonicalType())->getDecl();
|
||||
|
||||
if (ldecl->getKind() == Decl::Struct && rdecl->getKind() == Decl::Struct) {
|
||||
if (ldecl->getIdentifier() == rdecl->getIdentifier())
|
||||
return true;
|
||||
}
|
||||
if (ldecl->getKind() == Decl::Union && rdecl->getKind() == Decl::Union) {
|
||||
if (ldecl->getIdentifier() == rdecl->getIdentifier())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::pointerTypesAreCompatible(QualType lhs, QualType rhs) {
|
||||
// C99 6.7.5.1p2: For two pointer types to be compatible, both shall be
|
||||
// identically qualified and both shall be pointers to compatible types.
|
||||
if (lhs.getQualifiers() != rhs.getQualifiers())
|
||||
return false;
|
||||
|
||||
QualType ltype = cast<PointerType>(lhs.getCanonicalType())->getPointeeType();
|
||||
QualType rtype = cast<PointerType>(rhs.getCanonicalType())->getPointeeType();
|
||||
|
||||
return typesAreCompatible(ltype, rtype);
|
||||
}
|
||||
|
||||
// C++ 5.17p6: When the left opperand of an assignment operator denotes a
|
||||
// reference to T, the operation assigns to the object of type T denoted by the
|
||||
// reference.
|
||||
bool Type::referenceTypesAreCompatible(QualType lhs, QualType rhs) {
|
||||
QualType ltype = lhs;
|
||||
|
||||
if (lhs->isReferenceType())
|
||||
ltype = cast<ReferenceType>(lhs.getCanonicalType())->getReferenceeType();
|
||||
|
||||
QualType rtype = rhs;
|
||||
|
||||
if (rhs->isReferenceType())
|
||||
rtype = cast<ReferenceType>(rhs.getCanonicalType())->getReferenceeType();
|
||||
|
||||
return typesAreCompatible(ltype, rtype);
|
||||
}
|
||||
|
||||
bool Type::functionTypesAreCompatible(QualType lhs, QualType rhs) {
|
||||
const FunctionType *lbase = cast<FunctionType>(lhs.getCanonicalType());
|
||||
const FunctionType *rbase = cast<FunctionType>(rhs.getCanonicalType());
|
||||
const FunctionTypeProto *lproto = dyn_cast<FunctionTypeProto>(lbase);
|
||||
const FunctionTypeProto *rproto = dyn_cast<FunctionTypeProto>(rbase);
|
||||
|
||||
// first check the return types (common between C99 and K&R).
|
||||
if (!typesAreCompatible(lbase->getResultType(), rbase->getResultType()))
|
||||
return false;
|
||||
|
||||
if (lproto && rproto) { // two C99 style function prototypes
|
||||
unsigned lproto_nargs = lproto->getNumArgs();
|
||||
unsigned rproto_nargs = rproto->getNumArgs();
|
||||
|
||||
if (lproto_nargs != rproto_nargs)
|
||||
return false;
|
||||
|
||||
// both prototypes have the same number of arguments.
|
||||
if ((lproto->isVariadic() && !rproto->isVariadic()) ||
|
||||
(rproto->isVariadic() && !lproto->isVariadic()))
|
||||
return false;
|
||||
|
||||
// The use of ellipsis agree...now check the argument types.
|
||||
for (unsigned i = 0; i < lproto_nargs; i++)
|
||||
if (!typesAreCompatible(lproto->getArgType(i), rproto->getArgType(i)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
if (!lproto && !rproto) // two K&R style function decls, nothing to do.
|
||||
return true;
|
||||
|
||||
// we have a mixture of K&R style with C99 prototypes
|
||||
const FunctionTypeProto *proto = lproto ? lproto : rproto;
|
||||
|
||||
if (proto->isVariadic())
|
||||
return false;
|
||||
|
||||
// FIXME: Each parameter type T in the prototype must be compatible with the
|
||||
// type resulting from applying the usual argument conversions to T.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Type::arrayTypesAreCompatible(QualType lhs, QualType rhs) {
|
||||
QualType ltype = cast<ArrayType>(lhs.getCanonicalType())->getElementType();
|
||||
QualType rtype = cast<ArrayType>(rhs.getCanonicalType())->getElementType();
|
||||
|
||||
if (!typesAreCompatible(ltype, rtype))
|
||||
return false;
|
||||
|
||||
// FIXME: If both types specify constant sizes, then the sizes must also be
|
||||
// the same. Even if the sizes are the same, GCC produces an error.
|
||||
return true;
|
||||
}
|
||||
|
||||
/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible,
|
||||
/// both shall have the identically qualified version of a compatible type.
|
||||
/// C99 6.2.7p1: Two types have compatible types if their types are the
|
||||
/// same. See 6.7.[2,3,5] for additional rules.
|
||||
bool Type::typesAreCompatible(QualType lhs, QualType rhs) {
|
||||
QualType lcanon = lhs.getCanonicalType();
|
||||
QualType rcanon = rhs.getCanonicalType();
|
||||
|
||||
// If two types are identical, they are are compatible
|
||||
if (lcanon == rcanon)
|
||||
return true;
|
||||
|
||||
// If the canonical type classes don't match, they can't be compatible
|
||||
if (lcanon->getTypeClass() != rcanon->getTypeClass())
|
||||
return false;
|
||||
|
||||
switch (lcanon->getTypeClass()) {
|
||||
case Type::Pointer:
|
||||
return pointerTypesAreCompatible(lcanon, rcanon);
|
||||
case Type::Reference:
|
||||
return referenceTypesAreCompatible(lcanon, rcanon);
|
||||
case Type::Array:
|
||||
return arrayTypesAreCompatible(lcanon, rcanon);
|
||||
case Type::FunctionNoProto:
|
||||
case Type::FunctionProto:
|
||||
return functionTypesAreCompatible(lcanon, rcanon);
|
||||
case Type::Tagged: // handle structures, unions
|
||||
return tagTypesAreCompatible(lcanon, rcanon);
|
||||
case Type::Builtin:
|
||||
return false;
|
||||
default:
|
||||
assert(0 && "unexpected type");
|
||||
}
|
||||
return true; // should never get here...
|
||||
}
|
||||
|
||||
bool Type::isIntegerType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() >= BuiltinType::Bool &&
|
||||
BT->getKind() <= BuiltinType::LongLong;
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
|
||||
if (TT->getDecl()->getKind() == Decl::Enum)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isSignedIntegerType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
|
||||
return BT->getKind() >= BuiltinType::Char_S &&
|
||||
BT->getKind() <= BuiltinType::LongLong;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isUnsignedIntegerType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
|
||||
return BT->getKind() >= BuiltinType::Bool &&
|
||||
BT->getKind() <= BuiltinType::ULongLong;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isFloatingType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() >= BuiltinType::Float &&
|
||||
BT->getKind() <= BuiltinType::LongDouble;
|
||||
if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType))
|
||||
return CT->isFloatingType();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isRealFloatingType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() >= BuiltinType::Float &&
|
||||
BT->getKind() <= BuiltinType::LongDouble;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isRealType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() >= BuiltinType::Bool &&
|
||||
BT->getKind() <= BuiltinType::LongDouble;
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
|
||||
return TT->getDecl()->getKind() == Decl::Enum;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isComplexType() const {
|
||||
return isa<ComplexType>(CanonicalType);
|
||||
}
|
||||
|
||||
bool Type::isVectorType() const {
|
||||
return isa<VectorType>(CanonicalType);
|
||||
}
|
||||
|
||||
bool Type::isArithmeticType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() != BuiltinType::Void;
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
|
||||
if (TT->getDecl()->getKind() == Decl::Enum)
|
||||
return true;
|
||||
return isa<ComplexType>(CanonicalType) || isa<VectorType>(CanonicalType);
|
||||
}
|
||||
|
||||
bool Type::isScalarType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() != BuiltinType::Void;
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
|
||||
if (TT->getDecl()->getKind() == Decl::Enum)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return isa<PointerType>(CanonicalType) || isa<ComplexType>(CanonicalType);
|
||||
}
|
||||
|
||||
bool Type::isAggregateType() const {
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
|
||||
if (TT->getDecl()->getKind() == Decl::Struct)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return CanonicalType->getTypeClass() == Array;
|
||||
}
|
||||
|
||||
// The only variable size types are auto arrays within a function. Structures
|
||||
// cannot contain a VLA member. They can have a flexible array member, however
|
||||
// the structure is still constant size (C99 6.7.2.1p16).
|
||||
bool Type::isConstantSizeType(SourceLocation *loc) const {
|
||||
if (const ArrayType *Ary = dyn_cast<ArrayType>(CanonicalType)) {
|
||||
assert(Ary->getSize() && "Incomplete types don't have a size at all!");
|
||||
return Ary->getSize()->isIntegerConstantExpr(loc); // Variable Length Array?
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1)
|
||||
/// - a type that can describe objects, but which lacks information needed to
|
||||
/// determine its size.
|
||||
bool Type::isIncompleteType() const {
|
||||
switch (CanonicalType->getTypeClass()) {
|
||||
default: return false;
|
||||
case Builtin:
|
||||
// Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never
|
||||
// be completed.
|
||||
return isVoidType();
|
||||
case Tagged:
|
||||
// A tagged type (struct/union/enum/class) is incomplete if the decl is a
|
||||
// forward declaration, but not a full definition (C99 6.2.5p22).
|
||||
return !cast<TagType>(CanonicalType)->getDecl()->isDefinition();
|
||||
case Array:
|
||||
// An array of unknown size is an incomplete type (C99 6.2.5p22).
|
||||
return cast<ArrayType>(CanonicalType)->getSize() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Type::isPromotableIntegerType() const {
|
||||
const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType);
|
||||
if (!BT) return false;
|
||||
switch (BT->getKind()) {
|
||||
case BuiltinType::Bool:
|
||||
case BuiltinType::Char_S:
|
||||
case BuiltinType::Char_U:
|
||||
case BuiltinType::SChar:
|
||||
case BuiltinType::UChar:
|
||||
case BuiltinType::Short:
|
||||
case BuiltinType::UShort:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const char *BuiltinType::getName() const {
|
||||
switch (getKind()) {
|
||||
default: assert(0 && "Unknown builtin type!");
|
||||
case Void: return "void";
|
||||
case Bool: return "_Bool";
|
||||
case Char_S: return "char";
|
||||
case Char_U: return "char";
|
||||
case SChar: return "signed char";
|
||||
case Short: return "short";
|
||||
case Int: return "int";
|
||||
case Long: return "long";
|
||||
case LongLong: return "long long";
|
||||
case UChar: return "unsigned char";
|
||||
case UShort: return "unsigned short";
|
||||
case UInt: return "unsigned int";
|
||||
case ULong: return "unsigned long";
|
||||
case ULongLong: return "unsigned long long";
|
||||
case Float: return "float";
|
||||
case Double: return "double";
|
||||
case LongDouble: return "long double";
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: need to use TargetInfo to derive the target specific sizes. This
|
||||
// implementation will suffice for play with vector support.
|
||||
unsigned BuiltinType::getSize() const {
|
||||
switch (getKind()) {
|
||||
default: assert(0 && "Unknown builtin type!");
|
||||
case Void: return 0;
|
||||
case Bool:
|
||||
case Char_S:
|
||||
case Char_U: return sizeof(char) * 8;
|
||||
case SChar: return sizeof(signed char) * 8;
|
||||
case Short: return sizeof(short) * 8;
|
||||
case Int: return sizeof(int) * 8;
|
||||
case Long: return sizeof(long) * 8;
|
||||
case LongLong: return sizeof(long long) * 8;
|
||||
case UChar: return sizeof(unsigned char) * 8;
|
||||
case UShort: return sizeof(unsigned short) * 8;
|
||||
case UInt: return sizeof(unsigned int) * 8;
|
||||
case ULong: return sizeof(unsigned long) * 8;
|
||||
case ULongLong: return sizeof(unsigned long long) * 8;
|
||||
case Float: return sizeof(float) * 8;
|
||||
case Double: return sizeof(double) * 8;
|
||||
case LongDouble: return sizeof(long double) * 8;
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
|
||||
QualType* ArgTys,
|
||||
unsigned NumArgs, bool isVariadic) {
|
||||
ID.AddPointer(Result.getAsOpaquePtr());
|
||||
for (unsigned i = 0; i != NumArgs; ++i)
|
||||
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
|
||||
ID.AddInteger(isVariadic);
|
||||
}
|
||||
|
||||
void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getResultType(), ArgInfo, NumArgs, isVariadic());
|
||||
}
|
||||
|
||||
|
||||
bool RecordType::classof(const Type *T) {
|
||||
if (const TagType *TT = dyn_cast<TagType>(T))
|
||||
return isa<RecordDecl>(TT->getDecl());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Type Printing
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void QualType::dump(const char *msg) const {
|
||||
std::string R = "foo";
|
||||
getAsStringInternal(R);
|
||||
if (msg)
|
||||
fprintf(stderr, "%s: %s\n", msg, R.c_str());
|
||||
else
|
||||
fprintf(stderr, "%s\n", R.c_str());
|
||||
}
|
||||
|
||||
static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
|
||||
// Note: funkiness to ensure we get a space only between quals.
|
||||
bool NonePrinted = true;
|
||||
if (TypeQuals & QualType::Const)
|
||||
S += "const", NonePrinted = false;
|
||||
if (TypeQuals & QualType::Volatile)
|
||||
S += (NonePrinted+" volatile"), NonePrinted = false;
|
||||
if (TypeQuals & QualType::Restrict)
|
||||
S += (NonePrinted+" restrict"), NonePrinted = false;
|
||||
}
|
||||
|
||||
void QualType::getAsStringInternal(std::string &S) const {
|
||||
if (isNull()) {
|
||||
S += "NULL TYPE\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Print qualifiers as appropriate.
|
||||
if (unsigned TQ = getQualifiers()) {
|
||||
std::string TQS;
|
||||
AppendTypeQualList(TQS, TQ);
|
||||
if (!S.empty())
|
||||
S = TQS + ' ' + S;
|
||||
else
|
||||
S = TQS;
|
||||
}
|
||||
|
||||
getTypePtr()->getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void BuiltinType::getAsStringInternal(std::string &S) const {
|
||||
if (S.empty()) {
|
||||
S = getName();
|
||||
} else {
|
||||
// Prefix the basic type, e.g. 'int X'.
|
||||
S = ' ' + S;
|
||||
S = getName() + S;
|
||||
}
|
||||
}
|
||||
|
||||
void ComplexType::getAsStringInternal(std::string &S) const {
|
||||
ElementType->getAsStringInternal(S);
|
||||
S = "_Complex " + S;
|
||||
}
|
||||
|
||||
void PointerType::getAsStringInternal(std::string &S) const {
|
||||
S = '*' + S;
|
||||
|
||||
// Handle things like 'int (*A)[4];' correctly.
|
||||
// FIXME: this should include vectors, but vectors use attributes I guess.
|
||||
if (isa<ArrayType>(PointeeType.getTypePtr()))
|
||||
S = '(' + S + ')';
|
||||
|
||||
PointeeType.getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void ReferenceType::getAsStringInternal(std::string &S) const {
|
||||
S = '&' + S;
|
||||
|
||||
// Handle things like 'int (&A)[4];' correctly.
|
||||
// FIXME: this should include vectors, but vectors use attributes I guess.
|
||||
if (isa<ArrayType>(ReferenceeType.getTypePtr()))
|
||||
S = '(' + S + ')';
|
||||
|
||||
ReferenceeType.getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void ArrayType::getAsStringInternal(std::string &S) const {
|
||||
S += '[';
|
||||
|
||||
if (IndexTypeQuals) {
|
||||
AppendTypeQualList(S, IndexTypeQuals);
|
||||
S += ' ';
|
||||
}
|
||||
|
||||
if (SizeModifier == Static)
|
||||
S += "static";
|
||||
else if (SizeModifier == Star)
|
||||
S += '*';
|
||||
|
||||
S += ']';
|
||||
|
||||
ElementType.getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void VectorType::getAsStringInternal(std::string &S) const {
|
||||
S += " __attribute__(( vector_size(";
|
||||
// FIXME: handle types that are != 32 bits.
|
||||
S += llvm::utostr_32(NumElements*4); // convert back to bytes.
|
||||
S += ") ))";
|
||||
ElementType.getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void FunctionTypeNoProto::getAsStringInternal(std::string &S) const {
|
||||
// If needed for precedence reasons, wrap the inner part in grouping parens.
|
||||
if (!S.empty())
|
||||
S = "(" + S + ")";
|
||||
|
||||
S += "()";
|
||||
getResultType().getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void FunctionTypeProto::getAsStringInternal(std::string &S) const {
|
||||
// If needed for precedence reasons, wrap the inner part in grouping parens.
|
||||
if (!S.empty())
|
||||
S = "(" + S + ")";
|
||||
|
||||
S += "(";
|
||||
std::string Tmp;
|
||||
for (unsigned i = 0, e = getNumArgs(); i != e; ++i) {
|
||||
if (i) S += ", ";
|
||||
getArgType(i).getAsStringInternal(Tmp);
|
||||
S += Tmp;
|
||||
Tmp.clear();
|
||||
}
|
||||
|
||||
if (isVariadic()) {
|
||||
if (getNumArgs())
|
||||
S += ", ";
|
||||
S += "...";
|
||||
} else if (getNumArgs() == 0) {
|
||||
// Do not emit int() if we have a proto, emit 'int(void)'.
|
||||
S += "void";
|
||||
}
|
||||
|
||||
S += ")";
|
||||
getResultType().getAsStringInternal(S);
|
||||
}
|
||||
|
||||
|
||||
void TypedefType::getAsStringInternal(std::string &InnerString) const {
|
||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
||||
InnerString = ' ' + InnerString;
|
||||
InnerString = getDecl()->getIdentifier()->getName() + InnerString;
|
||||
}
|
||||
|
||||
void TagType::getAsStringInternal(std::string &InnerString) const {
|
||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
||||
InnerString = ' ' + InnerString;
|
||||
|
||||
const char *Kind = getDecl()->getKindName();
|
||||
const char *ID;
|
||||
if (const IdentifierInfo *II = getDecl()->getIdentifier())
|
||||
ID = II->getName();
|
||||
else
|
||||
ID = "<anonymous>";
|
||||
|
||||
InnerString = std::string(Kind) + " " + ID + InnerString;
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
//===--- 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,
|
||||
FATAL = 0x05,
|
||||
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;
|
||||
case FATAL: return Diagnostic::Fatal;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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() {}
|
|
@ -0,0 +1,169 @@
|
|||
//===--- 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>
|
||||
|
||||
|
||||
/// 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;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
##===- 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
|
||||
|
|
@ -0,0 +1,370 @@
|
|||
//===--- 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/Support/MemoryBuffer.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
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>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/fcntl.h>
|
||||
#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());
|
||||
|
||||
int FD = ::open(FileEnt->getName(), O_RDONLY);
|
||||
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::getNormalBuffer(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::getNormalBuffer(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) {
|
||||
assert(getFIDInfo(PhysLoc.getFileID())->IDType !=
|
||||
SrcMgr::FileIDInfo::MacroExpansion &&
|
||||
"Location instantiated in a macro?");
|
||||
|
||||
// Resolve InstantLoc down to a real logical location.
|
||||
InstantLoc = getLogicalLoc(InstantLoc);
|
||||
|
||||
unsigned InstantiationFileID;
|
||||
// If this is the same instantiation as was requested last time, return this
|
||||
// immediately.
|
||||
if (PhysLoc.getFileID() == LastInstantiationLoc_MacroFID &&
|
||||
InstantLoc == LastInstantiationLoc_InstantLoc) {
|
||||
InstantiationFileID = LastInstantiationLoc_Result;
|
||||
} else {
|
||||
// Add a FileID for this. FIXME: should cache these!
|
||||
FileIDs.push_back(FileIDInfo::getMacroExpansion(InstantLoc,
|
||||
PhysLoc.getFileID()));
|
||||
InstantiationFileID = FileIDs.size();
|
||||
|
||||
// Remember this in the single-entry cache for next time.
|
||||
LastInstantiationLoc_MacroFID = PhysLoc.getFileID();
|
||||
LastInstantiationLoc_InstantLoc = InstantLoc;
|
||||
LastInstantiationLoc_Result = InstantiationFileID;
|
||||
}
|
||||
return SourceLocation(InstantiationFileID, PhysLoc.getRawFilePos());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// 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.
|
||||
unsigned FileID = SL.getFileID();
|
||||
assert(FileID && "Invalid source location!");
|
||||
|
||||
return getFileInfo(FileID)->Buffer->getBufferStart() + getFilePos(SL);
|
||||
}
|
||||
|
||||
/// getIncludeLoc - Return the location of the #include for the specified
|
||||
/// FileID.
|
||||
SourceLocation SourceManager::getIncludeLoc(unsigned FileID) const {
|
||||
const SrcMgr::FileIDInfo *FIDInfo = getFIDInfo(FileID);
|
||||
|
||||
// For Macros, the physical loc is specified by the MacroTokenFileID.
|
||||
if (FIDInfo->IDType == SrcMgr::FileIDInfo::MacroExpansion)
|
||||
FIDInfo = &FileIDs[FIDInfo->u.MacroTokenFileID-1];
|
||||
|
||||
return FIDInfo->IncludeLoc;
|
||||
}
|
||||
|
||||
|
||||
/// getColumnNumber - Return the column # for the specified include 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 {
|
||||
Loc = getLogicalLoc(Loc);
|
||||
unsigned FileID = Loc.getFileID();
|
||||
if (FileID == 0) return 0;
|
||||
|
||||
unsigned FilePos = getFilePos(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.
|
||||
std::string SourceManager::getSourceName(SourceLocation Loc) {
|
||||
Loc = getLogicalLoc(Loc);
|
||||
unsigned FileID = Loc.getFileID();
|
||||
if (FileID == 0) return "";
|
||||
return getFileInfo(FileID)->Buffer->getBufferIdentifier();
|
||||
}
|
||||
|
||||
|
||||
/// 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) {
|
||||
Loc = getLogicalLoc(Loc);
|
||||
unsigned FileID = Loc.getFileID();
|
||||
if (FileID == 0) return 0;
|
||||
FileInfo *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) {
|
||||
const MemoryBuffer *Buffer = FileInfo->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.
|
||||
FileInfo->NumLines = LineOffsets.size();
|
||||
FileInfo->SourceLineCache = new unsigned[LineOffsets.size()];
|
||||
std::copy(LineOffsets.begin(), LineOffsets.end(),
|
||||
FileInfo->SourceLineCache);
|
||||
}
|
||||
|
||||
// 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 NumLines = FileInfo->NumLines;
|
||||
unsigned *SourceLineCache = FileInfo->SourceLineCache;
|
||||
|
||||
// TODO: If this is performance sensitive, we could try doing simple radix
|
||||
// type approaches to make good (tight?) initial guesses based on the
|
||||
// assumption that all lines are the same average size.
|
||||
unsigned *Pos = std::lower_bound(SourceLineCache, SourceLineCache+NumLines,
|
||||
getFilePos(Loc)+1);
|
||||
return Pos-SourceLineCache;
|
||||
}
|
||||
|
||||
/// getSourceFilePos - This method returns the *logical* offset from the start
|
||||
/// of the file that the specified SourceLocation represents. This returns
|
||||
/// the location of the *logical* character data, not the physical file
|
||||
/// position. In the case of macros, for example, this returns where the
|
||||
/// macro was instantiated, not where the characters for the macro can be
|
||||
/// found.
|
||||
unsigned SourceManager::getSourceFilePos(SourceLocation Loc) const {
|
||||
|
||||
// If this is a macro, we need to get the instantiation location.
|
||||
const SrcMgr::FileIDInfo *FIDInfo = getFIDInfo(Loc.getFileID());
|
||||
while (FIDInfo->IDType == SrcMgr::FileIDInfo::MacroExpansion) {
|
||||
Loc = FIDInfo->IncludeLoc;
|
||||
FIDInfo = getFIDInfo(Loc.getFileID());
|
||||
}
|
||||
|
||||
return getFilePos(Loc);
|
||||
}
|
||||
|
||||
|
||||
/// 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";
|
||||
unsigned NumBuffers = 0, NumMacros = 0;
|
||||
for (unsigned i = 0, e = FileIDs.size(); i != e; ++i) {
|
||||
if (FileIDs[i].IDType == FileIDInfo::NormalBuffer)
|
||||
++NumBuffers;
|
||||
else if (FileIDs[i].IDType == FileIDInfo::MacroExpansion)
|
||||
++NumMacros;
|
||||
else
|
||||
assert(0 && "Unknown FileID!");
|
||||
}
|
||||
std::cerr << " " << NumBuffers << " normal buffer FileID's, "
|
||||
<< NumMacros << " 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";
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
//===--- 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 <map>
|
||||
#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,
|
||||
std::map<std::string, std::string> &Map) {
|
||||
std::vector<std::string> PrimaryDefines;
|
||||
Target->getTargetDefines(PrimaryDefines);
|
||||
|
||||
while (!PrimaryDefines.empty()) {
|
||||
const char *Str = PrimaryDefines.back().c_str();
|
||||
if (const char *Equal = strchr(Str, '=')) {
|
||||
// Split at the '='.
|
||||
Map.insert(std::make_pair(std::string(Str, Equal),
|
||||
std::string(Equal+1,
|
||||
Str+PrimaryDefines.back().size())));
|
||||
} else {
|
||||
// Remember "macroname=1".
|
||||
Map.insert(std::make_pair(PrimaryDefines.back(), std::string("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.
|
||||
std::map<std::string, std::string> PrimaryDefines;
|
||||
GetTargetDefineMap(PrimaryTarget, PrimaryDefines);
|
||||
|
||||
// If we have no secondary targets, be a bit more efficient.
|
||||
if (SecondaryTargets.empty()) {
|
||||
for (std::map<std::string, 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".
|
||||
Buffer.insert(Buffer.end(), I->first.begin(), I->first.end());
|
||||
Buffer.push_back(' ');
|
||||
Buffer.insert(Buffer.end(), I->second.begin(), I->second.end());
|
||||
Buffer.push_back('\n');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the sets of secondary #defines.
|
||||
std::vector<std::map<std::string, std::string> > SecondaryDefines;
|
||||
SecondaryDefines.resize(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.
|
||||
while (!PrimaryDefines.empty()) {
|
||||
std::string DefineName = PrimaryDefines.begin()->first;
|
||||
std::string DefineValue = PrimaryDefines.begin()->second;
|
||||
PrimaryDefines.erase(PrimaryDefines.begin());
|
||||
|
||||
// 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 = SecondaryDefines.size(); i != e; ++i) {
|
||||
std::map<std::string, std::string>::iterator I =
|
||||
SecondaryDefines[i].find(DefineName);
|
||||
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->second == 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 = SecondaryDefines.size(); i != e; ++i) {
|
||||
std::map<std::string, std::string> &Defs = SecondaryDefines[i];
|
||||
while (!Defs.empty()) {
|
||||
const std::string &DefName = Defs.begin()->first;
|
||||
|
||||
// Insert "#define_other_target defname".
|
||||
const char *Command = "#define_other_target ";
|
||||
Buffer.insert(Buffer.end(), Command, Command+strlen(Command));
|
||||
Buffer.insert(Buffer.end(), DefName.begin(), DefName.end());
|
||||
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)
|
||||
SecondaryDefines[j].erase(DefName);
|
||||
|
||||
Defs.erase(Defs.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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::ComputeWCharWidth(SourceLocation Loc) {
|
||||
WCharWidth = PrimaryTarget->getWCharWidth();
|
||||
|
||||
// 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)
|
||||
if (SecondaryTargets[i]->getWCharWidth() != WCharWidth)
|
||||
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.
|
||||
std::map<std::string, const Builtin::Info*> PrimaryRecs;
|
||||
for (unsigned i = 0, e = NumRecords; i != e; ++i)
|
||||
PrimaryRecs[Records[i].Name] = 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.
|
||||
if (const Builtin::Info *PrimBI = PrimaryRecs[Records2nd[j].Name]) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
//===--- 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];
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
//===--- 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()) {
|
||||
// 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;
|
||||
|
||||
// FIXME: Evaluate initializer.
|
||||
}
|
||||
|
||||
/// 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()) {
|
||||
// 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;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,284 @@
|
|||
//===--- 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 and ignore the
|
||||
// result.
|
||||
if (const Expr *E = dyn_cast<Expr>(S)) {
|
||||
EmitExpr(E);
|
||||
} else {
|
||||
printf("Unimplemented stmt!\n");
|
||||
S->dump();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S) {
|
||||
// FIXME: handle vla's etc.
|
||||
|
||||
for (CompoundStmt::const_body_iterator I = S.body_begin(), E = S.body_end();
|
||||
I != E; ++I)
|
||||
EmitStmt(*I);
|
||||
}
|
||||
|
||||
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) {
|
||||
// FIXME: Handle continue/break.
|
||||
|
||||
// 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);
|
||||
|
||||
// Emit the loop body.
|
||||
EmitBlock(LoopBody);
|
||||
EmitStmt(S.getBody());
|
||||
|
||||
// Cycle to the condition.
|
||||
Builder.CreateBr(LoopHeader);
|
||||
|
||||
// Emit the exit block.
|
||||
EmitBlock(ExitBlock);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
|
||||
// FIXME: Handle continue/break.
|
||||
// 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);
|
||||
|
||||
// Emit the body of the loop into the block.
|
||||
EmitStmt(S.getBody());
|
||||
|
||||
// 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: Handle continue/break.
|
||||
// FIXME: What do we do if the increment (f.e.) contains a stmt expression,
|
||||
// which contains a continue/break?
|
||||
|
||||
// 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 = 0;
|
||||
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");
|
||||
AfterFor = new llvm::BasicBlock("afterfor");
|
||||
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 condition is true, execute the body of the for stmt.
|
||||
EmitStmt(S.getBody());
|
||||
|
||||
// If there is an increment, emit it next.
|
||||
if (S.getInc())
|
||||
EmitExpr(S.getInc());
|
||||
|
||||
// Finally, branch back up to the condition for the next iteration.
|
||||
Builder.CreateBr(CondBlock);
|
||||
|
||||
// Emit the fall-through block if there is any.
|
||||
if (AfterFor)
|
||||
EmitBlock(AfterFor);
|
||||
else
|
||||
EmitBlock(new llvm::BasicBlock());
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
RValue RetVal;
|
||||
|
||||
// Emit the result value, even if unused, to evalute the side effects.
|
||||
const Expr *RV = S.getRetValue();
|
||||
if (RV)
|
||||
RetVal = EmitExpr(RV);
|
||||
|
||||
QualType FnRetTy = CurFuncDecl->getType().getCanonicalType();
|
||||
FnRetTy = cast<FunctionType>(FnRetTy)->getResultType();
|
||||
|
||||
if (FnRetTy->isVoidType()) {
|
||||
// If the function returns void, emit ret void, and ignore the retval.
|
||||
Builder.CreateRetVoid();
|
||||
} else if (RV == 0) {
|
||||
// "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 {
|
||||
// Do implicit conversions to the returned type.
|
||||
RetVal = EmitConversion(RetVal, RV->getType(), FnRetTy);
|
||||
|
||||
if (RetVal.isScalar()) {
|
||||
Builder.CreateRet(RetVal.getVal());
|
||||
} else {
|
||||
llvm::Value *SRetPtr = CurFn->arg_begin();
|
||||
EmitStoreThroughLValue(RetVal, LValue::MakeAddr(SRetPtr), FnRetTy);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
//===--- 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();
|
||||
}
|
||||
|
||||
|
||||
void CodeGenFunction::GenerateCode(const FunctionDecl *FD) {
|
||||
LLVMIntTy = ConvertType(getContext().IntTy);
|
||||
LLVMPointerWidth = Target.getPointerWidth(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()));
|
||||
|
||||
// Verify that the function is well formed.
|
||||
assert(!verifyFunction(*CurFn));
|
||||
}
|
||||
|
|
@ -0,0 +1,354 @@
|
|||
//===--- 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/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 CastExpr;
|
||||
class CallExpr;
|
||||
class UnaryOperator;
|
||||
class BinaryOperator;
|
||||
class CompoundAssignOperator;
|
||||
class ArraySubscriptExpr;
|
||||
|
||||
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 two things: either a simple
|
||||
/// LLVM SSA value, or the address of an aggregate value in memory. These two
|
||||
/// possibilities are discriminated by isAggregate/isScalar.
|
||||
class RValue {
|
||||
llvm::Value *V;
|
||||
// TODO: Encode this into the low bit of pointer for more efficient
|
||||
// return-by-value.
|
||||
bool IsAggregate;
|
||||
|
||||
// FIXME: Aggregate rvalues need to retain information about whether they are
|
||||
// volatile or not.
|
||||
public:
|
||||
|
||||
bool isAggregate() const { return IsAggregate; }
|
||||
bool isScalar() const { return !IsAggregate; }
|
||||
|
||||
/// getVal() - Return the Value* of this scalar value.
|
||||
llvm::Value *getVal() const {
|
||||
assert(!isAggregate() && "Not a scalar!");
|
||||
return V;
|
||||
}
|
||||
|
||||
/// getAggregateAddr() - Return the Value* of the address of the aggregate.
|
||||
llvm::Value *getAggregateAddr() const {
|
||||
assert(isAggregate() && "Not an aggregate!");
|
||||
return V;
|
||||
}
|
||||
|
||||
static RValue get(llvm::Value *V) {
|
||||
RValue ER;
|
||||
ER.V = V;
|
||||
ER.IsAggregate = false;
|
||||
return ER;
|
||||
}
|
||||
static RValue getAggregate(llvm::Value *V) {
|
||||
RValue ER;
|
||||
ER.V = V;
|
||||
ER.IsAggregate = true;
|
||||
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*.
|
||||
} LVType;
|
||||
|
||||
llvm::Value *V;
|
||||
|
||||
union {
|
||||
llvm::Value *VectorIdx;
|
||||
};
|
||||
public:
|
||||
bool isSimple() const { return LVType == Simple; }
|
||||
bool isVectorElt() const { return LVType == VectorElt; }
|
||||
bool isBitfield() const { return LVType == BitField; }
|
||||
|
||||
// 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; }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// CodeGenFunction - This class organizes the per-function state that is used
|
||||
/// while generating LLVM code.
|
||||
class CodeGenFunction {
|
||||
CodeGenModule &CGM; // Per-module state.
|
||||
TargetInfo &Target;
|
||||
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;
|
||||
|
||||
/// 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;
|
||||
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);
|
||||
|
||||
|
||||
/// EmitLoadOfComplex - Given an RValue reference for a complex, emit code to
|
||||
/// load the real and imaginary pieces, returning them as Real/Imag.
|
||||
void EmitLoadOfComplex(RValue V, llvm::Value *&Real, llvm::Value *&Imag);
|
||||
|
||||
/// EmitStoreOfComplex - Store the specified real/imag parts into the
|
||||
/// specified value pointer.
|
||||
void EmitStoreOfComplex(llvm::Value *Real, llvm::Value *Imag,
|
||||
llvm::Value *ResPtr);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Conversions
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// EmitConversion - Convert the value specied by Val, whose type is ValTy, to
|
||||
/// the type specified by DstTy, following the rules of C99 6.3.
|
||||
RValue EmitConversion(RValue Val, QualType ValTy, QualType DstTy);
|
||||
|
||||
/// ConvertScalarValueToBool - Convert the specified expression value to a
|
||||
/// boolean (i1) truth value. This is equivalent to "Val == 0".
|
||||
llvm::Value *ConvertScalarValueToBool(RValue Val, QualType Ty);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// 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);
|
||||
void EmitCompoundStmt(const CompoundStmt &S);
|
||||
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);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// 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(const Expr *E);
|
||||
RValue EmitLoadOfLValue(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);
|
||||
|
||||
LValue EmitDeclRefLValue(const DeclRefExpr *E);
|
||||
LValue EmitStringLiteralLValue(const StringLiteral *E);
|
||||
LValue EmitUnaryOpLValue(const UnaryOperator *E);
|
||||
LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Expression Emission
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
RValue EmitExprWithUsualUnaryConversions(const Expr *E, QualType &ResTy);
|
||||
QualType EmitUsualArithmeticConversions(const BinaryOperator *E,
|
||||
RValue &LHS, RValue &RHS);
|
||||
void EmitShiftOperands(const BinaryOperator *E, RValue &LHS, RValue &RHS);
|
||||
|
||||
void EmitCompoundAssignmentOperands(const CompoundAssignOperator *CAO,
|
||||
LValue &LHSLV, RValue &LHS, RValue &RHS);
|
||||
RValue EmitCompoundAssignmentResult(const CompoundAssignOperator *E,
|
||||
LValue LHSLV, RValue ResV);
|
||||
|
||||
|
||||
RValue EmitExpr(const Expr *E);
|
||||
RValue EmitIntegerLiteral(const IntegerLiteral *E);
|
||||
RValue EmitFloatingLiteral(const FloatingLiteral *E);
|
||||
|
||||
RValue EmitCastExpr(const CastExpr *E);
|
||||
RValue EmitCallExpr(const CallExpr *E);
|
||||
RValue EmitArraySubscriptExprRV(const ArraySubscriptExpr *E);
|
||||
|
||||
// Unary Operators.
|
||||
RValue EmitUnaryOperator(const UnaryOperator *E);
|
||||
// FIXME: pre/post inc/dec
|
||||
RValue EmitUnaryAddrOf (const UnaryOperator *E);
|
||||
RValue EmitUnaryPlus (const UnaryOperator *E);
|
||||
RValue EmitUnaryMinus (const UnaryOperator *E);
|
||||
RValue EmitUnaryNot (const UnaryOperator *E);
|
||||
RValue EmitUnaryLNot (const UnaryOperator *E);
|
||||
// FIXME: SIZEOF/ALIGNOF(expr).
|
||||
// FIXME: real/imag
|
||||
|
||||
// Binary Operators.
|
||||
RValue EmitBinaryOperator(const BinaryOperator *E);
|
||||
RValue EmitBinaryMul(const BinaryOperator *E);
|
||||
RValue EmitBinaryDiv(const BinaryOperator *E);
|
||||
RValue EmitBinaryRem(const BinaryOperator *E);
|
||||
RValue EmitMul(RValue LHS, RValue RHS, QualType EltTy);
|
||||
RValue EmitDiv(RValue LHS, RValue RHS, QualType EltTy);
|
||||
RValue EmitRem(RValue LHS, RValue RHS, QualType EltTy);
|
||||
RValue EmitAdd(RValue LHS, RValue RHS, QualType EltTy);
|
||||
RValue EmitSub(RValue LHS, RValue RHS, QualType EltTy);
|
||||
RValue EmitShl(RValue LHS, RValue RHS, QualType ResTy);
|
||||
RValue EmitShr(RValue LHS, RValue RHS, QualType ResTy);
|
||||
RValue EmitBinaryCompare(const BinaryOperator *E, unsigned UICmpOpc,
|
||||
unsigned SICmpOpc, unsigned FCmpOpc);
|
||||
RValue EmitAnd(RValue LHS, RValue RHS, QualType EltTy);
|
||||
RValue EmitOr (RValue LHS, RValue RHS, QualType EltTy);
|
||||
RValue EmitXor(RValue LHS, RValue RHS, QualType EltTy);
|
||||
RValue EmitBinaryLAnd(const BinaryOperator *E);
|
||||
RValue EmitBinaryLOr(const BinaryOperator *E);
|
||||
|
||||
RValue EmitBinaryAssign(const BinaryOperator *E);
|
||||
RValue EmitBinaryComma(const BinaryOperator *E);
|
||||
};
|
||||
} // end namespace CodeGen
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,68 @@
|
|||
//===--- 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/DerivedTypes.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
|
||||
CodeGenModule::CodeGenModule(ASTContext &C, llvm::Module &M)
|
||||
: Context(C), TheModule(M), Types(C.Target) {}
|
||||
|
||||
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(FunctionDecl *FD) {
|
||||
// If this is not a prototype, emit the body.
|
||||
if (FD->getBody())
|
||||
CodeGenFunction(*this).GenerateCode(FD);
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Function *CodeGenModule::getMemCpyFn() {
|
||||
if (MemCpyFn) return MemCpyFn;
|
||||
llvm::Intrinsic::ID IID;
|
||||
switch (Context.Target.getPointerWidth(SourceLocation())) {
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
//===--- 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"
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
class Constant;
|
||||
class Function;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class FunctionDecl;
|
||||
class Decl;
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
llvm::Function *getMemCpyFn();
|
||||
|
||||
void EmitFunction(FunctionDecl *FD);
|
||||
|
||||
void PrintStats() {}
|
||||
};
|
||||
} // end namespace CodeGen
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,151 @@
|
|||
//===--- 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"
|
||||
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
|
||||
/// 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::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.
|
||||
case BuiltinType::Char_S:
|
||||
case BuiltinType::Char_U:
|
||||
case BuiltinType::SChar:
|
||||
case BuiltinType::UChar:
|
||||
return llvm::IntegerType::get(Target.getCharWidth(SourceLocation()));
|
||||
|
||||
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::Short:
|
||||
case BuiltinType::UShort:
|
||||
return llvm::IntegerType::get(Target.getShortWidth(SourceLocation()));
|
||||
|
||||
case BuiltinType::Int:
|
||||
case BuiltinType::UInt:
|
||||
return llvm::IntegerType::get(Target.getIntWidth(SourceLocation()));
|
||||
|
||||
case BuiltinType::Long:
|
||||
case BuiltinType::ULong:
|
||||
return llvm::IntegerType::get(Target.getLongWidth(SourceLocation()));
|
||||
|
||||
case BuiltinType::LongLong:
|
||||
case BuiltinType::ULongLong:
|
||||
return llvm::IntegerType::get(Target.getLongLongWidth(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::Array: {
|
||||
const ArrayType &A = cast<ArrayType>(Ty);
|
||||
assert(A.getSizeModifier() == ArrayType::Normal &&
|
||||
A.getIndexTypeQualifier() == 0 &&
|
||||
"FIXME: We only handle trivial array types so far!");
|
||||
|
||||
llvm::APSInt Size(32);
|
||||
if (A.getSize() && A.getSize()->isIntegerConstantExpr(Size)) {
|
||||
const llvm::Type *EltTy = ConvertType(A.getElementType());
|
||||
return llvm::ArrayType::get(EltTy, Size.getZExtValue());
|
||||
} else {
|
||||
assert(0 && "FIXME: VLAs not implemented yet!");
|
||||
}
|
||||
}
|
||||
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::TypeName:
|
||||
case Type::Tagged:
|
||||
break;
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
//===--- 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 <vector>
|
||||
|
||||
namespace llvm {
|
||||
class Type;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
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 {
|
||||
TargetInfo &Target;
|
||||
|
||||
public:
|
||||
CodeGenTypes(TargetInfo &target) : Target(target) {}
|
||||
|
||||
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
|
|
@ -0,0 +1,23 @@
|
|||
##===- 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
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
//===--- 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);
|
||||
}
|
||||
|
||||
/// PrintStats - Emit statistic information to stderr.
|
||||
///
|
||||
void clang::CodeGen::PrintStats(BuilderTy *B) {
|
||||
static_cast<CodeGenModule*>(B)->PrintStats();
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
//===--- 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/Lex/Preprocessor.h"
|
||||
#include "clang/Sema/ASTStreamer.h"
|
||||
|
||||
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.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);
|
||||
}
|
||||
|
||||
void clang::PrintFunctionDecl(FunctionDecl *FD) {
|
||||
bool HasBody = FD->getBody();
|
||||
|
||||
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, "\n%s", Proto.c_str());
|
||||
|
||||
if (FD->getBody()) {
|
||||
fprintf(stderr, " ");
|
||||
FD->getBody()->dump();
|
||||
fprintf(stderr, "\n");
|
||||
} else {
|
||||
fprintf(stderr, ";\n");
|
||||
}
|
||||
}
|
||||
|
||||
void clang::PrintTypeDefDecl(TypedefDecl *TD) {
|
||||
std::string S = TD->getName();
|
||||
TD->getUnderlyingType().getAsStringInternal(S);
|
||||
fprintf(stderr, "typedef %s;\n", S.c_str());
|
||||
}
|
||||
|
||||
void clang::PrintASTs(Preprocessor &PP, unsigned MainFileID, bool Stats) {
|
||||
ASTContext Context(PP.getTargetInfo(), PP.getIdentifierTable());
|
||||
ASTStreamerTy *Streamer = ASTStreamer_Init(PP, Context, MainFileID);
|
||||
|
||||
while (Decl *D = ASTStreamer_ReadTopLevelDecl(Streamer)) {
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
PrintFunctionDecl(FD);
|
||||
} 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);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
//===--- 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 PrintFunctionDecl(FunctionDecl *FD);
|
||||
void PrintTypeDefDecl(TypedefDecl *TD);
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
|
@ -0,0 +1,230 @@
|
|||
//===--- 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.getLineNumber(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.getLineNumber(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);
|
||||
|
||||
LexerToken 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.getLineNumber(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.getLineNumber(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.getLineNumber(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) {
|
||||
// Gather the set of expected diagnostics.
|
||||
DiagList ExpectedErrors, ExpectedWarnings;
|
||||
FindExpectedDiags(PP, MainFileID, ExpectedErrors, ExpectedWarnings);
|
||||
|
||||
// Parse the specified input file.
|
||||
BuildASTs(PP, MainFileID, false);
|
||||
|
||||
// Check that the expected diagnostics occurred.
|
||||
return CheckResults(PP, ExpectedErrors, ExpectedWarnings);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
//===--- 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.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 (isa<TypedefDecl>(D)) {
|
||||
std::cerr << "Read top-level typedef decl: '" << D->getName() << "'\n";
|
||||
} else {
|
||||
std::cerr << "Read top-level variable 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);
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
LEVEL = ../../..
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
||||
CXXFLAGS = -fno-rtti
|
||||
|
||||
TOOLNAME = clang
|
||||
USEDLIBS = clangCodeGen.a clangSEMA.a clangAST.a clangParse.a clangLex.a clangBasic.a LLVMCore.a LLVMSupport.a LLVMSystem.a
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
|
@ -0,0 +1,24 @@
|
|||
//===--- 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
|
|
@ -0,0 +1,55 @@
|
|||
//===--- 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, ExprTy *Init,
|
||||
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, Init, 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();
|
||||
}
|
|
@ -0,0 +1,436 @@
|
|||
//===--- 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/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) {
|
||||
#ifdef 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();
|
||||
memcpy(OutBufCur, Ptr, Size);
|
||||
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;
|
||||
std::string CurFilename;
|
||||
bool EmittedTokensOnThisLine;
|
||||
DirectoryLookup::DirType FileType;
|
||||
public:
|
||||
PrintPPOutputPPCallbacks(Preprocessor &pp) : PP(pp) {
|
||||
CurLine = 0;
|
||||
CurFilename = "\"<uninit>\"";
|
||||
EmittedTokensOnThisLine = false;
|
||||
FileType = DirectoryLookup::NormalHeaderDir;
|
||||
}
|
||||
|
||||
void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
|
||||
|
||||
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
|
||||
DirectoryLookup::DirType FileType);
|
||||
virtual void Ident(SourceLocation Loc, const std::string &str);
|
||||
|
||||
|
||||
void HandleFirstTokOnLine(LexerToken &Tok);
|
||||
void MoveToLine(SourceLocation Loc);
|
||||
bool AvoidConcat(const LexerToken &PrevTok, const LexerToken &Tok);
|
||||
};
|
||||
}
|
||||
|
||||
/// 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().getLineNumber(Loc);
|
||||
|
||||
// If this line is "close enough" to the original line, just print newlines,
|
||||
// otherwise print a #line directive.
|
||||
if (LineNo-CurLine < 8) {
|
||||
unsigned Line = CurLine;
|
||||
for (; Line != LineNo; ++Line)
|
||||
OutputChar('\n');
|
||||
CurLine = Line;
|
||||
} else {
|
||||
if (EmittedTokensOnThisLine) {
|
||||
OutputChar('\n');
|
||||
EmittedTokensOnThisLine = false;
|
||||
}
|
||||
|
||||
CurLine = LineNo;
|
||||
|
||||
OutputChar('#');
|
||||
OutputChar(' ');
|
||||
std::string Num = llvm::utostr_32(LineNo);
|
||||
OutputString(&Num[0], Num.size());
|
||||
OutputChar(' ');
|
||||
OutputString(&CurFilename[0], CurFilename.size());
|
||||
|
||||
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.getFileID()));
|
||||
} 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.
|
||||
}
|
||||
|
||||
CurLine = SourceMgr.getLineNumber(Loc);
|
||||
CurFilename = '"' + Lexer::Stringify(SourceMgr.getSourceName(Loc)) + '"';
|
||||
FileType = FileType;
|
||||
|
||||
if (EmittedTokensOnThisLine) {
|
||||
OutputChar('\n');
|
||||
EmittedTokensOnThisLine = false;
|
||||
}
|
||||
|
||||
if (DisableLineMarkers) return;
|
||||
|
||||
OutputChar('#');
|
||||
OutputChar(' ');
|
||||
std::string Num = llvm::utostr_32(CurLine);
|
||||
OutputString(&Num[0], Num.size());
|
||||
OutputChar(' ');
|
||||
OutputString(&CurFilename[0], CurFilename.size());
|
||||
|
||||
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(LexerToken &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.
|
||||
unsigned ColNo =
|
||||
PP.getSourceManager().getColumnNumber(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, LexerToken &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
|
||||
|
||||
/// 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 LexerToken &PrevTok,
|
||||
const LexerToken &Tok) {
|
||||
char Buffer[256];
|
||||
|
||||
// If we haven't emitted a token on this line yet, PrevTok isn't useful to
|
||||
// look at and no concatenation could happen anyway.
|
||||
if (!EmittedTokensOnThisLine)
|
||||
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;
|
||||
if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
|
||||
// Avoid spelling identifiers, the most common form of token.
|
||||
FirstChar = II->getName()[0];
|
||||
} else if (Tok.getLength() < 256) {
|
||||
const char *TokPtr = Buffer;
|
||||
PP.getSpelling(Tok, TokPtr);
|
||||
FirstChar = TokPtr[0];
|
||||
} else {
|
||||
FirstChar = PP.getSpelling(Tok)[0];
|
||||
}
|
||||
|
||||
tok::TokenKind PrevKind = PrevTok.getKind();
|
||||
if (PrevTok.getIdentifierInfo()) // Language keyword or named operator.
|
||||
PrevKind = tok::identifier;
|
||||
|
||||
switch (PrevKind) {
|
||||
default: return false;
|
||||
case tok::identifier: // id+id or id+number or id+L"foo".
|
||||
return isalnum(FirstChar) || FirstChar == '_';
|
||||
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 == '&' || FirstChar == '=';
|
||||
case tok::plus: // ++, +=
|
||||
return FirstChar == '+' || FirstChar == '=';
|
||||
case tok::minus: // --, ->, -=, ->*
|
||||
return FirstChar == '-' || FirstChar == '>' || FirstChar == '=';
|
||||
case tok::slash: // /=, /*, //
|
||||
return FirstChar == '=' || FirstChar == '*' || FirstChar == '/';
|
||||
case tok::less: // <<, <<=, <=, <?=, <?, <:, <%
|
||||
return FirstChar == '<' || FirstChar == '?' || FirstChar == '=' ||
|
||||
FirstChar == ':' || FirstChar == '%';
|
||||
case tok::greater: // >>, >=, >>=, >?=, >?, ->*
|
||||
return FirstChar == '>' || FirstChar == '?' || FirstChar == '=' ||
|
||||
FirstChar == '*';
|
||||
case tok::pipe: // ||, |=
|
||||
return FirstChar == '|' || FirstChar == '=';
|
||||
case tok::percent: // %=, %>, %:
|
||||
return FirstChar == '=' || FirstChar == '>' || FirstChar == ':';
|
||||
case tok::colon: // ::, :>
|
||||
return FirstChar == ':' || FirstChar == '>';
|
||||
case tok::hash: // ##, #@, %:%:
|
||||
return FirstChar == '#' || FirstChar == '@' || FirstChar == '%';
|
||||
case tok::arrow: // ->*
|
||||
return FirstChar == '*';
|
||||
|
||||
case tok::star: // *=
|
||||
case tok::exclaim: // !=
|
||||
case tok::lessless: // <<=
|
||||
case tok::greaterequal: // >>=
|
||||
case tok::caret: // ^=
|
||||
case tok::equal: // ==
|
||||
// Cases that concatenate only if the next char is =.
|
||||
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();
|
||||
|
||||
LexerToken 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() ||
|
||||
// Don't print "-" next to "-", it would form "--".
|
||||
Callbacks->AvoidConcat(PrevTok, Tok)) {
|
||||
OutputChar(' ');
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
@ -0,0 +1,443 @@
|
|||
//===--- 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;
|
||||
}
|
||||
|
||||
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 = linux.
|
||||
Archs.push_back(target_linux_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;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
//===--- 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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
//===--- 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
|
|
@ -0,0 +1,225 @@
|
|||
//===--- 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) {
|
||||
unsigned FileID = Pos.getFileID();
|
||||
if (FileID == 0) return;
|
||||
|
||||
// Print out the other include frames first.
|
||||
PrintIncludeStack(SourceMgr.getIncludeLoc(FileID));
|
||||
|
||||
unsigned LineNo = SourceMgr.getLineNumber(Pos);
|
||||
|
||||
const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(FileID);
|
||||
std::cerr << "In file included from " << Buffer->getBufferIdentifier()
|
||||
<< ":" << 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.getLineNumber(R.Begin());
|
||||
if (StartLineNo > LineNo) return; // No intersection.
|
||||
|
||||
unsigned EndLineNo = SourceMgr.getLineNumber(R.End());
|
||||
if (EndLineNo < LineNo) return; // No intersection.
|
||||
|
||||
// Compute the column number of the start.
|
||||
unsigned StartColNo = 0;
|
||||
if (StartLineNo == LineNo) {
|
||||
StartColNo = SourceMgr.getColumnNumber(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.getColumnNumber(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) {
|
||||
const char *StrData =
|
||||
SourceMgr.getCharacterData(SourceMgr.getLogicalLoc(Loc));
|
||||
|
||||
// Note, this could be special cased for common tokens like identifiers, ')',
|
||||
// etc to make this faster, if it mattered.
|
||||
|
||||
unsigned FileID = Loc.getFileID();
|
||||
|
||||
// Create a lexer starting at the beginning of this token.
|
||||
Lexer TheLexer(SourceMgr.getBuffer(FileID), FileID,
|
||||
*ThePreprocessor, StrData);
|
||||
|
||||
LexerToken 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, FilePos = 0, FileID = 0, ColNo = 0;
|
||||
unsigned LineStart = 0, LineEnd = 0;
|
||||
const llvm::MemoryBuffer *Buffer = 0;
|
||||
|
||||
if (Pos.isValid()) {
|
||||
LineNo = SourceMgr.getLineNumber(Pos);
|
||||
FileID = SourceMgr.getLogicalLoc(Pos).getFileID();
|
||||
|
||||
// First, if this diagnostic is not in the main file, print out the
|
||||
// "included from" lines.
|
||||
if (LastWarningLoc != SourceMgr.getIncludeLoc(FileID)) {
|
||||
LastWarningLoc = SourceMgr.getIncludeLoc(FileID);
|
||||
PrintIncludeStack(LastWarningLoc);
|
||||
}
|
||||
|
||||
// Compute the column number. Rewind from the current position to the start
|
||||
// of the line.
|
||||
ColNo = SourceMgr.getColumnNumber(Pos);
|
||||
FilePos = SourceMgr.getSourceFilePos(Pos);
|
||||
LineStart = FilePos-ColNo+1; // Column # is 1-based
|
||||
|
||||
// Compute the line end. Scan forward from the error position to the end of
|
||||
// the line.
|
||||
Buffer = SourceMgr.getBuffer(FileID);
|
||||
const char *Buf = Buffer->getBufferStart();
|
||||
const char *BufEnd = Buffer->getBufferEnd();
|
||||
LineEnd = FilePos;
|
||||
while (Buf+LineEnd != BufEnd &&
|
||||
Buf[LineEnd] != '\n' && Buf[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;
|
||||
case Diagnostic::Sorry: std::cerr << "sorry, unimplemented: ";
|
||||
break;
|
||||
}
|
||||
|
||||
std::cerr << FormatDiagnostic(Level, ID, Strs, NumStrs) << "\n";
|
||||
|
||||
if (!NoCaretDiagnostics && Pos.isValid()) {
|
||||
// Get the line of the source file.
|
||||
const char *Buf = Buffer->getBufferStart();
|
||||
std::string SourceLine(Buf+LineStart, Buf+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";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
//===--- 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
|
|
@ -0,0 +1,60 @@
|
|||
//===--- 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) {
|
||||
SourceLocation PhysLoc = SourceMgr.getPhysicalLoc(Pos);
|
||||
const FileEntry *F = SourceMgr.getFileEntryForFileID(PhysLoc.getFileID());
|
||||
if (F) {
|
||||
DirectoryLookup::DirType DirInfo = TheHeaderSearch->getFileDirFlavor(F);
|
||||
if (DirInfo == DirectoryLookup::SystemHeaderDir ||
|
||||
DirInfo == DirectoryLookup::ExternCSystemHeaderDir)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
//===--- 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
|
|
@ -0,0 +1,420 @@
|
|||
//===--- 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
|
|
@ -0,0 +1,914 @@
|
|||
//===--- 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.
|
||||
ParseASTCheck, // Parse ASTs and check diagnostics.
|
||||
ParseAST, // Parse 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(ParseASTCheck, "parse-ast-check",
|
||||
"Run parser, build ASTs, then check diagnostics"),
|
||||
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
|
||||
};
|
||||
|
||||
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++)"),
|
||||
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_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)
|
||||
DefineBuiltinMacro(Buf, "__STDC_VERSION__=199901L");
|
||||
else
|
||||
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: -isysroot,-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"));
|
||||
|
||||
// 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 = 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.
|
||||
LexerToken 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) {
|
||||
switch (ProgAction) {
|
||||
default:
|
||||
fprintf(stderr, "Unexpected program action!\n");
|
||||
return;
|
||||
case DumpTokens: { // Token dump mode.
|
||||
LexerToken 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);
|
||||
break;
|
||||
}
|
||||
case RunPreprocessorOnly: { // Just lex as fast as we can, no output.
|
||||
LexerToken Tok;
|
||||
// Start parsing the specified input file.
|
||||
PP.EnterSourceFile(MainFileID, 0, true);
|
||||
do {
|
||||
PP.Lex(Tok);
|
||||
} while (Tok.getKind() != tok::eof);
|
||||
break;
|
||||
}
|
||||
|
||||
case PrintPreprocessedInput: // -E mode.
|
||||
DoPrintPreprocessedInput(MainFileID, PP, LangInfo);
|
||||
break;
|
||||
|
||||
case ParseNoop: // -parse-noop
|
||||
ParseFile(PP, new MinimalAction(), MainFileID);
|
||||
break;
|
||||
|
||||
case ParsePrintCallbacks:
|
||||
ParseFile(PP, CreatePrintParserActionsAction(), MainFileID);
|
||||
break;
|
||||
case ParseSyntaxOnly: // -fsyntax-only
|
||||
case ParseAST:
|
||||
BuildASTs(PP, MainFileID, Stats);
|
||||
break;
|
||||
case ParseASTPrint:
|
||||
PrintASTs(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();
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
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,0 +1,45 @@
|
|||
//===--- 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;
|
||||
class 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
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
#import <Cocoa/Cocoa.h>
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
//#import<vecLib/vecLib.h>
|
|
@ -0,0 +1,5 @@
|
|||
// 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>
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
// 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)
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
// 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
|
|
@ -0,0 +1,319 @@
|
|||
//===--- 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];
|
||||
|
||||
// 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();
|
||||
return FE;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, didn't find it.
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
//===--- 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;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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;
|
||||
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 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,
|
||||
const LangOptions &LangOpts, IdentifierTable &Table) {
|
||||
int Flags = LangOpts.CPlusPlus ? 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,
|
||||
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, 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();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,661 @@
|
|||
//===--- 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/TargetInfo.h"
|
||||
#include "clang/Basic/Diagnostic.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; // 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;
|
||||
saw_float_suffix = false;
|
||||
isLong = false;
|
||||
isUnsigned = false;
|
||||
isLongLong = 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)) {
|
||||
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;
|
||||
|
||||
if (saw_period || saw_exponent) {
|
||||
if (s < ThisTokEnd) { // parse size suffix (float, long double)
|
||||
if (*s == 'f' || *s == 'F') {
|
||||
saw_float_suffix = true;
|
||||
s++;
|
||||
} else if (*s == 'l' || *s == 'L') {
|
||||
isLong = true;
|
||||
s++;
|
||||
}
|
||||
if (s != ThisTokEnd) {
|
||||
Diag(TokLoc, diag::err_invalid_suffix_float_constant,
|
||||
std::string(SuffixBegin, ThisTokEnd));
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (s < ThisTokEnd) {
|
||||
// parse int suffix - they can appear in any order ("ul", "lu", "llu").
|
||||
if (*s == 'u' || *s == 'U') {
|
||||
s++;
|
||||
isUnsigned = true; // unsigned
|
||||
|
||||
if ((s < ThisTokEnd) && (*s == 'l' || *s == 'L')) {
|
||||
s++;
|
||||
// handle "long long" type - l's need to be adjacent and same case.
|
||||
if ((s < ThisTokEnd) && (*s == *(s-1))) {
|
||||
isLongLong = true; // unsigned long long
|
||||
s++;
|
||||
} else {
|
||||
isLong = true; // unsigned long
|
||||
}
|
||||
}
|
||||
} else if (*s == 'l' || *s == 'L') {
|
||||
s++;
|
||||
// handle "long long" types - l's need to be adjacent and same case.
|
||||
if ((s < ThisTokEnd) && (*s == *(s-1))) {
|
||||
s++;
|
||||
if ((s < ThisTokEnd) && (*s == 'u' || *s == 'U')) {
|
||||
isUnsigned = true; // unsigned long long
|
||||
s++;
|
||||
} else {
|
||||
isLongLong = true; // long long
|
||||
}
|
||||
} else { // handle "long" types
|
||||
if ((s < ThisTokEnd) && (*s == 'u' || *s == 'U')) {
|
||||
isUnsigned = true; // unsigned long
|
||||
s++;
|
||||
} else {
|
||||
isLong = true; // long
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s != ThisTokEnd) {
|
||||
Diag(TokLoc, 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 strtof(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 LexerToken *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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,636 @@
|
|||
//===--- 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 LexerToken *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(LexerToken));
|
||||
// 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<LexerToken*>(Result->getUnexpArgument(0)),
|
||||
UnexpArgTokens, NumToks*sizeof(LexerToken));
|
||||
|
||||
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 LexerToken *ArgPtr) {
|
||||
unsigned NumArgTokens = 0;
|
||||
for (; ArgPtr->getKind() != tok::eof; ++ArgPtr)
|
||||
++NumArgTokens;
|
||||
return NumArgTokens;
|
||||
}
|
||||
|
||||
|
||||
/// getUnexpArgument - Return the unexpanded tokens for the specified formal.
|
||||
///
|
||||
const LexerToken *MacroArgs::getUnexpArgument(unsigned Arg) const {
|
||||
// The unexpanded argument tokens start immediately after the MacroArgs object
|
||||
// in memory.
|
||||
const LexerToken *Start = (const LexerToken *)(this+1);
|
||||
const LexerToken *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 LexerToken *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<LexerToken> &
|
||||
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<LexerToken> &Result = PreExpArgTokens[Arg];
|
||||
if (!Result.empty()) return Result;
|
||||
|
||||
const LexerToken *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(LexerToken());
|
||||
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 LexerToken StringifyArgument(const LexerToken *ArgToks,
|
||||
Preprocessor &PP, bool Charify = false) {
|
||||
LexerToken Tok;
|
||||
Tok.startToken();
|
||||
Tok.setKind(tok::string_literal);
|
||||
|
||||
const LexerToken *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 LexerToken &Tok = *ArgToks;
|
||||
if (!isFirst && Tok.hasLeadingSpace())
|
||||
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 LexerToken &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.
|
||||
MacroExpander::MacroExpander(LexerToken &Tok, MacroArgs *Actuals,
|
||||
Preprocessor &pp)
|
||||
: Macro(Tok.getIdentifierInfo()->getMacroInfo()),
|
||||
ActualArgs(Actuals), PP(pp), CurToken(0),
|
||||
InstantiateLoc(Tok.getLocation()),
|
||||
AtStartOfLine(Tok.isAtStartOfLine()),
|
||||
HasLeadingSpace(Tok.hasLeadingSpace()) {
|
||||
MacroTokens = &Macro->getReplacementTokens()[0];
|
||||
NumMacroTokens = Macro->getReplacementTokens().size();
|
||||
|
||||
// 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.
|
||||
MacroExpander::MacroExpander(const LexerToken *TokArray, unsigned NumToks,
|
||||
Preprocessor &pp)
|
||||
: Macro(0), ActualArgs(0), PP(pp), MacroTokens(TokArray),
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MacroExpander::~MacroExpander() {
|
||||
// If this was a function-like macro that actually uses its arguments, delete
|
||||
// the expanded tokens.
|
||||
if (Macro && MacroTokens != &Macro->getReplacementTokens()[0])
|
||||
delete [] MacroTokens;
|
||||
|
||||
// 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<LexerToken, 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 LexerToken &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?");
|
||||
|
||||
LexerToken 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(LexerToken::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(LexerToken::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 LexerToken *ResultArgToks;
|
||||
|
||||
// Only preexpand the argument if it could possibly need it. This
|
||||
// avoids some work in common cases.
|
||||
const LexerToken *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(LexerToken::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 LexerToken *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(LexerToken::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();
|
||||
LexerToken *Res = new LexerToken[ResultToks.size()];
|
||||
if (NumMacroTokens)
|
||||
memcpy(Res, &ResultToks[0], NumMacroTokens*sizeof(LexerToken));
|
||||
MacroTokens = Res;
|
||||
}
|
||||
}
|
||||
|
||||
/// Lex - Lex and return a token from this macro stream.
|
||||
///
|
||||
void MacroExpander::Lex(LexerToken &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();
|
||||
// The token could have come from a prior macro expansion. In that case,
|
||||
// ignore the macro expand part to get to the physloc. This happens for
|
||||
// stuff like: #define A(X) X A(A(X)) A(1)
|
||||
SourceLocation PhysLoc = SrcMgr.getPhysicalLoc(Tok.getLocation());
|
||||
Tok.setLocation(SrcMgr.getInstantiationLoc(PhysLoc, 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(LexerToken::StartOfLine , AtStartOfLine);
|
||||
Tok.setFlagValue(LexerToken::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(LexerToken &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 LexerToken &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.
|
||||
LexerToken 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);
|
||||
|
||||
unsigned FileID = ResultTokLoc.getFileID();
|
||||
assert(FileID && "Could not get FileID for paste?");
|
||||
|
||||
// Make a lexer object so that we lex and expand the paste result.
|
||||
Lexer *TL = new Lexer(SourceMgr.getBuffer(FileID), FileID, 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(LexerToken::StartOfLine , Tok.isAtStartOfLine());
|
||||
Result.setFlagValue(LexerToken::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;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
//===--- 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;
|
||||
}
|
||||
|
||||
/// 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() ||
|
||||
Arguments.size() != Other.Arguments.size() ||
|
||||
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 LexerToken &A = ReplacementTokens[i];
|
||||
const LexerToken &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;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
##===- 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
|
||||
|
|
@ -0,0 +1,654 @@
|
|||
//===--- 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,
|
||||
LexerToken &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, LexerToken &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()) {
|
||||
PP.Diag(PeekTok, diag::err_pp_illegal_floating_literal);
|
||||
return true;
|
||||
}
|
||||
assert(Literal.isIntegerLiteral() && "Unknown ppnumber");
|
||||
|
||||
// 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,
|
||||
LexerToken &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.
|
||||
LexerToken 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.toString(10, true) + " to " + LHS.toString(10, false));
|
||||
if (!RHS.isUnsigned() && RHS.isNegative())
|
||||
PP.Diag(OpToken, diag::warn_pp_convert_rhs_to_positive,
|
||||
RHS.toString(10, true) + " to " + RHS.toString(10, false));
|
||||
}
|
||||
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 = 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 = 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.
|
||||
LexerToken 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,369 @@
|
|||
//===--- 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, LexerToken &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.
|
||||
LexerToken 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(LexerToken &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);
|
||||
|
||||
unsigned FileID = TokLoc.getFileID();
|
||||
assert(FileID && "Could not get FileID for _Pragma?");
|
||||
|
||||
// Make and enter a lexer object so that we lex and expand the tokens just
|
||||
// like any others.
|
||||
Lexer *TL = new Lexer(SourceMgr.getBuffer(FileID), FileID, *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(LexerToken &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.
|
||||
unsigned FileID = getCurrentFileLexer()->getCurFileID();
|
||||
|
||||
// Mark the file as a once-only file now.
|
||||
HeaderInfo.MarkFileIncludeOnce(SourceMgr.getFileEntryForFileID(FileID));
|
||||
}
|
||||
|
||||
/// HandlePragmaPoison - Handle #pragma GCC poison. PoisonTok is the 'poison'.
|
||||
///
|
||||
void Preprocessor::HandlePragmaPoison(LexerToken &PoisonTok) {
|
||||
LexerToken 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(LexerToken &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.getFileEntryForFileID(TheLexer->getCurFileID());
|
||||
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(LexerToken &DependencyTok) {
|
||||
LexerToken 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], *FilenameEnd;
|
||||
bool isAngled = GetIncludeFilenameSpelling(FilenameTok,
|
||||
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));
|
||||
|
||||
unsigned FileID = getCurrentFileLexer()->getCurFileID();
|
||||
const FileEntry *CurFile = SourceMgr.getFileEntryForFileID(FileID);
|
||||
|
||||
// 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, LexerToken &OnceTok) {
|
||||
PP.CheckEndOfDirective("#pragma once");
|
||||
PP.HandlePragmaOnce(OnceTok);
|
||||
}
|
||||
};
|
||||
|
||||
struct PragmaPoisonHandler : public PragmaHandler {
|
||||
PragmaPoisonHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
|
||||
virtual void HandlePragma(Preprocessor &PP, LexerToken &PoisonTok) {
|
||||
PP.HandlePragmaPoison(PoisonTok);
|
||||
}
|
||||
};
|
||||
|
||||
struct PragmaSystemHeaderHandler : public PragmaHandler {
|
||||
PragmaSystemHeaderHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
|
||||
virtual void HandlePragma(Preprocessor &PP, LexerToken &SHToken) {
|
||||
PP.HandlePragmaSystemHeader(SHToken);
|
||||
PP.CheckEndOfDirective("#pragma");
|
||||
}
|
||||
};
|
||||
struct PragmaDependencyHandler : public PragmaHandler {
|
||||
PragmaDependencyHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
|
||||
virtual void HandlePragma(Preprocessor &PP, LexerToken &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
|
@ -0,0 +1,71 @@
|
|||
//===--- 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(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;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
LEVEL = ../..
|
||||
DIRS := Basic Lex Parse AST Sema CodeGen 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:
|
|
@ -0,0 +1,218 @@
|
|||
//===---------------------------------------------------------------------===//
|
||||
// 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.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
|
@ -0,0 +1,27 @@
|
|||
//===--- 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];
|
||||
}
|
|
@ -0,0 +1,285 @@
|
|||
//===--- 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";
|
||||
}
|
||||
}
|
||||
|
||||
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: infer real type.
|
||||
|
||||
// TODO: return "auto function" and other bad things based on the real type.
|
||||
|
||||
// 'data definition has no type or storage class'?
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
##===- 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
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
//===--- 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, ExprTy *Init,
|
||||
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;
|
||||
}
|
||||
|
||||
/// ParsedObjcClassDeclaration -
|
||||
/// Scope will always be top level file scope.
|
||||
Action::DeclTy *
|
||||
MinimalAction::ParsedObjcClassDeclaration(Scope *S,
|
||||
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
|
@ -0,0 +1,935 @@
|
|||
//===--- ParseExpr.cpp - Expression 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 Expression parsing implementation. Expressions in
|
||||
// C99 basically consist of a bunch of binary operators with unary operators and
|
||||
// other random stuff at the leaves.
|
||||
//
|
||||
// In the C99 grammar, these unary operators bind tightest and are represented
|
||||
// as the 'cast-expression' production. Everything else is either a binary
|
||||
// operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are
|
||||
// handled by ParseCastExpression, the higher level pieces are handled by
|
||||
// ParseBinaryExpression.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Parse/Parser.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
using namespace clang;
|
||||
|
||||
/// PrecedenceLevels - These are precedences for the binary/ternary operators in
|
||||
/// the C99 grammar. These have been named to relate with the C99 grammar
|
||||
/// productions. Low precedences numbers bind more weakly than high numbers.
|
||||
namespace prec {
|
||||
enum Level {
|
||||
Unknown = 0, // Not binary operator.
|
||||
Comma = 1, // ,
|
||||
Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
|
||||
Conditional = 3, // ?
|
||||
LogicalOr = 4, // ||
|
||||
LogicalAnd = 5, // &&
|
||||
InclusiveOr = 6, // |
|
||||
ExclusiveOr = 7, // ^
|
||||
And = 8, // &
|
||||
Equality = 9, // ==, !=
|
||||
Relational = 10, // >=, <=, >, <
|
||||
Shift = 11, // <<, >>
|
||||
Additive = 12, // -, +
|
||||
Multiplicative = 13 // *, /, %
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// getBinOpPrecedence - Return the precedence of the specified binary operator
|
||||
/// token. This returns:
|
||||
///
|
||||
static prec::Level getBinOpPrecedence(tok::TokenKind Kind) {
|
||||
switch (Kind) {
|
||||
default: return prec::Unknown;
|
||||
case tok::comma: return prec::Comma;
|
||||
case tok::equal:
|
||||
case tok::starequal:
|
||||
case tok::slashequal:
|
||||
case tok::percentequal:
|
||||
case tok::plusequal:
|
||||
case tok::minusequal:
|
||||
case tok::lesslessequal:
|
||||
case tok::greatergreaterequal:
|
||||
case tok::ampequal:
|
||||
case tok::caretequal:
|
||||
case tok::pipeequal: return prec::Assignment;
|
||||
case tok::question: return prec::Conditional;
|
||||
case tok::pipepipe: return prec::LogicalOr;
|
||||
case tok::ampamp: return prec::LogicalAnd;
|
||||
case tok::pipe: return prec::InclusiveOr;
|
||||
case tok::caret: return prec::ExclusiveOr;
|
||||
case tok::amp: return prec::And;
|
||||
case tok::exclaimequal:
|
||||
case tok::equalequal: return prec::Equality;
|
||||
case tok::lessequal:
|
||||
case tok::less:
|
||||
case tok::greaterequal:
|
||||
case tok::greater: return prec::Relational;
|
||||
case tok::lessless:
|
||||
case tok::greatergreater: return prec::Shift;
|
||||
case tok::plus:
|
||||
case tok::minus: return prec::Additive;
|
||||
case tok::percent:
|
||||
case tok::slash:
|
||||
case tok::star: return prec::Multiplicative;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// ParseExpression - Simple precedence-based parser for binary/ternary
|
||||
/// operators.
|
||||
///
|
||||
/// Note: we diverge from the C99 grammar when parsing the assignment-expression
|
||||
/// production. C99 specifies that the LHS of an assignment operator should be
|
||||
/// parsed as a unary-expression, but consistency dictates that it be a
|
||||
/// conditional-expession. In practice, the important thing here is that the
|
||||
/// LHS of an assignment has to be an l-value, which productions between
|
||||
/// unary-expression and conditional-expression don't produce. Because we want
|
||||
/// consistency, we parse the LHS as a conditional-expression, then check for
|
||||
/// l-value-ness in semantic analysis stages.
|
||||
///
|
||||
/// multiplicative-expression: [C99 6.5.5]
|
||||
/// cast-expression
|
||||
/// multiplicative-expression '*' cast-expression
|
||||
/// multiplicative-expression '/' cast-expression
|
||||
/// multiplicative-expression '%' cast-expression
|
||||
///
|
||||
/// additive-expression: [C99 6.5.6]
|
||||
/// multiplicative-expression
|
||||
/// additive-expression '+' multiplicative-expression
|
||||
/// additive-expression '-' multiplicative-expression
|
||||
///
|
||||
/// shift-expression: [C99 6.5.7]
|
||||
/// additive-expression
|
||||
/// shift-expression '<<' additive-expression
|
||||
/// shift-expression '>>' additive-expression
|
||||
///
|
||||
/// relational-expression: [C99 6.5.8]
|
||||
/// shift-expression
|
||||
/// relational-expression '<' shift-expression
|
||||
/// relational-expression '>' shift-expression
|
||||
/// relational-expression '<=' shift-expression
|
||||
/// relational-expression '>=' shift-expression
|
||||
///
|
||||
/// equality-expression: [C99 6.5.9]
|
||||
/// relational-expression
|
||||
/// equality-expression '==' relational-expression
|
||||
/// equality-expression '!=' relational-expression
|
||||
///
|
||||
/// AND-expression: [C99 6.5.10]
|
||||
/// equality-expression
|
||||
/// AND-expression '&' equality-expression
|
||||
///
|
||||
/// exclusive-OR-expression: [C99 6.5.11]
|
||||
/// AND-expression
|
||||
/// exclusive-OR-expression '^' AND-expression
|
||||
///
|
||||
/// inclusive-OR-expression: [C99 6.5.12]
|
||||
/// exclusive-OR-expression
|
||||
/// inclusive-OR-expression '|' exclusive-OR-expression
|
||||
///
|
||||
/// logical-AND-expression: [C99 6.5.13]
|
||||
/// inclusive-OR-expression
|
||||
/// logical-AND-expression '&&' inclusive-OR-expression
|
||||
///
|
||||
/// logical-OR-expression: [C99 6.5.14]
|
||||
/// logical-AND-expression
|
||||
/// logical-OR-expression '||' logical-AND-expression
|
||||
///
|
||||
/// conditional-expression: [C99 6.5.15]
|
||||
/// logical-OR-expression
|
||||
/// logical-OR-expression '?' expression ':' conditional-expression
|
||||
/// [GNU] logical-OR-expression '?' ':' conditional-expression
|
||||
///
|
||||
/// assignment-expression: [C99 6.5.16]
|
||||
/// conditional-expression
|
||||
/// unary-expression assignment-operator assignment-expression
|
||||
///
|
||||
/// assignment-operator: one of
|
||||
/// = *= /= %= += -= <<= >>= &= ^= |=
|
||||
///
|
||||
/// expression: [C99 6.5.17]
|
||||
/// assignment-expression
|
||||
/// expression ',' assignment-expression
|
||||
///
|
||||
Parser::ExprResult Parser::ParseExpression() {
|
||||
ExprResult LHS = ParseCastExpression(false);
|
||||
if (LHS.isInvalid) return LHS;
|
||||
|
||||
return ParseRHSOfBinaryExpression(LHS, prec::Comma);
|
||||
}
|
||||
|
||||
/// ParseAssignmentExpression - Parse an expr that doesn't include commas.
|
||||
///
|
||||
Parser::ExprResult Parser::ParseAssignmentExpression() {
|
||||
ExprResult LHS = ParseCastExpression(false);
|
||||
if (LHS.isInvalid) return LHS;
|
||||
|
||||
return ParseRHSOfBinaryExpression(LHS, prec::Assignment);
|
||||
}
|
||||
|
||||
Parser::ExprResult Parser::ParseConstantExpression() {
|
||||
ExprResult LHS = ParseCastExpression(false);
|
||||
if (LHS.isInvalid) return LHS;
|
||||
|
||||
// TODO: Validate that this is a constant expr!
|
||||
return ParseRHSOfBinaryExpression(LHS, prec::Conditional);
|
||||
}
|
||||
|
||||
/// ParseExpressionWithLeadingIdentifier - This special purpose method is used
|
||||
/// in contexts where we have already consumed an identifier (which we saved in
|
||||
/// 'IdTok'), then discovered that the identifier was really the leading token
|
||||
/// of part of an expression. For example, in "A[1]+B", we consumed "A" (which
|
||||
/// is now in 'IdTok') and the current token is "[".
|
||||
Parser::ExprResult Parser::
|
||||
ParseExpressionWithLeadingIdentifier(const LexerToken &IdTok) {
|
||||
// We know that 'IdTok' must correspond to this production:
|
||||
// primary-expression: identifier
|
||||
|
||||
// Let the actions module handle the identifier.
|
||||
ExprResult Res = Actions.ParseIdentifierExpr(CurScope, IdTok.getLocation(),
|
||||
*IdTok.getIdentifierInfo(),
|
||||
Tok.getKind() == tok::l_paren);
|
||||
|
||||
// Because we have to parse an entire cast-expression before starting the
|
||||
// ParseRHSOfBinaryExpression method (which parses any trailing binops), we
|
||||
// need to handle the 'postfix-expression' rules. We do this by invoking
|
||||
// ParsePostfixExpressionSuffix to consume any postfix-expression suffixes:
|
||||
Res = ParsePostfixExpressionSuffix(Res);
|
||||
if (Res.isInvalid) return Res;
|
||||
|
||||
// At this point, the "A[1]" part of "A[1]+B" has been consumed. Once this is
|
||||
// done, we know we don't have to do anything for cast-expression, because the
|
||||
// only non-postfix-expression production starts with a '(' token, and we know
|
||||
// we have an identifier. As such, we can invoke ParseRHSOfBinaryExpression
|
||||
// to consume any trailing operators (e.g. "+" in this example) and connected
|
||||
// chunks of the expression.
|
||||
return ParseRHSOfBinaryExpression(Res, prec::Comma);
|
||||
}
|
||||
|
||||
/// ParseExpressionWithLeadingIdentifier - This special purpose method is used
|
||||
/// in contexts where we have already consumed an identifier (which we saved in
|
||||
/// 'IdTok'), then discovered that the identifier was really the leading token
|
||||
/// of part of an assignment-expression. For example, in "A[1]+B", we consumed
|
||||
/// "A" (which is now in 'IdTok') and the current token is "[".
|
||||
Parser::ExprResult Parser::
|
||||
ParseAssignmentExprWithLeadingIdentifier(const LexerToken &IdTok) {
|
||||
// We know that 'IdTok' must correspond to this production:
|
||||
// primary-expression: identifier
|
||||
|
||||
// Let the actions module handle the identifier.
|
||||
ExprResult Res = Actions.ParseIdentifierExpr(CurScope, IdTok.getLocation(),
|
||||
*IdTok.getIdentifierInfo(),
|
||||
Tok.getKind() == tok::l_paren);
|
||||
|
||||
// Because we have to parse an entire cast-expression before starting the
|
||||
// ParseRHSOfBinaryExpression method (which parses any trailing binops), we
|
||||
// need to handle the 'postfix-expression' rules. We do this by invoking
|
||||
// ParsePostfixExpressionSuffix to consume any postfix-expression suffixes:
|
||||
Res = ParsePostfixExpressionSuffix(Res);
|
||||
if (Res.isInvalid) return Res;
|
||||
|
||||
// At this point, the "A[1]" part of "A[1]+B" has been consumed. Once this is
|
||||
// done, we know we don't have to do anything for cast-expression, because the
|
||||
// only non-postfix-expression production starts with a '(' token, and we know
|
||||
// we have an identifier. As such, we can invoke ParseRHSOfBinaryExpression
|
||||
// to consume any trailing operators (e.g. "+" in this example) and connected
|
||||
// chunks of the expression.
|
||||
return ParseRHSOfBinaryExpression(Res, prec::Assignment);
|
||||
}
|
||||
|
||||
|
||||
/// ParseAssignmentExpressionWithLeadingStar - This special purpose method is
|
||||
/// used in contexts where we have already consumed a '*' (which we saved in
|
||||
/// 'StarTok'), then discovered that the '*' was really the leading token of an
|
||||
/// expression. For example, in "*(int*)P+B", we consumed "*" (which is
|
||||
/// now in 'StarTok') and the current token is "(".
|
||||
Parser::ExprResult Parser::
|
||||
ParseAssignmentExpressionWithLeadingStar(const LexerToken &StarTok) {
|
||||
// We know that 'StarTok' must correspond to this production:
|
||||
// unary-expression: unary-operator cast-expression
|
||||
// where 'unary-operator' is '*'.
|
||||
|
||||
// Parse the cast-expression that follows the '*'. This will parse the
|
||||
// "*(int*)P" part of "*(int*)P+B".
|
||||
ExprResult Res = ParseCastExpression(false);
|
||||
if (Res.isInvalid) return Res;
|
||||
|
||||
// Combine StarTok + Res to get the new AST for the combined expression..
|
||||
Res = Actions.ParseUnaryOp(StarTok.getLocation(), tok::star, Res.Val);
|
||||
if (Res.isInvalid) return Res;
|
||||
|
||||
|
||||
// We have to parse an entire cast-expression before starting the
|
||||
// ParseRHSOfBinaryExpression method (which parses any trailing binops). Since
|
||||
// we know that the only production above us is the cast-expression
|
||||
// production, and because the only alternative productions start with a '('
|
||||
// token (we know we had a '*'), there is no work to do to get a whole
|
||||
// cast-expression.
|
||||
|
||||
// At this point, the "*(int*)P" part of "*(int*)P+B" has been consumed. Once
|
||||
// this is done, we can invoke ParseRHSOfBinaryExpression to consume any
|
||||
// trailing operators (e.g. "+" in this example) and connected chunks of the
|
||||
// assignment-expression.
|
||||
return ParseRHSOfBinaryExpression(Res, prec::Assignment);
|
||||
}
|
||||
|
||||
|
||||
/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with
|
||||
/// LHS and has a precedence of at least MinPrec.
|
||||
Parser::ExprResult
|
||||
Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) {
|
||||
unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind());
|
||||
SourceLocation ColonLoc;
|
||||
|
||||
while (1) {
|
||||
// If this token has a lower precedence than we are allowed to parse (e.g.
|
||||
// because we are called recursively, or because the token is not a binop),
|
||||
// then we are done!
|
||||
if (NextTokPrec < MinPrec)
|
||||
return LHS;
|
||||
|
||||
// Consume the operator, saving the operator token for error reporting.
|
||||
LexerToken OpToken = Tok;
|
||||
ConsumeToken();
|
||||
|
||||
// Special case handling for the ternary operator.
|
||||
ExprResult TernaryMiddle(true);
|
||||
if (NextTokPrec == prec::Conditional) {
|
||||
if (Tok.getKind() != tok::colon) {
|
||||
// Handle this production specially:
|
||||
// logical-OR-expression '?' expression ':' conditional-expression
|
||||
// In particular, the RHS of the '?' is 'expression', not
|
||||
// 'logical-OR-expression' as we might expect.
|
||||
TernaryMiddle = ParseExpression();
|
||||
if (TernaryMiddle.isInvalid) return TernaryMiddle;
|
||||
} else {
|
||||
// Special case handling of "X ? Y : Z" where Y is empty:
|
||||
// logical-OR-expression '?' ':' conditional-expression [GNU]
|
||||
TernaryMiddle = ExprResult(false);
|
||||
Diag(Tok, diag::ext_gnu_conditional_expr);
|
||||
}
|
||||
|
||||
if (Tok.getKind() != tok::colon) {
|
||||
Diag(Tok, diag::err_expected_colon);
|
||||
Diag(OpToken, diag::err_matching, "?");
|
||||
return ExprResult(true);
|
||||
}
|
||||
|
||||
// Eat the colon.
|
||||
ColonLoc = ConsumeToken();
|
||||
}
|
||||
|
||||
// Parse another leaf here for the RHS of the operator.
|
||||
ExprResult RHS = ParseCastExpression(false);
|
||||
if (RHS.isInvalid) return RHS;
|
||||
|
||||
// Remember the precedence of this operator and get the precedence of the
|
||||
// operator immediately to the right of the RHS.
|
||||
unsigned ThisPrec = NextTokPrec;
|
||||
NextTokPrec = getBinOpPrecedence(Tok.getKind());
|
||||
|
||||
// Assignment and conditional expressions are right-associative.
|
||||
bool isRightAssoc = NextTokPrec == prec::Conditional ||
|
||||
NextTokPrec == prec::Assignment;
|
||||
|
||||
// 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 < NextTokPrec ||
|
||||
(ThisPrec == NextTokPrec && isRightAssoc)) {
|
||||
// If this is left-associative, only parse things on the RHS that bind
|
||||
// more tightly than the current operator. If it is left-associative, it
|
||||
// is okay, to bind exactly as tightly. For example, compile A=B=C=D as
|
||||
// A=(B=(C=D)), where each paren is a level of recursion here.
|
||||
RHS = ParseRHSOfBinaryExpression(RHS, ThisPrec + !isRightAssoc);
|
||||
if (RHS.isInvalid) return RHS;
|
||||
|
||||
NextTokPrec = getBinOpPrecedence(Tok.getKind());
|
||||
}
|
||||
assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
|
||||
|
||||
// Combine the LHS and RHS into the LHS (e.g. build AST).
|
||||
if (TernaryMiddle.isInvalid)
|
||||
LHS = Actions.ParseBinOp(OpToken.getLocation(), OpToken.getKind(),
|
||||
LHS.Val, RHS.Val);
|
||||
else
|
||||
LHS = Actions.ParseConditionalOp(OpToken.getLocation(), ColonLoc,
|
||||
LHS.Val, TernaryMiddle.Val, RHS.Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
|
||||
/// true, parse a unary-expression.
|
||||
///
|
||||
/// cast-expression: [C99 6.5.4]
|
||||
/// unary-expression
|
||||
/// '(' type-name ')' cast-expression
|
||||
///
|
||||
/// unary-expression: [C99 6.5.3]
|
||||
/// postfix-expression
|
||||
/// '++' unary-expression
|
||||
/// '--' unary-expression
|
||||
/// unary-operator cast-expression
|
||||
/// 'sizeof' unary-expression
|
||||
/// 'sizeof' '(' type-name ')'
|
||||
/// [GNU] '__alignof' unary-expression
|
||||
/// [GNU] '__alignof' '(' type-name ')'
|
||||
/// [GNU] '&&' identifier
|
||||
///
|
||||
/// unary-operator: one of
|
||||
/// '&' '*' '+' '-' '~' '!'
|
||||
/// [GNU] '__extension__' '__real' '__imag'
|
||||
///
|
||||
/// primary-expression: [C99 6.5.1]
|
||||
/// identifier
|
||||
/// constant
|
||||
/// string-literal
|
||||
/// [C++] boolean-literal [C++ 2.13.5]
|
||||
/// '(' expression ')'
|
||||
/// '__func__' [C99 6.4.2.2]
|
||||
/// [GNU] '__FUNCTION__'
|
||||
/// [GNU] '__PRETTY_FUNCTION__'
|
||||
/// [GNU] '(' compound-statement ')'
|
||||
/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')'
|
||||
/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')'
|
||||
/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
|
||||
/// assign-expr ')'
|
||||
/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
|
||||
/// [OBC] '[' objc-receiver objc-message-args ']' [TODO]
|
||||
/// [OBC] '@selector' '(' objc-selector-arg ')' [TODO]
|
||||
/// [OBC] '@protocol' '(' identifier ')' [TODO]
|
||||
/// [OBC] '@encode' '(' type-name ')' [TODO]
|
||||
/// [OBC] objc-string-literal [TODO]
|
||||
/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
||||
/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
||||
/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
||||
/// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
||||
///
|
||||
/// constant: [C99 6.4.4]
|
||||
/// integer-constant
|
||||
/// floating-constant
|
||||
/// enumeration-constant -> identifier
|
||||
/// character-constant
|
||||
///
|
||||
Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
|
||||
ExprResult Res;
|
||||
tok::TokenKind SavedKind = Tok.getKind();
|
||||
|
||||
// This handles all of cast-expression, unary-expression, postfix-expression,
|
||||
// and primary-expression. We handle them together like this for efficiency
|
||||
// and to simplify handling of an expression starting with a '(' token: which
|
||||
// may be one of a parenthesized expression, cast-expression, compound literal
|
||||
// expression, or statement expression.
|
||||
//
|
||||
// If the parsed tokens consist of a primary-expression, the cases below
|
||||
// call ParsePostfixExpressionSuffix to handle the postfix expression
|
||||
// suffixes. Cases that cannot be followed by postfix exprs should
|
||||
// return without invoking ParsePostfixExpressionSuffix.
|
||||
switch (SavedKind) {
|
||||
case tok::l_paren: {
|
||||
// If this expression is limited to being a unary-expression, the parent can
|
||||
// not start a cast expression.
|
||||
ParenParseOption ParenExprType =
|
||||
isUnaryExpression ? CompoundLiteral : CastExpr;
|
||||
TypeTy *CastTy;
|
||||
SourceLocation LParenLoc = Tok.getLocation();
|
||||
SourceLocation RParenLoc;
|
||||
Res = ParseParenExpression(ParenExprType, CastTy, RParenLoc);
|
||||
if (Res.isInvalid) return Res;
|
||||
|
||||
switch (ParenExprType) {
|
||||
case SimpleExpr: break; // Nothing else to do.
|
||||
case CompoundStmt: break; // Nothing else to do.
|
||||
case CompoundLiteral:
|
||||
// We parsed '(' type-name ')' '{' ... '}'. If any suffixes of
|
||||
// postfix-expression exist, parse them now.
|
||||
break;
|
||||
case CastExpr:
|
||||
// We parsed '(' type-name ')' and the thing after it wasn't a '{'. Parse
|
||||
// the cast-expression that follows it next.
|
||||
// TODO: For cast expression with CastTy.
|
||||
Res = ParseCastExpression(false);
|
||||
if (!Res.isInvalid)
|
||||
Res = Actions.ParseCastExpr(LParenLoc, CastTy, RParenLoc, Res.Val);
|
||||
return Res;
|
||||
}
|
||||
|
||||
// These can be followed by postfix-expr pieces.
|
||||
return ParsePostfixExpressionSuffix(Res);
|
||||
}
|
||||
|
||||
// primary-expression
|
||||
case tok::numeric_constant:
|
||||
// constant: integer-constant
|
||||
// constant: floating-constant
|
||||
|
||||
Res = Actions.ParseNumericConstant(Tok);
|
||||
ConsumeToken();
|
||||
|
||||
// These can be followed by postfix-expr pieces.
|
||||
return ParsePostfixExpressionSuffix(Res);
|
||||
|
||||
case tok::kw_true:
|
||||
case tok::kw_false:
|
||||
return ParseCXXBoolLiteral();
|
||||
|
||||
case tok::identifier: { // primary-expression: identifier
|
||||
// constant: enumeration-constant
|
||||
// Consume the identifier so that we can see if it is followed by a '('.
|
||||
// Function designators are allowed to be undeclared (C99 6.5.1p2), so we
|
||||
// need to know whether or not this identifier is a function designator or
|
||||
// not.
|
||||
IdentifierInfo &II = *Tok.getIdentifierInfo();
|
||||
SourceLocation L = ConsumeToken();
|
||||
Res = Actions.ParseIdentifierExpr(CurScope, L, II,
|
||||
Tok.getKind() == tok::l_paren);
|
||||
// These can be followed by postfix-expr pieces.
|
||||
return ParsePostfixExpressionSuffix(Res);
|
||||
}
|
||||
case tok::char_constant: // constant: character-constant
|
||||
Res = Actions.ParseCharacterConstant(Tok);
|
||||
ConsumeToken();
|
||||
// These can be followed by postfix-expr pieces.
|
||||
return ParsePostfixExpressionSuffix(Res);
|
||||
case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
|
||||
case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU]
|
||||
case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU]
|
||||
Res = Actions.ParseSimplePrimaryExpr(Tok.getLocation(), SavedKind);
|
||||
ConsumeToken();
|
||||
// These can be followed by postfix-expr pieces.
|
||||
return ParsePostfixExpressionSuffix(Res);
|
||||
case tok::string_literal: // primary-expression: string-literal
|
||||
case tok::wide_string_literal:
|
||||
Res = ParseStringLiteralExpression();
|
||||
if (Res.isInvalid) return Res;
|
||||
// This can be followed by postfix-expr pieces (e.g. "foo"[1]).
|
||||
return ParsePostfixExpressionSuffix(Res);
|
||||
case tok::kw___builtin_va_arg:
|
||||
case tok::kw___builtin_offsetof:
|
||||
case tok::kw___builtin_choose_expr:
|
||||
case tok::kw___builtin_types_compatible_p:
|
||||
return ParseBuiltinPrimaryExpression();
|
||||
case tok::plusplus: // unary-expression: '++' unary-expression
|
||||
case tok::minusminus: { // unary-expression: '--' unary-expression
|
||||
SourceLocation SavedLoc = ConsumeToken();
|
||||
Res = ParseCastExpression(true);
|
||||
if (!Res.isInvalid)
|
||||
Res = Actions.ParseUnaryOp(SavedLoc, SavedKind, Res.Val);
|
||||
return Res;
|
||||
}
|
||||
case tok::amp: // unary-expression: '&' cast-expression
|
||||
case tok::star: // unary-expression: '*' cast-expression
|
||||
case tok::plus: // unary-expression: '+' cast-expression
|
||||
case tok::minus: // unary-expression: '-' cast-expression
|
||||
case tok::tilde: // unary-expression: '~' cast-expression
|
||||
case tok::exclaim: // unary-expression: '!' cast-expression
|
||||
case tok::kw___real: // unary-expression: '__real' cast-expression [GNU]
|
||||
case tok::kw___imag: // unary-expression: '__imag' cast-expression [GNU]
|
||||
case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU]
|
||||
// FIXME: Extension not handled correctly here!
|
||||
SourceLocation SavedLoc = ConsumeToken();
|
||||
Res = ParseCastExpression(false);
|
||||
if (!Res.isInvalid)
|
||||
Res = Actions.ParseUnaryOp(SavedLoc, SavedKind, Res.Val);
|
||||
return Res;
|
||||
}
|
||||
case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression
|
||||
// unary-expression: 'sizeof' '(' type-name ')'
|
||||
case tok::kw___alignof: // unary-expression: '__alignof' unary-expression
|
||||
// unary-expression: '__alignof' '(' type-name ')'
|
||||
return ParseSizeofAlignofExpression();
|
||||
case tok::ampamp: { // unary-expression: '&&' identifier
|
||||
SourceLocation AmpAmpLoc = ConsumeToken();
|
||||
if (Tok.getKind() != tok::identifier) {
|
||||
Diag(Tok, diag::err_expected_ident);
|
||||
return ExprResult(true);
|
||||
}
|
||||
|
||||
Diag(AmpAmpLoc, diag::ext_gnu_address_of_label);
|
||||
Res = Actions.ParseAddrLabel(AmpAmpLoc, Tok.getLocation(),
|
||||
Tok.getIdentifierInfo());
|
||||
ConsumeToken();
|
||||
return Res;
|
||||
}
|
||||
case tok::kw_const_cast:
|
||||
case tok::kw_dynamic_cast:
|
||||
case tok::kw_reinterpret_cast:
|
||||
case tok::kw_static_cast:
|
||||
return ParseCXXCasts();
|
||||
default:
|
||||
Diag(Tok, diag::err_expected_expression);
|
||||
return ExprResult(true);
|
||||
}
|
||||
|
||||
// unreachable.
|
||||
abort();
|
||||
}
|
||||
|
||||
/// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression
|
||||
/// is parsed, this method parses any suffixes that apply.
|
||||
///
|
||||
/// postfix-expression: [C99 6.5.2]
|
||||
/// primary-expression
|
||||
/// postfix-expression '[' expression ']'
|
||||
/// postfix-expression '(' argument-expression-list[opt] ')'
|
||||
/// postfix-expression '.' identifier
|
||||
/// postfix-expression '->' identifier
|
||||
/// postfix-expression '++'
|
||||
/// postfix-expression '--'
|
||||
/// '(' type-name ')' '{' initializer-list '}'
|
||||
/// '(' type-name ')' '{' initializer-list ',' '}'
|
||||
///
|
||||
/// argument-expression-list: [C99 6.5.2]
|
||||
/// argument-expression
|
||||
/// argument-expression-list ',' assignment-expression
|
||||
///
|
||||
Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
|
||||
// Now that the primary-expression piece of the postfix-expression has been
|
||||
// parsed, see if there are any postfix-expression pieces here.
|
||||
SourceLocation Loc;
|
||||
while (1) {
|
||||
switch (Tok.getKind()) {
|
||||
default: // Not a postfix-expression suffix.
|
||||
return LHS;
|
||||
case tok::l_square: { // postfix-expression: p-e '[' expression ']'
|
||||
Loc = ConsumeBracket();
|
||||
ExprResult Idx = ParseExpression();
|
||||
|
||||
SourceLocation RLoc = Tok.getLocation();
|
||||
|
||||
if (!LHS.isInvalid && !Idx.isInvalid && Tok.getKind() == tok::r_square)
|
||||
LHS = Actions.ParseArraySubscriptExpr(LHS.Val, Loc, Idx.Val, RLoc);
|
||||
else
|
||||
LHS = ExprResult(true);
|
||||
|
||||
// Match the ']'.
|
||||
MatchRHSPunctuation(tok::r_square, Loc);
|
||||
break;
|
||||
}
|
||||
|
||||
case tok::l_paren: { // p-e: p-e '(' argument-expression-list[opt] ')'
|
||||
llvm::SmallVector<ExprTy*, 8> ArgExprs;
|
||||
llvm::SmallVector<SourceLocation, 8> CommaLocs;
|
||||
bool ArgExprsOk = true;
|
||||
|
||||
Loc = ConsumeParen();
|
||||
|
||||
if (Tok.getKind() != tok::r_paren) {
|
||||
while (1) {
|
||||
ExprResult ArgExpr = ParseAssignmentExpression();
|
||||
if (ArgExpr.isInvalid) {
|
||||
ArgExprsOk = false;
|
||||
SkipUntil(tok::r_paren);
|
||||
break;
|
||||
} else
|
||||
ArgExprs.push_back(ArgExpr.Val);
|
||||
|
||||
if (Tok.getKind() != tok::comma)
|
||||
break;
|
||||
// Move to the next argument, remember where the comma was.
|
||||
CommaLocs.push_back(ConsumeToken());
|
||||
}
|
||||
}
|
||||
|
||||
// Match the ')'.
|
||||
if (!LHS.isInvalid && ArgExprsOk && Tok.getKind() == tok::r_paren) {
|
||||
assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&&
|
||||
"Unexpected number of commas!");
|
||||
LHS = Actions.ParseCallExpr(LHS.Val, Loc, &ArgExprs[0], ArgExprs.size(),
|
||||
&CommaLocs[0], Tok.getLocation());
|
||||
}
|
||||
|
||||
if (ArgExprsOk)
|
||||
MatchRHSPunctuation(tok::r_paren, Loc);
|
||||
break;
|
||||
}
|
||||
case tok::arrow: // postfix-expression: p-e '->' identifier
|
||||
case tok::period: { // postfix-expression: p-e '.' identifier
|
||||
tok::TokenKind OpKind = Tok.getKind();
|
||||
SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token.
|
||||
|
||||
if (Tok.getKind() != tok::identifier) {
|
||||
Diag(Tok, diag::err_expected_ident);
|
||||
return ExprResult(true);
|
||||
}
|
||||
|
||||
if (!LHS.isInvalid)
|
||||
LHS = Actions.ParseMemberReferenceExpr(LHS.Val, OpLoc, OpKind,
|
||||
Tok.getLocation(),
|
||||
*Tok.getIdentifierInfo());
|
||||
ConsumeToken();
|
||||
break;
|
||||
}
|
||||
case tok::plusplus: // postfix-expression: postfix-expression '++'
|
||||
case tok::minusminus: // postfix-expression: postfix-expression '--'
|
||||
if (!LHS.isInvalid)
|
||||
LHS = Actions.ParsePostfixUnaryOp(Tok.getLocation(), Tok.getKind(),
|
||||
LHS.Val);
|
||||
ConsumeToken();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// ParseSizeofAlignofExpression - Parse a sizeof or alignof expression.
|
||||
/// unary-expression: [C99 6.5.3]
|
||||
/// 'sizeof' unary-expression
|
||||
/// 'sizeof' '(' type-name ')'
|
||||
/// [GNU] '__alignof' unary-expression
|
||||
/// [GNU] '__alignof' '(' type-name ')'
|
||||
Parser::ExprResult Parser::ParseSizeofAlignofExpression() {
|
||||
assert((Tok.getKind() == tok::kw_sizeof ||
|
||||
Tok.getKind() == tok::kw___alignof) &&
|
||||
"Not a sizeof/alignof expression!");
|
||||
LexerToken OpTok = Tok;
|
||||
ConsumeToken();
|
||||
|
||||
// If the operand doesn't start with an '(', it must be an expression.
|
||||
ExprResult Operand;
|
||||
if (Tok.getKind() != tok::l_paren) {
|
||||
Operand = ParseCastExpression(true);
|
||||
} else {
|
||||
// If it starts with a '(', we know that it is either a parenthesized
|
||||
// type-name, or it is a unary-expression that starts with a compound
|
||||
// literal, or starts with a primary-expression that is a parenthesized
|
||||
// expression.
|
||||
ParenParseOption ExprType = CastExpr;
|
||||
TypeTy *CastTy;
|
||||
SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
|
||||
Operand = ParseParenExpression(ExprType, CastTy, RParenLoc);
|
||||
|
||||
// If ParseParenExpression parsed a '(typename)' sequence only, the this is
|
||||
// sizeof/alignof a type. Otherwise, it is sizeof/alignof an expression.
|
||||
if (ExprType == CastExpr) {
|
||||
return Actions.ParseSizeOfAlignOfTypeExpr(OpTok.getLocation(),
|
||||
OpTok.getKind() == tok::kw_sizeof,
|
||||
LParenLoc, CastTy, RParenLoc);
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, the operand to the sizeof/alignof was an expresion.
|
||||
if (!Operand.isInvalid)
|
||||
Operand = Actions.ParseUnaryOp(OpTok.getLocation(), OpTok.getKind(),
|
||||
Operand.Val);
|
||||
return Operand;
|
||||
}
|
||||
|
||||
/// ParseBuiltinPrimaryExpression
|
||||
///
|
||||
/// primary-expression: [C99 6.5.1]
|
||||
/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')'
|
||||
/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')'
|
||||
/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
|
||||
/// assign-expr ')'
|
||||
/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
|
||||
///
|
||||
/// [GNU] offsetof-member-designator:
|
||||
/// [GNU] identifier
|
||||
/// [GNU] offsetof-member-designator '.' identifier
|
||||
/// [GNU] offsetof-member-designator '[' expression ']'
|
||||
///
|
||||
Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
|
||||
ExprResult Res(false);
|
||||
const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo();
|
||||
|
||||
tok::TokenKind T = Tok.getKind();
|
||||
SourceLocation StartLoc = ConsumeToken(); // Eat the builtin identifier.
|
||||
|
||||
// All of these start with an open paren.
|
||||
if (Tok.getKind() != tok::l_paren) {
|
||||
Diag(Tok, diag::err_expected_lparen_after, BuiltinII->getName());
|
||||
return ExprResult(true);
|
||||
}
|
||||
|
||||
SourceLocation LParenLoc = ConsumeParen();
|
||||
// TODO: Build AST.
|
||||
|
||||
switch (T) {
|
||||
default: assert(0 && "Not a builtin primary expression!");
|
||||
case tok::kw___builtin_va_arg:
|
||||
Res = ParseAssignmentExpression();
|
||||
if (Res.isInvalid) {
|
||||
SkipUntil(tok::r_paren);
|
||||
return Res;
|
||||
}
|
||||
|
||||
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
|
||||
return ExprResult(true);
|
||||
|
||||
ParseTypeName();
|
||||
break;
|
||||
|
||||
case tok::kw___builtin_offsetof:
|
||||
ParseTypeName();
|
||||
|
||||
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
|
||||
return ExprResult(true);
|
||||
|
||||
// We must have at least one identifier here.
|
||||
if (ExpectAndConsume(tok::identifier, diag::err_expected_ident, "",
|
||||
tok::r_paren))
|
||||
return ExprResult(true);
|
||||
|
||||
while (1) {
|
||||
if (Tok.getKind() == tok::period) {
|
||||
// offsetof-member-designator: offsetof-member-designator '.' identifier
|
||||
ConsumeToken();
|
||||
|
||||
if (ExpectAndConsume(tok::identifier, diag::err_expected_ident, "",
|
||||
tok::r_paren))
|
||||
return ExprResult(true);
|
||||
} else if (Tok.getKind() == tok::l_square) {
|
||||
// offsetof-member-designator: offsetof-member-design '[' expression ']'
|
||||
SourceLocation LSquareLoc = ConsumeBracket();
|
||||
Res = ParseExpression();
|
||||
if (Res.isInvalid) {
|
||||
SkipUntil(tok::r_paren);
|
||||
return Res;
|
||||
}
|
||||
|
||||
MatchRHSPunctuation(tok::r_square, LSquareLoc);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case tok::kw___builtin_choose_expr:
|
||||
Res = ParseAssignmentExpression();
|
||||
|
||||
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
|
||||
return ExprResult(true);
|
||||
|
||||
Res = ParseAssignmentExpression();
|
||||
|
||||
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
|
||||
return ExprResult(true);
|
||||
|
||||
Res = ParseAssignmentExpression();
|
||||
break;
|
||||
case tok::kw___builtin_types_compatible_p:
|
||||
ParseTypeName();
|
||||
|
||||
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
|
||||
return ExprResult(true);
|
||||
|
||||
ParseTypeName();
|
||||
break;
|
||||
}
|
||||
|
||||
MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
||||
|
||||
// These can be followed by postfix-expr pieces because they are
|
||||
// primary-expressions.
|
||||
return ParsePostfixExpressionSuffix(Res);
|
||||
}
|
||||
|
||||
/// ParseParenExpression - This parses the unit that starts with a '(' token,
|
||||
/// based on what is allowed by ExprType. The actual thing parsed is returned
|
||||
/// in ExprType.
|
||||
///
|
||||
/// primary-expression: [C99 6.5.1]
|
||||
/// '(' expression ')'
|
||||
/// [GNU] '(' compound-statement ')' (if !ParenExprOnly)
|
||||
/// postfix-expression: [C99 6.5.2]
|
||||
/// '(' type-name ')' '{' initializer-list '}'
|
||||
/// '(' type-name ')' '{' initializer-list ',' '}'
|
||||
/// cast-expression: [C99 6.5.4]
|
||||
/// '(' type-name ')' cast-expression
|
||||
///
|
||||
Parser::ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType,
|
||||
TypeTy *&CastTy,
|
||||
SourceLocation &RParenLoc) {
|
||||
assert(Tok.getKind() == tok::l_paren && "Not a paren expr!");
|
||||
SourceLocation OpenLoc = ConsumeParen();
|
||||
ExprResult Result(false);
|
||||
CastTy = 0;
|
||||
|
||||
if (ExprType >= CompoundStmt && Tok.getKind() == tok::l_brace &&
|
||||
!getLang().NoExtensions) {
|
||||
Diag(Tok, diag::ext_gnu_statement_expr);
|
||||
ParseCompoundStatement();
|
||||
ExprType = CompoundStmt;
|
||||
// TODO: Build AST for GNU compound stmt.
|
||||
} else if (ExprType >= CompoundLiteral && isTypeSpecifierQualifier()) {
|
||||
// Otherwise, this is a compound literal expression or cast expression.
|
||||
TypeTy *Ty = ParseTypeName();
|
||||
|
||||
// Match the ')'.
|
||||
if (Tok.getKind() == tok::r_paren)
|
||||
RParenLoc = ConsumeParen();
|
||||
else
|
||||
MatchRHSPunctuation(tok::r_paren, OpenLoc);
|
||||
|
||||
if (Tok.getKind() == tok::l_brace) {
|
||||
if (!getLang().C99) // Compound literals don't exist in C90.
|
||||
Diag(OpenLoc, diag::ext_c99_compound_literal);
|
||||
Result = ParseInitializer();
|
||||
ExprType = CompoundLiteral;
|
||||
// TODO: Build AST for compound literal.
|
||||
} else if (ExprType == CastExpr) {
|
||||
// Note that this doesn't parse the subsequence cast-expression, it just
|
||||
// returns the parsed type to the callee.
|
||||
ExprType = CastExpr;
|
||||
CastTy = Ty;
|
||||
return ExprResult(false);
|
||||
} else {
|
||||
Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
|
||||
return ExprResult(true);
|
||||
}
|
||||
return Result;
|
||||
} else {
|
||||
Result = ParseExpression();
|
||||
ExprType = SimpleExpr;
|
||||
if (!Result.isInvalid && Tok.getKind() == tok::r_paren)
|
||||
Result = Actions.ParseParenExpr(OpenLoc, Tok.getLocation(), Result.Val);
|
||||
}
|
||||
|
||||
// Match the ')'.
|
||||
if (Result.isInvalid)
|
||||
SkipUntil(tok::r_paren);
|
||||
else {
|
||||
if (Tok.getKind() == tok::r_paren)
|
||||
RParenLoc = ConsumeParen();
|
||||
else
|
||||
MatchRHSPunctuation(tok::r_paren, OpenLoc);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// ParseStringLiteralExpression - This handles the various token types that
|
||||
/// form string literals, and also handles string concatenation [C99 5.1.1.2,
|
||||
/// translation phase #6].
|
||||
///
|
||||
/// primary-expression: [C99 6.5.1]
|
||||
/// string-literal
|
||||
Parser::ExprResult Parser::ParseStringLiteralExpression() {
|
||||
assert(isTokenStringLiteral() && "Not a string literal!");
|
||||
|
||||
// String concat. Note that keywords like __func__ and __FUNCTION__ are not
|
||||
// considered to be strings for concatenation purposes.
|
||||
llvm::SmallVector<LexerToken, 4> StringToks;
|
||||
|
||||
do {
|
||||
StringToks.push_back(Tok);
|
||||
ConsumeStringToken();
|
||||
} while (isTokenStringLiteral());
|
||||
|
||||
// Pass the set of string tokens, ready for concatenation, to the actions.
|
||||
return Actions.ParseStringLiteral(&StringToks[0], StringToks.size());
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
//===--- 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);
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
//===--- 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"
|
||||
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.
|
||||
LexerToken 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);
|
||||
else {
|
||||
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) {
|
||||
SkipUntil(tok::r_brace);
|
||||
return SubElt;
|
||||
}
|
||||
|
||||
// If we don't have a comma continued list, we're done.
|
||||
if (Tok.getKind() != tok::comma) break;
|
||||
ConsumeToken();
|
||||
|
||||
// Handle trailing comma.
|
||||
if (Tok.getKind() == tok::r_brace) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Match the '}'.
|
||||
MatchRHSPunctuation(tok::r_brace, LBraceLoc);
|
||||
return ExprResult(false);
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
//===--- ParseObjc.cpp - Objective C Parsing ------------------------------===//
|
||||
//
|
||||
// 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 Objective-C portions of the Parser interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Parse/Parser.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
using namespace clang;
|
||||
|
||||
|
||||
/// ParseExternalDeclaration:
|
||||
/// external-declaration: [C99 6.9]
|
||||
/// [OBJC] objc-class-definition
|
||||
/// [OBJC] objc-class-declaration [TODO]
|
||||
/// [OBJC] objc-alias-declaration [TODO]
|
||||
/// [OBJC] objc-protocol-definition [TODO]
|
||||
/// [OBJC] objc-method-definition [TODO]
|
||||
/// [OBJC] '@' 'end' [TODO]
|
||||
void Parser::ParseObjCAtDirectives() {
|
||||
SourceLocation AtLoc = ConsumeToken(); // the "@"
|
||||
|
||||
IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
switch (II ? II->getObjCKeywordID() : tok::objc_not_keyword) {
|
||||
case tok::objc_class:
|
||||
return ParseObjCAtClassDeclaration(AtLoc);
|
||||
case tok::objc_interface:
|
||||
return ParseObjCAtInterfaceDeclaration();
|
||||
case tok::objc_protocol:
|
||||
return ParseObjCAtProtocolDeclaration();
|
||||
case tok::objc_implementation:
|
||||
return ParseObjCAtImplementationDeclaration();
|
||||
case tok::objc_end:
|
||||
return ParseObjCAtEndDeclaration();
|
||||
case tok::objc_compatibility_alias:
|
||||
return ParseObjCAtAliasDeclaration();
|
||||
default:
|
||||
Diag(AtLoc, diag::err_unexpected_at);
|
||||
SkipUntil(tok::semi);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// objc-class-declaration:
|
||||
/// '@' 'class' identifier-list ';'
|
||||
///
|
||||
void Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
|
||||
ConsumeToken(); // the identifier "class"
|
||||
llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
|
||||
|
||||
while (1) {
|
||||
if (Tok.getKind() != tok::identifier) {
|
||||
Diag(Tok, diag::err_expected_ident);
|
||||
SkipUntil(tok::semi);
|
||||
return;
|
||||
}
|
||||
|
||||
ClassNames.push_back(Tok.getIdentifierInfo());
|
||||
ConsumeToken();
|
||||
|
||||
if (Tok.getKind() != tok::comma)
|
||||
break;
|
||||
|
||||
ConsumeToken();
|
||||
}
|
||||
|
||||
// Consume the ';'.
|
||||
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
|
||||
return;
|
||||
|
||||
Actions.ParsedObjcClassDeclaration(CurScope,
|
||||
&ClassNames[0], ClassNames.size());
|
||||
}
|
||||
|
||||
void Parser::ParseObjCAtInterfaceDeclaration() {
|
||||
assert(0 && "Unimp");
|
||||
}
|
||||
void Parser::ParseObjCAtProtocolDeclaration() {
|
||||
assert(0 && "Unimp");
|
||||
}
|
||||
void Parser::ParseObjCAtImplementationDeclaration() {
|
||||
assert(0 && "Unimp");
|
||||
}
|
||||
void Parser::ParseObjCAtEndDeclaration() {
|
||||
assert(0 && "Unimp");
|
||||
}
|
||||
void Parser::ParseObjCAtAliasDeclaration() {
|
||||
assert(0 && "Unimp");
|
||||
}
|
||||
|
||||
void Parser::ParseObjCInstanceMethodDeclaration() {
|
||||
assert(0 && "Unimp");
|
||||
}
|
||||
|
||||
void Parser::ParseObjCClassMethodDeclaration() {
|
||||
assert(0 && "Unimp");
|
||||
}
|
|
@ -0,0 +1,848 @@
|
|||
//===--- 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()) {
|
||||
// TODO: warn/disable if declaration is in the middle of a block and !C99.
|
||||
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!");
|
||||
|
||||
LexerToken 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);
|
||||
|
||||
// TODO: look up enclosing switch stmt.
|
||||
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;
|
||||
|
||||
// TODO: look up enclosing switch stmt.
|
||||
return Actions.ParseDefaultStmt(DefaultLoc, ColonLoc, SubStmt.Val);
|
||||
}
|
||||
|
||||
|
||||
/// 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 [TODO]
|
||||
/// 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() {
|
||||
assert(Tok.getKind() == tok::l_brace && "Not a compount stmt!");
|
||||
|
||||
// Enter a scope to hold everything within the compound stmt.
|
||||
EnterScope(0);
|
||||
|
||||
// Parse the statements in the body.
|
||||
StmtResult Body = ParseCompoundStatementBody();
|
||||
|
||||
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() {
|
||||
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.
|
||||
|
||||
llvm::SmallVector<StmtTy*, 32> Stmts;
|
||||
while (Tok.getKind() != tok::r_brace && Tok.getKind() != tok::eof) {
|
||||
StmtResult R = ParseStatementOrDeclaration(false);
|
||||
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());
|
||||
}
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
// Parse the condition.
|
||||
ExprResult CondExp = ParseSimpleParenExpression();
|
||||
if (CondExp.isInvalid) {
|
||||
SkipUntil(tok::semi);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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());
|
||||
|
||||
|
||||
// If it has an else, parse it.
|
||||
SourceLocation ElseLoc;
|
||||
StmtResult ElseStmt(false);
|
||||
if (Tok.getKind() == tok::kw_else) {
|
||||
ElseLoc = ConsumeToken();
|
||||
ElseStmt = ParseStatement();
|
||||
|
||||
if (ElseStmt.isInvalid)
|
||||
ElseStmt = Actions.ParseNullStmt(ElseLoc);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Start the switch scope.
|
||||
EnterScope(Scope::BreakScope);
|
||||
|
||||
// Parse the condition.
|
||||
ExprResult Cond = ParseSimpleParenExpression();
|
||||
|
||||
// Read the body statement.
|
||||
StmtResult Body = ParseStatement();
|
||||
|
||||
ExitScope();
|
||||
|
||||
if (Cond.isInvalid || Body.isInvalid) return true;
|
||||
|
||||
return Actions.ParseSwitchStmt(SwitchLoc, Cond.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;
|
||||
}
|
||||
|
||||
// Start the loop scope.
|
||||
EnterScope(Scope::BreakScope | Scope::ContinueScope);
|
||||
|
||||
// Parse the condition.
|
||||
ExprResult Cond = ParseSimpleParenExpression();
|
||||
|
||||
// Read the body statement.
|
||||
StmtResult Body = ParseStatement();
|
||||
|
||||
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'.
|
||||
|
||||
// Start the loop scope.
|
||||
EnterScope(Scope::BreakScope | Scope::ContinueScope);
|
||||
|
||||
// Read the body statement.
|
||||
StmtResult Body = ParseStatement();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Read the body statement.
|
||||
StmtResult Body = ParseStatement();
|
||||
|
||||
// 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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,615 @@
|
|||
//===--- 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;
|
||||
|
||||
ParenCount = BracketCount = BraceCount = 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 false). 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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// ScopeCache - Cache scopes to avoid malloc traffic.
|
||||
/// FIXME: eliminate this static ctor
|
||||
static llvm::SmallVector<Scope*, 16> ScopeCache;
|
||||
|
||||
/// EnterScope - Start a new scope.
|
||||
void Parser::EnterScope(unsigned ScopeFlags) {
|
||||
if (!ScopeCache.empty()) {
|
||||
Scope *N = ScopeCache.back();
|
||||
ScopeCache.pop_back();
|
||||
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 *Old = CurScope;
|
||||
CurScope = Old->getParent();
|
||||
|
||||
if (ScopeCache.size() == 16)
|
||||
delete Old;
|
||||
else
|
||||
ScopeCache.push_back(Old);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// C99 6.9: External Definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
Parser::~Parser() {
|
||||
// If we still have scopes active, delete the scope tree.
|
||||
delete CurScope;
|
||||
|
||||
// Free the scope cache.
|
||||
while (!ScopeCache.empty()) {
|
||||
delete ScopeCache.back();
|
||||
ScopeCache.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize - Warm up the parser.
|
||||
///
|
||||
void Parser::Initialize() {
|
||||
// Prime the lexer look-ahead.
|
||||
ConsumeToken();
|
||||
|
||||
// Create the global scope, install it as the current scope.
|
||||
assert(CurScope == 0 && "A scope is already active?");
|
||||
EnterScope(0);
|
||||
|
||||
|
||||
// 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, 0);
|
||||
}
|
||||
|
||||
if (Tok.getKind() == tok::eof) // Empty source file is an extension.
|
||||
Diag(Tok, diag::ext_empty_source_file);
|
||||
}
|
||||
|
||||
/// 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 [TODO]
|
||||
/// declaration [TODO]
|
||||
/// [EXT] ';'
|
||||
/// [GNU] asm-definition
|
||||
/// [GNU] __extension__ external-declaration [TODO]
|
||||
/// [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_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.
|
||||
ParseObjCAtDirectives();
|
||||
return 0;
|
||||
case tok::minus:
|
||||
if (getLang().ObjC1) {
|
||||
ParseObjCInstanceMethodDeclaration();
|
||||
} else {
|
||||
Diag(Tok, diag::err_expected_external_declaration);
|
||||
ConsumeToken();
|
||||
}
|
||||
return 0;
|
||||
case tok::plus:
|
||||
if (getLang().ObjC1) {
|
||||
ParseObjCClassMethodDeclaration();
|
||||
} else {
|
||||
Diag(Tok, diag::err_expected_external_declaration);
|
||||
ConsumeToken();
|
||||
}
|
||||
return 0;
|
||||
case tok::kw_typedef:
|
||||
// A function definition cannot start with a 'typedef' keyword.
|
||||
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 [TODO]
|
||||
/// declaration: [C99 6.7]
|
||||
/// declaration-specifiers init-declarator-list[opt] ';' [TODO]
|
||||
/// [!C99] init-declarator-list ';' [TODO]
|
||||
/// [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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
// 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, 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 the default mode.
|
||||
|
||||
* -E mode gives output nearly identical to GCC, though not all bugs in
|
||||
whitespace calculation have been emulated (e.g. the number of blank lines
|
||||
emitted).
|
||||
|
||||
* -fsyntax-only is currently partially implemented, lacking some semantic
|
||||
analysis.
|
||||
|
||||
* -Eonly mode does all preprocessing, but does not print the output, useful for
|
||||
timing the preprocessor.
|
||||
|
||||
* -parse-print-callbacks prints almost no callbacks so far.
|
||||
|
||||
* -parse-ast builds ASTs, but doesn't print them. This is most useful for
|
||||
timing AST building vs -parse-noop.
|
||||
|
||||
* -parse-ast-print prints most expression and statements nodes, but some
|
||||
minor things are missing.
|
||||
|
||||
* -parse-ast-check checks that diagnostic messages that are expected are
|
||||
reported and that those which are reported are expected.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
IV. Missing Functionality / Improvements
|
||||
|
||||
clang driver:
|
||||
* Include search paths are hard-coded into the driver.
|
||||
|
||||
File Manager:
|
||||
* Reduce syscalls, 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:
|
||||
* All.
|
||||
|
||||
Parser:
|
||||
* C90/K&R modes are only partially implemented.
|
||||
* __extension__, __attribute__ [currently just skipped and ignored].
|
||||
* "initializers", GCC inline asm.
|
||||
|
||||
Semantic Analysis:
|
||||
* Perhaps 75% done.
|
||||
|
||||
Code Gen:
|
||||
* Mostly missing.
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
//===--- 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);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
##===- 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
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
//===--- 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) {
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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();
|
||||
}
|
|
@ -0,0 +1,353 @@
|
|||
//===--- 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 <vector>
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class Preprocessor;
|
||||
class Decl;
|
||||
class Expr;
|
||||
class VarDecl;
|
||||
class ParmVarDecl;
|
||||
class TypedefDecl;
|
||||
class FunctionDecl;
|
||||
class QualType;
|
||||
class LangOptions;
|
||||
class DeclaratorChunk;
|
||||
class LexerToken;
|
||||
class IntegerLiteral;
|
||||
class ArrayType;
|
||||
class LabelStmt;
|
||||
|
||||
/// 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;
|
||||
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);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// 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, ExprTy *Init,
|
||||
DeclTy *LastInGroup);
|
||||
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);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// 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);
|
||||
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);
|
||||
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 ParseSwitchStmt(SourceLocation SwitchLoc, ExprTy *Cond,
|
||||
StmtTy *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 ParseSimplePrimaryExpr(SourceLocation Loc,
|
||||
tok::TokenKind Kind);
|
||||
virtual ExprResult ParseNumericConstant(const LexerToken &);
|
||||
virtual ExprResult ParseCharacterConstant(const LexerToken &);
|
||||
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 LexerToken *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 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);
|
||||
|
||||
/// 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);
|
||||
private:
|
||||
// UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts
|
||||
// functions and arrays to their respective pointers (C99 6.3.2.1)
|
||||
QualType UsualUnaryConversions(QualType t);
|
||||
// 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(QualType &t1, QualType &t2);
|
||||
// DefaultFunctionArrayConversion - converts functions and arrays
|
||||
// to their respective pointers (C99 6.3.2.1). If the type isn't a function
|
||||
// or array, this routine simply returns the input type (unmodified).
|
||||
QualType DefaultFunctionArrayConversion(QualType t);
|
||||
|
||||
enum AssignmentCheckResult {
|
||||
Compatible,
|
||||
Incompatible,
|
||||
PointerFromInt,
|
||||
IntFromPointer,
|
||||
IncompatiblePointer,
|
||||
CompatiblePointerDiscardsQualifiers
|
||||
};
|
||||
// CheckAssignmentConstraints - conversions for assignment, argument passing,
|
||||
// variable initialization, and function return values. Currently used by
|
||||
// CheckAssignmentOperands, ParseCallExpr, and ParseReturnStmt. C99 6.5.16.
|
||||
AssignmentCheckResult CheckAssignmentConstraints(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);
|
||||
inline QualType CheckRemainderOperands( // C99 6.5.5
|
||||
Expr *lex, Expr *rex, SourceLocation OpLoc);
|
||||
inline QualType CheckAdditionOperands( // C99 6.5.6
|
||||
Expr *lex, Expr *rex, SourceLocation OpLoc);
|
||||
inline QualType CheckSubtractionOperands( // C99 6.5.6
|
||||
Expr *lex, Expr *rex, SourceLocation OpLoc);
|
||||
inline QualType CheckShiftOperands( // C99 6.5.7
|
||||
Expr *lex, Expr *rex, SourceLocation OpLoc);
|
||||
inline QualType CheckRelationalOperands( // C99 6.5.8
|
||||
Expr *lex, Expr *rex, SourceLocation OpLoc);
|
||||
inline QualType CheckEqualityOperands( // C99 6.5.9
|
||||
Expr *lex, Expr *rex, SourceLocation OpLoc);
|
||||
inline QualType CheckBitwiseOperands( // C99 6.5.[10...12]
|
||||
Expr *lex, Expr *rex, SourceLocation OpLoc);
|
||||
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);
|
||||
|
||||
/// C99: 6.7.5p3: Used by ParseDeclarator/ParseField to make sure we have
|
||||
/// a constant expression of type int with a value greater than zero. If the
|
||||
/// array has an incomplete type or a valid constant size, return false,
|
||||
/// otherwise emit a diagnostic and return true.
|
||||
bool VerifyConstantArrayType(const ArrayType *ary, SourceLocation loc);
|
||||
};
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,44 @@
|
|||
//===--- 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"
|
||||
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, OpLoc);
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
//===--- 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/Stmt.h"
|
||||
#include "clang/AST/Expr.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);
|
||||
|
||||
// Exprs are statements, so there is no need to do a conversion here. However,
|
||||
// diagnose some potentially bad code.
|
||||
if (!E->hasLocalSideEffect())
|
||||
Diag(E->getExprLoc(), diag::warn_unused_expr, E->getSourceRange());
|
||||
|
||||
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) {
|
||||
return new CompoundStmt((Stmt**)Elts, NumElts);
|
||||
}
|
||||
|
||||
Action::StmtResult
|
||||
Sema::ParseCaseStmt(SourceLocation CaseLoc, ExprTy *lhsval,
|
||||
SourceLocation DotDotDotLoc, ExprTy *RHSVal,
|
||||
SourceLocation ColonLoc, StmtTy *SubStmt) {
|
||||
Expr *LHSVal = ((Expr *)lhsval);
|
||||
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(&ExpLoc))
|
||||
return Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr,
|
||||
LHSVal->getSourceRange());
|
||||
|
||||
// FIXME: SEMA for RHS of case range.
|
||||
|
||||
return new CaseStmt(LHSVal, (Expr*)RHSVal, (Stmt*)SubStmt);
|
||||
}
|
||||
|
||||
Action::StmtResult
|
||||
Sema::ParseDefaultStmt(SourceLocation DefaultLoc,
|
||||
SourceLocation ColonLoc, StmtTy *SubStmt) {
|
||||
return new DefaultStmt((Stmt*)SubStmt);
|
||||
}
|
||||
|
||||
Action::StmtResult
|
||||
Sema::ParseLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
|
||||
SourceLocation ColonLoc, StmtTy *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, (Stmt*)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 (Stmt*)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((Stmt*)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");
|
||||
|
||||
QualType condType = DefaultFunctionArrayConversion(condExpr->getType());
|
||||
assert(!condType.isNull() && "ParseIfStmt(): missing expression type");
|
||||
|
||||
if (!condType->isScalarType()) // C99 6.8.4.1p1
|
||||
return Diag(IfLoc, diag::err_typecheck_statement_requires_scalar,
|
||||
condType.getAsString(), condExpr->getSourceRange());
|
||||
|
||||
return new IfStmt(condExpr, (Stmt*)ThenVal, (Stmt*)ElseVal);
|
||||
}
|
||||
|
||||
Action::StmtResult
|
||||
Sema::ParseSwitchStmt(SourceLocation SwitchLoc, ExprTy *Cond, StmtTy *Body) {
|
||||
return new SwitchStmt((Expr*)Cond, (Stmt*)Body);
|
||||
}
|
||||
|
||||
Action::StmtResult
|
||||
Sema::ParseWhileStmt(SourceLocation WhileLoc, ExprTy *Cond, StmtTy *Body) {
|
||||
Expr *condExpr = (Expr *)Cond;
|
||||
assert(condExpr && "ParseWhileStmt(): missing expression");
|
||||
|
||||
QualType condType = DefaultFunctionArrayConversion(condExpr->getType());
|
||||
assert(!condType.isNull() && "ParseWhileStmt(): missing expression type");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Action::StmtResult
|
||||
Sema::ParseDoStmt(SourceLocation DoLoc, StmtTy *Body,
|
||||
SourceLocation WhileLoc, ExprTy *Cond) {
|
||||
Expr *condExpr = (Expr *)Cond;
|
||||
assert(condExpr && "ParseDoStmt(): missing expression");
|
||||
|
||||
QualType condType = DefaultFunctionArrayConversion(condExpr->getType());
|
||||
assert(!condType.isNull() && "ParseDoStmt(): missing expression type");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Action::StmtResult
|
||||
Sema::ParseForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
|
||||
StmtTy *First, ExprTy *Second, ExprTy *Third,
|
||||
SourceLocation RParenLoc, StmtTy *Body) {
|
||||
if (First) {
|
||||
// C99 6.8.5p3: FIXME. Need to hack Parser::ParseForStatement() and
|
||||
// declaration support to create a DeclStmt node. Once this is done,
|
||||
// we can test for DeclStmt vs. Expr (already a sub-class of Stmt).
|
||||
}
|
||||
if (Second) {
|
||||
Expr *testExpr = (Expr *)Second;
|
||||
QualType testType = DefaultFunctionArrayConversion(testExpr->getType());
|
||||
assert(!testType.isNull() && "ParseForStmt(): missing test expression type");
|
||||
|
||||
if (!testType->isScalarType()) // C99 6.8.5p2
|
||||
return Diag(ForLoc, diag::err_typecheck_statement_requires_scalar,
|
||||
testType.getAsString(), testExpr->getSourceRange());
|
||||
}
|
||||
return new ForStmt((Stmt*)First, (Expr*)Second, (Expr*)Third, (Stmt*)Body);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// FIXME: Remember that this continue goes with this loop.
|
||||
return new ContinueStmt();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// FIXME: Remember that this break goes with this loop/switch.
|
||||
return new BreakStmt();
|
||||
}
|
||||
|
||||
|
||||
Action::StmtResult
|
||||
Sema::ParseReturnStmt(SourceLocation ReturnLoc, ExprTy *RetValExp) {
|
||||
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(),
|
||||
((Expr *)RetValExp)->getSourceRange());
|
||||
return new ReturnStmt((Expr*)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((Expr*)0);
|
||||
}
|
||||
}
|
||||
// we have a non-void function with an expression, continue checking
|
||||
QualType rhsType = ((Expr *)RetValExp)->getType();
|
||||
|
||||
if (lhsType == rhsType) // common case, fast path...
|
||||
return new ReturnStmt((Expr*)RetValExp);
|
||||
|
||||
// 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 = CheckAssignmentConstraints(lhsType, rhsType);
|
||||
bool hadError = false;
|
||||
|
||||
// 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(),
|
||||
((Expr *)RetValExp)->getSourceRange());
|
||||
hadError = true;
|
||||
break;
|
||||
case PointerFromInt:
|
||||
// check for null pointer constant (C99 6.3.2.3p3)
|
||||
if (!((Expr *)RetValExp)->isNullPointerConstant()) {
|
||||
Diag(ReturnLoc, diag::ext_typecheck_return_pointer_int,
|
||||
lhsType.getAsString(), rhsType.getAsString(),
|
||||
((Expr *)RetValExp)->getSourceRange());
|
||||
}
|
||||
break;
|
||||
case IntFromPointer:
|
||||
Diag(ReturnLoc, diag::ext_typecheck_return_pointer_int,
|
||||
lhsType.getAsString(), rhsType.getAsString(),
|
||||
((Expr *)RetValExp)->getSourceRange());
|
||||
break;
|
||||
case IncompatiblePointer:
|
||||
Diag(ReturnLoc, diag::ext_typecheck_return_incompatible_pointer,
|
||||
lhsType.getAsString(), rhsType.getAsString(),
|
||||
((Expr *)RetValExp)->getSourceRange());
|
||||
break;
|
||||
case CompatiblePointerDiscardsQualifiers:
|
||||
Diag(ReturnLoc, diag::ext_typecheck_return_discards_qualifiers,
|
||||
lhsType.getAsString(), rhsType.getAsString(),
|
||||
((Expr *)RetValExp)->getSourceRange());
|
||||
break;
|
||||
}
|
||||
return new ReturnStmt((Expr*)RetValExp);
|
||||
}
|
||||
|
|
@ -0,0 +1,262 @@
|
|||
//===--- 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"
|
||||
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_int:
|
||||
if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) {
|
||||
switch (DS.getTypeSpecWidth()) {
|
||||
case DeclSpec::TSW_unspecified: return Ctx.IntTy;
|
||||
case DeclSpec::TSW_short: return Ctx.ShortTy;
|
||||
case DeclSpec::TSW_long: return Ctx.LongTy;
|
||||
case DeclSpec::TSW_longlong: return Ctx.LongLongTy;
|
||||
}
|
||||
} else {
|
||||
switch (DS.getTypeSpecWidth()) {
|
||||
case DeclSpec::TSW_unspecified: return Ctx.UnsignedIntTy;
|
||||
case DeclSpec::TSW_short: return Ctx.UnsignedShortTy;
|
||||
case DeclSpec::TSW_long: return Ctx.UnsignedLongTy;
|
||||
case DeclSpec::TSW_longlong: return Ctx.UnsignedLongLongTy;
|
||||
}
|
||||
}
|
||||
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.FloatComplexTy;
|
||||
|
||||
case DeclSpec::TST_double: {
|
||||
bool isLong = DS.getTypeSpecWidth() == DeclSpec::TSW_long;
|
||||
if (DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified)
|
||||
return isLong ? Ctx.LongDoubleTy : Ctx.DoubleTy;
|
||||
assert(DS.getTypeSpecComplex() == DeclSpec::TSC_complex &&
|
||||
"FIXME: imaginary types not supported yet!");
|
||||
return isLong ? Ctx.LongDoubleComplexTy : Ctx.DoubleComplexTy;
|
||||
}
|
||||
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!");
|
||||
// TypeQuals handled by caller.
|
||||
return Ctx.getTypedefType(cast<TypedefDecl>(D));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// GetTypeForDeclarator - Convert the type for the specified declarator to Type
|
||||
/// instances.
|
||||
QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
|
||||
QualType T = ConvertDeclSpecToType(D.getDeclSpec(), Context);
|
||||
|
||||
// If there was an error parsing declspecs, return a null type pointer.
|
||||
if (T.isNull()) return T;
|
||||
|
||||
// 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 (isa<ReferenceType>(T.getCanonicalType().getTypePtr())) {
|
||||
// C++ 8.3.2p4: There shall be no ... pointers to references ...
|
||||
Diag(D.getIdentifierLoc(), diag::err_illegal_decl_pointer_to_reference,
|
||||
D.getIdentifier()->getName());
|
||||
return QualType();
|
||||
}
|
||||
|
||||
// Apply the pointer typequals to the pointer object.
|
||||
T = Context.getPointerType(T).getQualifiedType(DeclType.Ptr.TypeQuals);
|
||||
break;
|
||||
case DeclaratorChunk::Reference:
|
||||
if (isa<ReferenceType>(T.getCanonicalType().getTypePtr())) {
|
||||
// C++ 8.3.2p4: There shall be no references to references ...
|
||||
Diag(D.getIdentifierLoc(),
|
||||
diag::err_illegal_decl_reference_to_reference,
|
||||
D.getIdentifier()->getName());
|
||||
return QualType();
|
||||
}
|
||||
|
||||
T = Context.getReferenceType(T);
|
||||
break;
|
||||
case DeclaratorChunk::Array: {
|
||||
const DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr;
|
||||
ArrayType::ArraySizeModifier ASM;
|
||||
if (ATI.isStar)
|
||||
ASM = ArrayType::Star;
|
||||
else if (ATI.hasStatic)
|
||||
ASM = ArrayType::Static;
|
||||
else
|
||||
ASM = ArrayType::Normal;
|
||||
|
||||
Type *CanonicalT = T.getCanonicalType().getTypePtr();
|
||||
|
||||
// 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());
|
||||
return QualType();
|
||||
} else if (isa<FunctionType>(CanonicalT)) {
|
||||
Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_functions,
|
||||
D.getIdentifier()->getName());
|
||||
return QualType();
|
||||
} else if (isa<ReferenceType>(CanonicalT)) {
|
||||
// C++ 8.3.2p4: There shall be no ... arrays of references ...
|
||||
Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_references,
|
||||
D.getIdentifier()->getName());
|
||||
return QualType();
|
||||
} else if (RecordType *EltTy = dyn_cast<RecordType>(CanonicalT)) {
|
||||
// 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());
|
||||
return QualType();
|
||||
}
|
||||
}
|
||||
T = Context.getArrayType(T, ASM, ATI.TypeQuals,
|
||||
static_cast<Expr *>(ATI.NumElts));
|
||||
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);
|
||||
if (ArgTy.isNull())
|
||||
return QualType(); // Error occurred parsing argument type.
|
||||
|
||||
// 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.
|
||||
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);
|
||||
return QualType();
|
||||
}
|
||||
// Reject, but continue to parse 'int(void abc)'.
|
||||
if (FTI.ArgInfo[i].Ident)
|
||||
Diag(FTI.ArgInfo[i].IdentLoc,
|
||||
diag::err_void_param_with_identifier);
|
||||
|
||||
// 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);
|
||||
|
||||
// If the type of the declarator was invalid, this is an invalid typename.
|
||||
if (T.isNull())
|
||||
return true;
|
||||
|
||||
return T.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// If the type of the declarator was invalid, this is an invalid typename.
|
||||
if (T.isNull())
|
||||
return true;
|
||||
|
||||
return T.getAsOpaquePtr();
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//===---------------------------------------------------------------------===//
|
||||
// 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;
|
||||
^
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
|
|
@ -0,0 +1,781 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 42;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1A30A9E90B93A4C800201A91 /* ExprCXX.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A30A9E80B93A4C800201A91 /* ExprCXX.h */; };
|
||||
1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */; };
|
||||
1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.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 */; };
|
||||
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 */; };
|
||||
DE345C570AFC69E800DBC861 /* StmtVisitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE345C560AFC69E800DBC861 /* StmtVisitor.cpp */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
DED7D74B0A524295003AD0FB /* LexerToken.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D73C0A524295003AD0FB /* LexerToken.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 */; };
|
||||
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 */,
|
||||
DED7D74B0A524295003AD0FB /* LexerToken.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 */,
|
||||
);
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
DE345C560AFC69E800DBC861 /* StmtVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StmtVisitor.cpp; path = AST/StmtVisitor.cpp; 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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
DED7D73C0A524295003AD0FB /* LexerToken.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LexerToken.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>"; };
|
||||
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 */,
|
||||
);
|
||||
name = Source;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1AB674ADFE9D54B511CA2CBB /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8DD76F6C0486A84900D96B5E /* clang */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C6859E8C029090F304C91782 /* Documentation */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DEAEED4A0A5AF89A0045101B /* NOTES.txt */,
|
||||
DED7D7D70A524302003AD0FB /* README.txt */,
|
||||
DEEBBD430C19C5D200A9FE82 /* TODO.txt */,
|
||||
);
|
||||
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 */,
|
||||
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 */,
|
||||
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 */,
|
||||
DE4264FB0C113592005A861D /* CGDecl.cpp */,
|
||||
DE4772FB0C10EAEC002239E8 /* CGExpr.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 */,
|
||||
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 */,
|
||||
DEC8D9900A9433CD00353FCA /* Decl.h */,
|
||||
DE0FCA620A95859D00248FD5 /* Expr.h */,
|
||||
1A30A9E80B93A4C800201A91 /* ExprCXX.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 */,
|
||||
DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */,
|
||||
DE0FCB330A9C21F100248FD5 /* Expr.cpp */,
|
||||
DE3452400AEF1A2D00DBC861 /* Stmt.cpp */,
|
||||
DE75EDF00B06880E0020CF81 /* Type.cpp */,
|
||||
DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */,
|
||||
DE345C560AFC69E800DBC861 /* StmtVisitor.cpp */,
|
||||
);
|
||||
name = AST;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DED7D72E0A524295003AD0FB /* include */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DED7D7300A524295003AD0FB /* Basic */,
|
||||
DED7D7390A524295003AD0FB /* Lex */,
|
||||
DE1F21F20A7D84E800FBF588 /* Parse */,
|
||||
DEC8D98B0A9433BC00353FCA /* AST */,
|
||||
DE67E7260C02108300F66BC5 /* Sema */,
|
||||
DE928B140C05659A00231DA4 /* CodeGen */,
|
||||
);
|
||||
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 */,
|
||||
DED7D73C0A524295003AD0FB /* LexerToken.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 */,
|
||||
);
|
||||
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 = "";
|
||||
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 */,
|
||||
DE345C570AFC69E800DBC861 /* StmtVisitor.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 */,
|
||||
);
|
||||
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 */;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
//===--- AST.h - "Umbrella" header for AST library --------------*- 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 interface to the AST classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_AST_H
|
||||
#define LLVM_CLANG_AST_AST_H
|
||||
|
||||
// This header exports all AST interfaces.
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,128 @@
|
|||
//===--- ASTContext.h - Context to hold long-lived AST nodes ----*- 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 ASTContext interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_ASTCONTEXT_H
|
||||
#define LLVM_CLANG_AST_ASTCONTEXT_H
|
||||
|
||||
#include "clang/AST/Builtins.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
class TargetInfo;
|
||||
|
||||
/// ASTContext - This class holds long-lived AST nodes (such as types and
|
||||
/// decls) that can be referred to throughout the semantic analysis of a file.
|
||||
class ASTContext {
|
||||
std::vector<Type*> Types;
|
||||
llvm::FoldingSet<ComplexType> ComplexTypes;
|
||||
llvm::FoldingSet<PointerType> PointerTypes;
|
||||
llvm::FoldingSet<ReferenceType> ReferenceTypes;
|
||||
llvm::FoldingSet<ArrayType> ArrayTypes;
|
||||
llvm::FoldingSet<VectorType> VectorTypes;
|
||||
llvm::FoldingSet<FunctionTypeNoProto> FunctionTypeNoProtos;
|
||||
llvm::FoldingSet<FunctionTypeProto> FunctionTypeProtos;
|
||||
public:
|
||||
TargetInfo &Target;
|
||||
Builtin::Context BuiltinInfo;
|
||||
|
||||
// Builtin Types.
|
||||
QualType VoidTy;
|
||||
QualType BoolTy;
|
||||
QualType CharTy;
|
||||
QualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy;
|
||||
QualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy;
|
||||
QualType UnsignedLongLongTy;
|
||||
QualType FloatTy, DoubleTy, LongDoubleTy;
|
||||
QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
|
||||
|
||||
ASTContext(TargetInfo &t, IdentifierTable &idents) : Target(t) {
|
||||
InitBuiltinTypes();
|
||||
BuiltinInfo.InitializeBuiltins(idents, Target);
|
||||
}
|
||||
~ASTContext();
|
||||
|
||||
void PrintStats() const;
|
||||
|
||||
/// getComplexType - Return the uniqued reference to the type for a complex
|
||||
/// number with the specified element type.
|
||||
QualType getComplexType(QualType T);
|
||||
|
||||
/// getPointerType - Return the uniqued reference to the type for a pointer to
|
||||
/// the specified type.
|
||||
QualType getPointerType(QualType T);
|
||||
|
||||
/// getReferenceType - Return the uniqued reference to the type for a
|
||||
/// reference to the specified type.
|
||||
QualType getReferenceType(QualType T);
|
||||
|
||||
/// getArrayType - Return the unique reference to the type for an array of the
|
||||
/// specified element type.
|
||||
QualType getArrayType(QualType EltTy, ArrayType::ArraySizeModifier ASM,
|
||||
unsigned EltTypeQuals, Expr *NumElts);
|
||||
|
||||
/// convertToVectorType - Return the unique reference to a vector type of
|
||||
/// the specified element type and size. VectorType can be a pointer, array,
|
||||
/// function, or built-in type (i.e. _Bool, integer, or float).
|
||||
QualType convertToVectorType(QualType VectorType, unsigned NumElts);
|
||||
|
||||
/// getFunctionTypeNoProto - Return a K&R style C function type like 'int()'.
|
||||
///
|
||||
QualType getFunctionTypeNoProto(QualType ResultTy);
|
||||
|
||||
/// getFunctionType - Return a normal function type with a typed argument
|
||||
/// list. isVariadic indicates whether the argument list includes '...'.
|
||||
QualType getFunctionType(QualType ResultTy, QualType *ArgArray,
|
||||
unsigned NumArgs, bool isVariadic);
|
||||
|
||||
/// getTypedefType - Return the unique reference to the type for the
|
||||
/// specified typename decl.
|
||||
QualType getTypedefType(TypedefDecl *Decl);
|
||||
|
||||
/// getTagDeclType - Return the unique reference to the type for the
|
||||
/// specified TagDecl (struct/union/class/enum) decl.
|
||||
QualType getTagDeclType(TagDecl *Decl);
|
||||
|
||||
/// getSizeType - Return the unique type for "size_t" (C99 7.17), defined
|
||||
/// in <stddef.h>. The sizeof operator requires this (C99 6.5.3.4p4).
|
||||
QualType getSizeType() const;
|
||||
|
||||
/// getIntegerBitwidth - Return the bitwidth of the specified integer type
|
||||
/// according to the target. 'Loc' specifies the source location that
|
||||
/// requires evaluation of this property.
|
||||
unsigned getIntegerBitwidth(QualType T, SourceLocation Loc);
|
||||
|
||||
// maxIntegerType - Returns the highest ranked integer type. Handles 3
|
||||
// different type combos: unsigned/unsigned, signed/signed, signed/unsigned.
|
||||
static QualType maxIntegerType(QualType lhs, QualType rhs);
|
||||
|
||||
// maxFloatingType - Returns the highest ranked float type. Both input
|
||||
// types are required to be floats.
|
||||
static QualType maxFloatingType(QualType lt, QualType rt);
|
||||
|
||||
// maxComplexType - Returns the highest ranked complex type. Handles 3
|
||||
// different type combos: complex/complex, complex/float, float/complex.
|
||||
QualType maxComplexType(QualType lt, QualType rt) const;
|
||||
|
||||
private:
|
||||
ASTContext(const ASTContext&); // DO NOT IMPLEMENT
|
||||
void operator=(const ASTContext&); // DO NOT IMPLEMENT
|
||||
|
||||
void InitBuiltinTypes();
|
||||
void InitBuiltinType(QualType &R, BuiltinType::Kind K);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,53 @@
|
|||
//===--- Builtins.def - Builtin function info 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 standard 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.
|
||||
//
|
||||
// FIXME: This should really be a .td file, but that requires modifying tblgen.
|
||||
// Perhaps tblgen should have plugins.
|
||||
|
||||
// The first value provided to the macro specifies the function name of the
|
||||
// builtin, and results in a clang::builtin::BIXX enum value for XX.
|
||||
|
||||
// The second value provided to the macro specifies the type of the function
|
||||
// (result value, then each argument) as follows:
|
||||
// v -> void
|
||||
// c -> char
|
||||
// s -> short
|
||||
// i -> int
|
||||
// f -> float
|
||||
// d -> double
|
||||
// . -> "...". This may only occur at the end of the function list.
|
||||
//
|
||||
// Types maybe prefixed with the following modifiers:
|
||||
// L -> long (e.g. Li for 'long int')
|
||||
// LL -> long long
|
||||
// S -> signed
|
||||
// U -> unsigned
|
||||
|
||||
// The third value provided to the macro specifies information about attributes
|
||||
// of the function. Currently we have:
|
||||
// n -> nothrow
|
||||
// c -> const
|
||||
|
||||
BUILTIN(__builtin_inf , "d" , "nc")
|
||||
BUILTIN(__builtin_inff , "f" , "nc")
|
||||
BUILTIN(__builtin_infl , "Ld" , "nc")
|
||||
BUILTIN(__builtin_fabs , "dd" , "nc")
|
||||
BUILTIN(__builtin_fabsf, "ff" , "nc")
|
||||
BUILTIN(__builtin_fabsl, "LdLd", "nc")
|
||||
BUILTIN(__builtin_constant_p, "UsUs", "nc")
|
||||
|
||||
#undef BUILTIN
|
|
@ -0,0 +1,72 @@
|
|||
//===--- Builtins.h - Builtin function header -------------------*- 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 enum values for all the target-independent builtin
|
||||
// functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_BUILTINS_H
|
||||
#define LLVM_CLANG_AST_BUILTINS_H
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace clang {
|
||||
class TargetInfo;
|
||||
class IdentifierTable;
|
||||
class ASTContext;
|
||||
class QualType;
|
||||
|
||||
namespace Builtin {
|
||||
enum ID {
|
||||
NotBuiltin = 0, // This is not a builtin function.
|
||||
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
|
||||
#include "clang/AST/Builtins.def"
|
||||
FirstTSBuiltin
|
||||
};
|
||||
|
||||
struct Info {
|
||||
const char *Name, *Type, *Attributes;
|
||||
|
||||
bool operator==(const Info &RHS) const {
|
||||
return !strcmp(Name, RHS.Name) &&
|
||||
!strcmp(Type, RHS.Type) &&
|
||||
!strcmp(Attributes, RHS.Attributes);
|
||||
}
|
||||
bool operator!=(const Info &RHS) const { return !(*this == RHS); }
|
||||
};
|
||||
|
||||
/// Builtin::Context - This holds information about target-independent and
|
||||
/// target-specific builtins, allowing easy queries by clients.
|
||||
class Context {
|
||||
const Info *TSRecords;
|
||||
unsigned NumTSRecords;
|
||||
public:
|
||||
Context() : TSRecords(0), NumTSRecords(0) {}
|
||||
|
||||
/// InitializeBuiltins - Mark the identifiers for all the builtins with their
|
||||
/// appropriate builtin ID # and mark any non-portable builtin identifiers as
|
||||
/// such.
|
||||
void InitializeBuiltins(IdentifierTable &Table, const TargetInfo &Target);
|
||||
|
||||
/// Builtin::GetName - Return the identifier name for the specified builtin,
|
||||
/// e.g. "__builtin_abs".
|
||||
const char *GetName(unsigned ID) const {
|
||||
return GetRecord(ID).Name;
|
||||
}
|
||||
|
||||
/// GetBuiltinType - Return the type for the specified builtin.
|
||||
QualType GetBuiltinType(unsigned ID, ASTContext &Context) const;
|
||||
private:
|
||||
const Info &GetRecord(unsigned ID) const;
|
||||
};
|
||||
|
||||
}
|
||||
} // end namespace clang
|
||||
#endif
|
|
@ -0,0 +1,442 @@
|
|||
//===--- Decl.h - Classes for representing declarations ---------*- 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 Decl interface and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DECL_H
|
||||
#define LLVM_CLANG_AST_DECL_H
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
|
||||
namespace clang {
|
||||
class IdentifierInfo;
|
||||
class Expr;
|
||||
class Stmt;
|
||||
class FunctionDecl;
|
||||
|
||||
|
||||
/// Decl - This represents one declaration (or definition), e.g. a variable,
|
||||
/// typedef, function, struct, etc.
|
||||
///
|
||||
class Decl {
|
||||
public:
|
||||
enum Kind {
|
||||
// Concrete sub-classes of ValueDecl
|
||||
Function, BlockVariable, FileVariable, ParmVariable, EnumConstant,
|
||||
// Concrete sub-classes of TypeDecl
|
||||
Typedef, Struct, Union, Class, Enum,
|
||||
// Concrete sub-class of Decl
|
||||
Field
|
||||
};
|
||||
|
||||
/// IdentifierNamespace - According to C99 6.2.3, there are four namespaces,
|
||||
/// labels, tags, members and ordinary identifiers.
|
||||
enum IdentifierNamespace {
|
||||
IDNS_Label,
|
||||
IDNS_Tag,
|
||||
IDNS_Member,
|
||||
IDNS_Ordinary
|
||||
};
|
||||
private:
|
||||
/// DeclKind - This indicates which class this is.
|
||||
Kind DeclKind;
|
||||
|
||||
/// Loc - The location that this decl.
|
||||
SourceLocation Loc;
|
||||
|
||||
/// Identifier - The identifier for this declaration (e.g. the name for the
|
||||
/// variable, the tag for a struct).
|
||||
IdentifierInfo *Identifier;
|
||||
|
||||
/// When this decl is in scope while parsing, the Next field contains a
|
||||
/// pointer to the shadowed decl of the same name. When the scope is popped,
|
||||
/// Decls are relinked onto a containing decl object.
|
||||
///
|
||||
Decl *Next;
|
||||
|
||||
/// NextDeclarator - If this decl was part of a multi-declarator declaration,
|
||||
/// such as "int X, Y, *Z;" this indicates Decl for the next declarator.
|
||||
Decl *NextDeclarator;
|
||||
|
||||
protected:
|
||||
Decl(Kind DK, SourceLocation L, IdentifierInfo *Id, Decl *NextDecl)
|
||||
: DeclKind(DK), Loc(L), Identifier(Id), Next(0), NextDeclarator(NextDecl) {
|
||||
if (Decl::CollectingStats()) addDeclKind(DK);
|
||||
}
|
||||
virtual ~Decl();
|
||||
|
||||
public:
|
||||
IdentifierInfo *getIdentifier() const { return Identifier; }
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
const char *getName() const;
|
||||
|
||||
Kind getKind() const { return DeclKind; }
|
||||
Decl *getNext() const { return Next; }
|
||||
void setNext(Decl *N) { Next = N; }
|
||||
|
||||
/// getNextDeclarator - If this decl was part of a multi-declarator
|
||||
/// declaration, such as "int X, Y, *Z;" this returns the decl for the next
|
||||
/// declarator. Otherwise it returns null.
|
||||
Decl *getNextDeclarator() { return NextDeclarator; }
|
||||
const Decl *getNextDeclarator() const { return NextDeclarator; }
|
||||
void setNextDeclarator(Decl *N) { NextDeclarator = N; }
|
||||
|
||||
IdentifierNamespace getIdentifierNamespace() const {
|
||||
switch (DeclKind) {
|
||||
default: assert(0 && "Unknown decl kind!");
|
||||
case Typedef:
|
||||
case Function:
|
||||
case BlockVariable:
|
||||
case FileVariable:
|
||||
case ParmVariable:
|
||||
case EnumConstant:
|
||||
return IDNS_Ordinary;
|
||||
case Struct:
|
||||
case Union:
|
||||
case Class:
|
||||
case Enum:
|
||||
return IDNS_Tag;
|
||||
}
|
||||
}
|
||||
// global temp stats (until we have a per-module visitor)
|
||||
static void addDeclKind(const Kind k);
|
||||
static bool CollectingStats(bool enable=false);
|
||||
static void PrintStats();
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *) { return true; }
|
||||
};
|
||||
|
||||
/// ValueDecl - Represent the declaration of a variable (in which case it is
|
||||
/// an lvalue) a function (in which case it is a function designator) or
|
||||
/// an enum constant.
|
||||
class ValueDecl : public Decl {
|
||||
QualType DeclType;
|
||||
protected:
|
||||
ValueDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T,
|
||||
Decl *PrevDecl) : Decl(DK, L, Id, PrevDecl), DeclType(T) {}
|
||||
public:
|
||||
QualType getType() const { return DeclType; }
|
||||
void setType(QualType newType) { DeclType = newType; }
|
||||
QualType getCanonicalType() const { return DeclType.getCanonicalType(); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= Function && D->getKind() <= EnumConstant;
|
||||
}
|
||||
static bool classof(const ValueDecl *D) { return true; }
|
||||
};
|
||||
|
||||
/// VarDecl - An instance of this class is created to represent a variable
|
||||
/// declaration or definition.
|
||||
class VarDecl : public ValueDecl {
|
||||
public:
|
||||
enum StorageClass {
|
||||
None, Extern, Static, Auto, Register
|
||||
};
|
||||
StorageClass getStorageClass() const { return SClass; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= BlockVariable && D->getKind() <= ParmVariable;
|
||||
}
|
||||
static bool classof(const VarDecl *D) { return true; }
|
||||
protected:
|
||||
VarDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T,
|
||||
StorageClass SC, Decl *PrevDecl)
|
||||
: ValueDecl(DK, L, Id, T, PrevDecl) { SClass = SC; }
|
||||
private:
|
||||
StorageClass SClass;
|
||||
// TODO: Initializer.
|
||||
};
|
||||
|
||||
/// BlockVarDecl - Represent a local variable declaration.
|
||||
class BlockVarDecl : public VarDecl {
|
||||
public:
|
||||
BlockVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S,
|
||||
Decl *PrevDecl)
|
||||
: VarDecl(BlockVariable, L, Id, T, S, PrevDecl) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == BlockVariable; }
|
||||
static bool classof(const BlockVarDecl *D) { return true; }
|
||||
};
|
||||
|
||||
/// FileVarDecl - Represent a file scoped variable declaration. This
|
||||
/// will allow us to reason about external variable declarations and tentative
|
||||
/// definitions (C99 6.9.2p2) using our type system (without storing a
|
||||
/// pointer to the decl's scope, which is transient).
|
||||
class FileVarDecl : public VarDecl {
|
||||
public:
|
||||
FileVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S,
|
||||
Decl *PrevDecl)
|
||||
: VarDecl(FileVariable, L, Id, T, S, PrevDecl) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == FileVariable; }
|
||||
static bool classof(const FileVarDecl *D) { return true; }
|
||||
};
|
||||
|
||||
/// ParmVarDecl - Represent a parameter to a function.
|
||||
class ParmVarDecl : public VarDecl {
|
||||
public:
|
||||
ParmVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S,
|
||||
Decl *PrevDecl)
|
||||
: VarDecl(ParmVariable, L, Id, T, S, PrevDecl) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == ParmVariable; }
|
||||
static bool classof(const ParmVarDecl *D) { return true; }
|
||||
};
|
||||
|
||||
/// FunctionDecl - An instance of this class is created to represent a function
|
||||
/// declaration or definition.
|
||||
class FunctionDecl : public ValueDecl {
|
||||
public:
|
||||
enum StorageClass {
|
||||
None, Extern, Static
|
||||
};
|
||||
FunctionDecl(SourceLocation L, IdentifierInfo *Id, QualType T,
|
||||
StorageClass S = None, Decl *PrevDecl)
|
||||
: ValueDecl(Function, L, Id, T, PrevDecl),
|
||||
ParamInfo(0), Body(0), DeclChain(0), SClass(S) {}
|
||||
virtual ~FunctionDecl();
|
||||
|
||||
Stmt *getBody() const { return Body; }
|
||||
void setBody(Stmt *B) { Body = B; }
|
||||
|
||||
Decl *getDeclChain() const { return DeclChain; }
|
||||
void setDeclChain(Decl *D) { DeclChain = D; }
|
||||
|
||||
unsigned getNumParams() const;
|
||||
const ParmVarDecl *getParamDecl(unsigned i) const {
|
||||
assert(i < getNumParams() && "Illegal param #");
|
||||
return ParamInfo[i];
|
||||
}
|
||||
ParmVarDecl *getParamDecl(unsigned i) {
|
||||
assert(i < getNumParams() && "Illegal param #");
|
||||
return ParamInfo[i];
|
||||
}
|
||||
void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams);
|
||||
|
||||
QualType getResultType() const {
|
||||
return cast<FunctionType>(getType())->getResultType();
|
||||
}
|
||||
StorageClass getStorageClass() const { return SClass; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == Function; }
|
||||
static bool classof(const FunctionDecl *D) { return true; }
|
||||
private:
|
||||
/// ParamInfo - new[]'d array of pointers to VarDecls for the formal
|
||||
/// parameters of this function. This is null if a prototype or if there are
|
||||
/// no formals. TODO: we could allocate this space immediately after the
|
||||
/// FunctionDecl object to save an allocation like FunctionType does.
|
||||
ParmVarDecl **ParamInfo;
|
||||
|
||||
Stmt *Body; // Null if a prototype.
|
||||
|
||||
/// DeclChain - Linked list of declarations that are defined inside this
|
||||
/// function.
|
||||
Decl *DeclChain;
|
||||
|
||||
StorageClass SClass;
|
||||
};
|
||||
|
||||
|
||||
/// FieldDecl - An instance of this class is created by Sema::ParseField to
|
||||
/// represent a member of a struct/union/class.
|
||||
class FieldDecl : public Decl {
|
||||
QualType DeclType;
|
||||
public:
|
||||
FieldDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Decl *PrevDecl)
|
||||
: Decl(Field, L, Id, PrevDecl), DeclType(T) {}
|
||||
|
||||
QualType getType() const { return DeclType; }
|
||||
QualType getCanonicalType() const { return DeclType.getCanonicalType(); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == Field;
|
||||
}
|
||||
static bool classof(const FieldDecl *D) { return true; }
|
||||
};
|
||||
|
||||
/// EnumConstantDecl - An instance of this object exists for each enum constant
|
||||
/// that is defined. For example, in "enum X {a,b}", each of a/b are
|
||||
/// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a
|
||||
/// TagType for the X EnumDecl.
|
||||
class EnumConstantDecl : public ValueDecl {
|
||||
Expr *Init; // an integer constant expression
|
||||
llvm::APSInt Val; // The value.
|
||||
public:
|
||||
EnumConstantDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Expr *E,
|
||||
const llvm::APSInt &V, Decl *PrevDecl)
|
||||
: ValueDecl(EnumConstant, L, Id, T, PrevDecl), Init(E), Val(V) {}
|
||||
|
||||
const Expr *getInitExpr() const { return Init; }
|
||||
Expr *getInitExpr() { return Init; }
|
||||
const llvm::APSInt &getInitVal() const { return Val; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == EnumConstant;
|
||||
}
|
||||
static bool classof(const EnumConstantDecl *D) { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// TypeDecl - Represents a declaration of a type.
|
||||
///
|
||||
class TypeDecl : public Decl {
|
||||
/// TypeForDecl - This indicates the Type object that represents this
|
||||
/// TypeDecl. It is a cache maintained by ASTContext::getTypedefType and
|
||||
/// ASTContext::getTagDeclType.
|
||||
Type *TypeForDecl;
|
||||
friend class ASTContext;
|
||||
protected:
|
||||
TypeDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, Decl *PrevDecl)
|
||||
: Decl(DK, L, Id, PrevDecl), TypeForDecl(0) {}
|
||||
public:
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= Typedef && D->getKind() <= Enum;
|
||||
}
|
||||
static bool classof(const TypeDecl *D) { return true; }
|
||||
};
|
||||
|
||||
|
||||
class TypedefDecl : public TypeDecl {
|
||||
/// UnderlyingType - This is the type the typedef is set to.
|
||||
QualType UnderlyingType;
|
||||
public:
|
||||
TypedefDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Decl *PrevDecl)
|
||||
: TypeDecl(Typedef, L, Id, PrevDecl), UnderlyingType(T) {}
|
||||
|
||||
QualType getUnderlyingType() const { return UnderlyingType; }
|
||||
void setUnderlyingType(QualType newType) { UnderlyingType = newType; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == Typedef; }
|
||||
static bool classof(const TypedefDecl *D) { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// TagDecl - Represents the declaration of a struct/union/class/enum.
|
||||
class TagDecl : public TypeDecl {
|
||||
/// IsDefinition - True if this is a definition ("struct foo {};"), false if
|
||||
/// it is a declaration ("struct foo;").
|
||||
bool IsDefinition : 1;
|
||||
protected:
|
||||
TagDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, Decl *PrevDecl)
|
||||
: TypeDecl(DK, L, Id, PrevDecl) {
|
||||
IsDefinition = false;
|
||||
}
|
||||
public:
|
||||
|
||||
/// isDefinition - Return true if this decl has its body specified.
|
||||
bool isDefinition() const {
|
||||
return IsDefinition;
|
||||
}
|
||||
|
||||
const char *getKindName() const {
|
||||
switch (getKind()) {
|
||||
default: assert(0 && "Unknown TagDecl!");
|
||||
case Struct: return "struct";
|
||||
case Union: return "union";
|
||||
case Class: return "class";
|
||||
case Enum: return "enum";
|
||||
}
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == Struct || D->getKind() == Union ||
|
||||
D->getKind() == Class || D->getKind() == Enum;
|
||||
}
|
||||
static bool classof(const TagDecl *D) { return true; }
|
||||
protected:
|
||||
void setDefinition(bool V) { IsDefinition = V; }
|
||||
};
|
||||
|
||||
/// EnumDecl - Represents an enum. As an extension, we allow forward-declared
|
||||
/// enums.
|
||||
class EnumDecl : public TagDecl {
|
||||
/// ElementList - this is a linked list of EnumConstantDecl's which are linked
|
||||
/// together through their getNextDeclarator pointers.
|
||||
EnumConstantDecl *ElementList;
|
||||
public:
|
||||
EnumDecl(SourceLocation L, IdentifierInfo *Id, Decl *PrevDecl)
|
||||
: TagDecl(Enum, L, Id, PrevDecl) {
|
||||
ElementList = 0;
|
||||
}
|
||||
|
||||
/// defineElements - When created, EnumDecl correspond to a forward declared
|
||||
/// enum. This method is used to mark the decl as being defined, with the
|
||||
/// specified list of enums.
|
||||
void defineElements(EnumConstantDecl *ListHead) {
|
||||
assert(!isDefinition() && "Cannot redefine enums!");
|
||||
ElementList = ListHead;
|
||||
setDefinition(true);
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == Enum;
|
||||
}
|
||||
static bool classof(const EnumDecl *D) { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// RecordDecl - Represents a struct/union/class.
|
||||
class RecordDecl : public TagDecl {
|
||||
/// HasFlexibleArrayMember - This is true if this struct ends with a flexible
|
||||
/// array member (e.g. int X[]) or if this union contains a struct that does.
|
||||
/// If so, this cannot be contained in arrays or other structs as a member.
|
||||
bool HasFlexibleArrayMember : 1;
|
||||
|
||||
/// Members/NumMembers - This is a new[]'d array of pointers to Decls.
|
||||
FieldDecl **Members; // Null if not defined.
|
||||
int NumMembers; // -1 if not defined.
|
||||
public:
|
||||
RecordDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, Decl *PrevDecl)
|
||||
: TagDecl(DK, L, Id, PrevDecl) {
|
||||
HasFlexibleArrayMember = false;
|
||||
assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
|
||||
Members = 0;
|
||||
NumMembers = -1;
|
||||
}
|
||||
|
||||
bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
|
||||
void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; }
|
||||
|
||||
/// 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 defineBody(FieldDecl **Members, unsigned numMembers);
|
||||
|
||||
/// getMember - If the member doesn't exist, or there are no members, this
|
||||
/// function will return 0;
|
||||
FieldDecl *getMember(IdentifierInfo *name);
|
||||
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == Struct || D->getKind() == Union ||
|
||||
D->getKind() == Class;
|
||||
}
|
||||
static bool classof(const RecordDecl *D) { return true; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,596 @@
|
|||
//===--- Expr.h - Classes for representing expressions ----------*- 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 Expr interface and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_EXPR_H
|
||||
#define LLVM_CLANG_AST_EXPR_H
|
||||
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
|
||||
namespace clang {
|
||||
class IdentifierInfo;
|
||||
class Decl;
|
||||
|
||||
/// Expr - This represents one expression. Note that Expr's are subclasses of
|
||||
/// Stmt. This allows an expression to be transparently used any place a Stmt
|
||||
/// is required.
|
||||
///
|
||||
class Expr : public Stmt {
|
||||
QualType TR;
|
||||
protected:
|
||||
Expr(StmtClass SC, QualType T) : Stmt(SC), TR(T) {}
|
||||
~Expr() {}
|
||||
public:
|
||||
QualType getType() const { return TR; }
|
||||
|
||||
/// SourceLocation tokens are not useful in isolation - they are low level
|
||||
/// value objects created/interpreted by SourceManager. We assume AST
|
||||
/// clients will have a pointer to the respective SourceManager.
|
||||
virtual SourceRange getSourceRange() const = 0;
|
||||
SourceLocation getLocStart() const { return getSourceRange().Begin(); }
|
||||
SourceLocation getLocEnd() const { return getSourceRange().End(); }
|
||||
|
||||
/// getExprLoc - Return the preferred location for the arrow when diagnosing
|
||||
/// a problem with a generic expression.
|
||||
virtual SourceLocation getExprLoc() const { return getLocStart(); }
|
||||
|
||||
/// hasLocalSideEffect - Return true if this immediate expression has side
|
||||
/// effects, not counting any sub-expressions.
|
||||
bool hasLocalSideEffect() const;
|
||||
|
||||
/// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or
|
||||
/// incomplete type other than void. Nonarray expressions that can be lvalues:
|
||||
/// - name, where name must be a variable
|
||||
/// - e[i]
|
||||
/// - (e), where e must be an lvalue
|
||||
/// - e.name, where e must be an lvalue
|
||||
/// - e->name
|
||||
/// - *e, the type of e cannot be a function type
|
||||
/// - string-constant
|
||||
///
|
||||
enum isLvalueResult {
|
||||
LV_Valid,
|
||||
LV_NotObjectType,
|
||||
LV_IncompleteVoidType,
|
||||
LV_InvalidExpression
|
||||
};
|
||||
isLvalueResult isLvalue();
|
||||
|
||||
/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
|
||||
/// does not have an incomplete type, does not have a const-qualified type,
|
||||
/// and if it is a structure or union, does not have any member (including,
|
||||
/// recursively, any member or element of all contained aggregates or unions)
|
||||
/// with a const-qualified type.
|
||||
enum isModifiableLvalueResult {
|
||||
MLV_Valid,
|
||||
MLV_NotObjectType,
|
||||
MLV_IncompleteVoidType,
|
||||
MLV_InvalidExpression,
|
||||
MLV_IncompleteType,
|
||||
MLV_ConstQualified,
|
||||
MLV_ArrayType
|
||||
};
|
||||
isModifiableLvalueResult isModifiableLvalue();
|
||||
|
||||
bool isNullPointerConstant() const;
|
||||
|
||||
/// isIntegerConstantExpr - Return true if this expression is a valid integer
|
||||
/// constant expression, and, if so, return its value in Result. If not a
|
||||
/// valid i-c-e, return false and fill in Loc (if specified) with the location
|
||||
/// of the invalid expression.
|
||||
bool isIntegerConstantExpr(llvm::APSInt &Result, SourceLocation *Loc = 0,
|
||||
bool isEvaluated = true) const;
|
||||
bool isIntegerConstantExpr(SourceLocation *Loc = 0) const {
|
||||
llvm::APSInt X(32);
|
||||
return isIntegerConstantExpr(X, Loc);
|
||||
}
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() >= firstExprConstant &&
|
||||
T->getStmtClass() <= lastExprConstant;
|
||||
}
|
||||
static bool classof(const Expr *) { return true; }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Primary Expressions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// DeclRefExpr - [C99 6.5.1p2] - A reference to a declared variable, function,
|
||||
/// enum, etc.
|
||||
class DeclRefExpr : public Expr {
|
||||
Decl *D; // a ValueDecl or EnumConstantDecl
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
DeclRefExpr(Decl *d, QualType t, SourceLocation l) :
|
||||
Expr(DeclRefExprClass, t), D(d), Loc(l) {}
|
||||
|
||||
Decl *getDecl() { return D; }
|
||||
const Decl *getDecl() const { return D; }
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DeclRefExprClass;
|
||||
}
|
||||
static bool classof(const DeclRefExpr *) { return true; }
|
||||
};
|
||||
|
||||
class IntegerLiteral : public Expr {
|
||||
llvm::APInt Value;
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
// type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
|
||||
// or UnsignedLongLongTy
|
||||
IntegerLiteral(const llvm::APInt &V, QualType type, SourceLocation l)
|
||||
: Expr(IntegerLiteralClass, type), Value(V), Loc(l) {
|
||||
assert(type->isIntegerType() && "Illegal type in IntegerLiteral");
|
||||
}
|
||||
const llvm::APInt &getValue() const { return Value; }
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == IntegerLiteralClass;
|
||||
}
|
||||
static bool classof(const IntegerLiteral *) { return true; }
|
||||
};
|
||||
|
||||
class CharacterLiteral : public Expr {
|
||||
unsigned Value;
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
// type should be IntTy
|
||||
CharacterLiteral(unsigned value, QualType type, SourceLocation l)
|
||||
: Expr(CharacterLiteralClass, type), Value(value), Loc(l) {
|
||||
}
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
unsigned getValue() const { return Value; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CharacterLiteralClass;
|
||||
}
|
||||
static bool classof(const CharacterLiteral *) { return true; }
|
||||
};
|
||||
|
||||
class FloatingLiteral : public Expr {
|
||||
float Value; // FIXME
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
FloatingLiteral(float value, QualType type, SourceLocation l)
|
||||
: Expr(FloatingLiteralClass, type), Value(value), Loc(l) {}
|
||||
|
||||
float getValue() const { return Value; }
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == FloatingLiteralClass;
|
||||
}
|
||||
static bool classof(const FloatingLiteral *) { return true; }
|
||||
};
|
||||
|
||||
class StringLiteral : public Expr {
|
||||
const char *StrData;
|
||||
unsigned ByteLength;
|
||||
bool IsWide;
|
||||
// if the StringLiteral was composed using token pasting, both locations
|
||||
// are needed. If not (the common case), firstTokLoc == lastTokLoc.
|
||||
// FIXME: if space becomes an issue, we should create a sub-class.
|
||||
SourceLocation firstTokLoc, lastTokLoc;
|
||||
public:
|
||||
StringLiteral(const char *strData, unsigned byteLength, bool Wide,
|
||||
QualType t, SourceLocation b, SourceLocation e);
|
||||
virtual ~StringLiteral();
|
||||
|
||||
const char *getStrData() const { return StrData; }
|
||||
unsigned getByteLength() const { return ByteLength; }
|
||||
bool isWide() const { return IsWide; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(firstTokLoc,lastTokLoc);
|
||||
}
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == StringLiteralClass;
|
||||
}
|
||||
static bool classof(const StringLiteral *) { return true; }
|
||||
};
|
||||
|
||||
/// ParenExpr - This represents a parethesized expression, e.g. "(1)". This
|
||||
/// AST node is only formed if full location information is requested.
|
||||
class ParenExpr : public Expr {
|
||||
SourceLocation L, R;
|
||||
Expr *Val;
|
||||
public:
|
||||
ParenExpr(SourceLocation l, SourceLocation r, Expr *val)
|
||||
: Expr(ParenExprClass, val->getType()), L(l), R(r), Val(val) {}
|
||||
|
||||
const Expr *getSubExpr() const { return Val; }
|
||||
Expr *getSubExpr() { return Val; }
|
||||
SourceRange getSourceRange() const { return SourceRange(L, R); }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ParenExprClass;
|
||||
}
|
||||
static bool classof(const ParenExpr *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// UnaryOperator - This represents the unary-expression's (except sizeof of
|
||||
/// types), the postinc/postdec operators from postfix-expression, and various
|
||||
/// extensions.
|
||||
class UnaryOperator : public Expr {
|
||||
public:
|
||||
enum Opcode {
|
||||
PostInc, PostDec, // [C99 6.5.2.4] Postfix increment and decrement operators
|
||||
PreInc, PreDec, // [C99 6.5.3.1] Prefix increment and decrement operators.
|
||||
AddrOf, Deref, // [C99 6.5.3.2] Address and indirection operators.
|
||||
Plus, Minus, // [C99 6.5.3.3] Unary arithmetic operators.
|
||||
Not, LNot, // [C99 6.5.3.3] Unary arithmetic operators.
|
||||
SizeOf, AlignOf, // [C99 6.5.3.4] Sizeof (expr, not type) operator.
|
||||
Real, Imag, // "__real expr"/"__imag expr" Extension.
|
||||
Extension // __extension__ marker.
|
||||
};
|
||||
private:
|
||||
Expr *Val;
|
||||
Opcode Opc;
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
|
||||
UnaryOperator(Expr *input, Opcode opc, QualType type, SourceLocation l)
|
||||
: Expr(UnaryOperatorClass, type), Val(input), Opc(opc), Loc(l) {}
|
||||
|
||||
Opcode getOpcode() const { return Opc; }
|
||||
Expr *getSubExpr() const { return Val; }
|
||||
|
||||
/// getOperatorLoc - Return the location of the operator.
|
||||
SourceLocation getOperatorLoc() const { return Loc; }
|
||||
|
||||
/// isPostfix - Return true if this is a postfix operation, like x++.
|
||||
static bool isPostfix(Opcode Op);
|
||||
|
||||
bool isPostfix() const { return isPostfix(Opc); }
|
||||
bool isIncrementDecrementOp() const { return Opc>=PostInc && Opc<=PreDec; }
|
||||
bool isSizeOfAlignOfOp() const { return Opc == SizeOf || Opc == AlignOf; }
|
||||
static bool isArithmeticOp(Opcode Op) { return Op >= Plus && Op <= LNot; }
|
||||
|
||||
/// getDecl - a recursive routine that derives the base decl for an
|
||||
/// expression. For example, it will return the declaration for "s" from
|
||||
/// the following complex expression "s.zz[2].bb.vv".
|
||||
static bool isAddressable(Expr *e);
|
||||
|
||||
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
|
||||
/// corresponds to, e.g. "sizeof" or "[pre]++"
|
||||
static const char *getOpcodeStr(Opcode Op);
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
if (isPostfix())
|
||||
return SourceRange(Val->getLocStart(), Loc);
|
||||
else
|
||||
return SourceRange(Loc, Val->getLocEnd());
|
||||
}
|
||||
virtual SourceLocation getExprLoc() const { return Loc; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == UnaryOperatorClass;
|
||||
}
|
||||
static bool classof(const UnaryOperator *) { return true; }
|
||||
};
|
||||
|
||||
/// SizeOfAlignOfTypeExpr - [C99 6.5.3.4] - This is only for sizeof/alignof of
|
||||
/// *types*. sizeof(expr) is handled by UnaryOperator.
|
||||
class SizeOfAlignOfTypeExpr : public Expr {
|
||||
bool isSizeof; // true if sizeof, false if alignof.
|
||||
QualType Ty;
|
||||
SourceLocation OpLoc, RParenLoc;
|
||||
public:
|
||||
SizeOfAlignOfTypeExpr(bool issizeof, QualType argType, QualType resultType,
|
||||
SourceLocation op, SourceLocation rp) :
|
||||
Expr(SizeOfAlignOfTypeExprClass, resultType),
|
||||
isSizeof(issizeof), Ty(argType), OpLoc(op), RParenLoc(rp) {}
|
||||
|
||||
bool isSizeOf() const { return isSizeof; }
|
||||
QualType getArgumentType() const { return Ty; }
|
||||
SourceRange getSourceRange() const { return SourceRange(OpLoc, RParenLoc); }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == SizeOfAlignOfTypeExprClass;
|
||||
}
|
||||
static bool classof(const SizeOfAlignOfTypeExpr *) { return true; }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Postfix Operators.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
|
||||
class ArraySubscriptExpr : public Expr {
|
||||
Expr *Base, *Idx;
|
||||
SourceLocation RBracketLoc;
|
||||
public:
|
||||
ArraySubscriptExpr(Expr *base, Expr *idx, QualType t,
|
||||
SourceLocation rbracketloc) :
|
||||
Expr(ArraySubscriptExprClass, t),
|
||||
Base(base), Idx(idx), RBracketLoc(rbracketloc) {}
|
||||
|
||||
Expr *getBase() { return Base; }
|
||||
const Expr *getBase() const { return Base; }
|
||||
Expr *getIdx() { return Idx; }
|
||||
const Expr *getIdx() const { return Idx; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(Base->getLocStart(), RBracketLoc);
|
||||
}
|
||||
virtual SourceLocation getExprLoc() const { return RBracketLoc; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ArraySubscriptExprClass;
|
||||
}
|
||||
static bool classof(const ArraySubscriptExpr *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// CallExpr - [C99 6.5.2.2] Function Calls.
|
||||
///
|
||||
class CallExpr : public Expr {
|
||||
Expr *Fn;
|
||||
Expr **Args;
|
||||
unsigned NumArgs;
|
||||
SourceLocation RParenLoc;
|
||||
public:
|
||||
CallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t,
|
||||
SourceLocation rparenloc);
|
||||
~CallExpr() {
|
||||
delete [] Args;
|
||||
}
|
||||
|
||||
const Expr *getCallee() const { return Fn; }
|
||||
Expr *getCallee() { return Fn; }
|
||||
|
||||
/// getNumArgs - Return the number of actual arguments to this call.
|
||||
///
|
||||
unsigned getNumArgs() const { return NumArgs; }
|
||||
|
||||
/// getArg - Return the specified argument.
|
||||
Expr *getArg(unsigned Arg) {
|
||||
assert(Arg < NumArgs && "Arg access out of range!");
|
||||
return Args[Arg];
|
||||
}
|
||||
const Expr *getArg(unsigned Arg) const {
|
||||
assert(Arg < NumArgs && "Arg access out of range!");
|
||||
return Args[Arg];
|
||||
}
|
||||
|
||||
/// getNumCommas - Return the number of commas that must have been present in
|
||||
/// this function call.
|
||||
unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(Fn->getLocStart(), RParenLoc);
|
||||
}
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CallExprClass;
|
||||
}
|
||||
static bool classof(const CallExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// MemberExpr - [C99 6.5.2.3] Structure and Union Members.
|
||||
///
|
||||
class MemberExpr : public Expr {
|
||||
Expr *Base;
|
||||
FieldDecl *MemberDecl;
|
||||
SourceLocation MemberLoc;
|
||||
bool IsArrow; // True if this is "X->F", false if this is "X.F".
|
||||
public:
|
||||
MemberExpr(Expr *base, bool isarrow, FieldDecl *memberdecl, SourceLocation l)
|
||||
: Expr(MemberExprClass, memberdecl->getType()),
|
||||
Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow) {}
|
||||
|
||||
Expr *getBase() const { return Base; }
|
||||
FieldDecl *getMemberDecl() const { return MemberDecl; }
|
||||
bool isArrow() const { return IsArrow; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getBase()->getLocStart(), MemberLoc);
|
||||
}
|
||||
virtual SourceLocation getExprLoc() const { return MemberLoc; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == MemberExprClass;
|
||||
}
|
||||
static bool classof(const MemberExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CastExpr - [C99 6.5.4] Cast Operators.
|
||||
///
|
||||
class CastExpr : public Expr {
|
||||
QualType Ty;
|
||||
Expr *Op;
|
||||
SourceLocation Loc; // the location of the left paren
|
||||
public:
|
||||
CastExpr(QualType ty, Expr *op, SourceLocation l) :
|
||||
Expr(CastExprClass, ty), Ty(ty), Op(op), Loc(l) {}
|
||||
CastExpr(StmtClass SC, QualType ty, Expr *op) :
|
||||
Expr(SC, QualType()), Ty(ty), Op(op), Loc(SourceLocation()) {}
|
||||
|
||||
SourceLocation getLParenLoc() const { return Loc; }
|
||||
|
||||
QualType getDestType() const { return Ty; }
|
||||
Expr *getSubExpr() const { return Op; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(Loc, getSubExpr()->getSourceRange().End());
|
||||
}
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CastExprClass;
|
||||
}
|
||||
static bool classof(const CastExpr *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
class BinaryOperator : public Expr {
|
||||
public:
|
||||
enum Opcode {
|
||||
// Operators listed in order of precedence.
|
||||
Mul, Div, Rem, // [C99 6.5.5] Multiplicative operators.
|
||||
Add, Sub, // [C99 6.5.6] Additive operators.
|
||||
Shl, Shr, // [C99 6.5.7] Bitwise shift operators.
|
||||
LT, GT, LE, GE, // [C99 6.5.8] Relational operators.
|
||||
EQ, NE, // [C99 6.5.9] Equality operators.
|
||||
And, // [C99 6.5.10] Bitwise AND operator.
|
||||
Xor, // [C99 6.5.11] Bitwise XOR operator.
|
||||
Or, // [C99 6.5.12] Bitwise OR operator.
|
||||
LAnd, // [C99 6.5.13] Logical AND operator.
|
||||
LOr, // [C99 6.5.14] Logical OR operator.
|
||||
Assign, MulAssign,// [C99 6.5.16] Assignment operators.
|
||||
DivAssign, RemAssign,
|
||||
AddAssign, SubAssign,
|
||||
ShlAssign, ShrAssign,
|
||||
AndAssign, XorAssign,
|
||||
OrAssign,
|
||||
Comma // [C99 6.5.17] Comma operator.
|
||||
};
|
||||
|
||||
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy)
|
||||
: Expr(BinaryOperatorClass, ResTy), LHS(lhs), RHS(rhs), Opc(opc) {
|
||||
assert(!isCompoundAssignmentOp() &&
|
||||
"Use ArithAssignBinaryOperator for compound assignments");
|
||||
}
|
||||
|
||||
Opcode getOpcode() const { return Opc; }
|
||||
Expr *getLHS() const { return LHS; }
|
||||
Expr *getRHS() const { return RHS; }
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getLHS()->getLocStart(), getRHS()->getLocEnd());
|
||||
}
|
||||
|
||||
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
|
||||
/// corresponds to, e.g. "<<=".
|
||||
static const char *getOpcodeStr(Opcode Op);
|
||||
|
||||
/// predicates to categorize the respective opcodes.
|
||||
bool isMultiplicativeOp() const { return Opc >= Mul && Opc <= Rem; }
|
||||
bool isAdditiveOp() const { return Opc == Add || Opc == Sub; }
|
||||
bool isShiftOp() const { return Opc == Shl || Opc == Shr; }
|
||||
bool isBitwiseOp() const { return Opc >= And && Opc <= Or; }
|
||||
bool isRelationalOp() const { return Opc >= LT && Opc <= GE; }
|
||||
bool isEqualityOp() const { return Opc == EQ || Opc == NE; }
|
||||
bool isLogicalOp() const { return Opc == LAnd || Opc == LOr; }
|
||||
bool isAssignmentOp() const { return Opc >= Assign && Opc <= OrAssign; }
|
||||
bool isCompoundAssignmentOp() const { return Opc > Assign && Opc <= OrAssign;}
|
||||
bool isShiftAssignOp() const { return Opc == ShlAssign || Opc == ShrAssign; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == BinaryOperatorClass;
|
||||
}
|
||||
static bool classof(const BinaryOperator *) { return true; }
|
||||
private:
|
||||
Expr *LHS, *RHS;
|
||||
Opcode Opc;
|
||||
protected:
|
||||
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, bool dead)
|
||||
: Expr(BinaryOperatorClass, ResTy), LHS(lhs), RHS(rhs), Opc(opc) {
|
||||
}
|
||||
};
|
||||
|
||||
/// CompoundAssignOperator - For compound assignments (e.g. +=), we keep
|
||||
/// track of the type the operation is performed in. Due to the semantics of
|
||||
/// these operators, the operands are promoted, the aritmetic performed, an
|
||||
/// implicit conversion back to the result type done, then the assignment takes
|
||||
/// place. This captures the intermediate type which the computation is done
|
||||
/// in.
|
||||
class CompoundAssignOperator : public BinaryOperator {
|
||||
QualType ComputationType;
|
||||
public:
|
||||
CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc,
|
||||
QualType ResType, QualType CompType)
|
||||
: BinaryOperator(lhs, rhs, opc, ResType, true), ComputationType(CompType) {
|
||||
assert(isCompoundAssignmentOp() &&
|
||||
"Only should be used for compound assignments");
|
||||
}
|
||||
|
||||
QualType getComputationType() const { return ComputationType; }
|
||||
|
||||
static bool classof(const CompoundAssignOperator *) { return true; }
|
||||
static bool classof(const BinaryOperator *B) {
|
||||
return B->isCompoundAssignmentOp();
|
||||
}
|
||||
static bool classof(const Stmt *S) {
|
||||
return isa<BinaryOperator>(S) && classof(cast<BinaryOperator>(S));
|
||||
}
|
||||
};
|
||||
|
||||
/// ConditionalOperator - The ?: operator. Note that LHS may be null when the
|
||||
/// GNU "missing LHS" extension is in use.
|
||||
///
|
||||
class ConditionalOperator : public Expr {
|
||||
Expr *Cond, *LHS, *RHS; // Left/Middle/Right hand sides.
|
||||
public:
|
||||
ConditionalOperator(Expr *cond, Expr *lhs, Expr *rhs, QualType t)
|
||||
: Expr(ConditionalOperatorClass, t), Cond(cond), LHS(lhs), RHS(rhs) {}
|
||||
|
||||
Expr *getCond() const { return Cond; }
|
||||
Expr *getLHS() const { return LHS; }
|
||||
Expr *getRHS() const { return RHS; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getCond()->getLocStart(), getRHS()->getLocEnd());
|
||||
}
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ConditionalOperatorClass;
|
||||
}
|
||||
static bool classof(const ConditionalOperator *) { return true; }
|
||||
};
|
||||
|
||||
/// AddrLabel - The GNU address of label extension, representing &&label.
|
||||
class AddrLabel : public Expr {
|
||||
SourceLocation AmpAmpLoc, LabelLoc;
|
||||
LabelStmt *Label;
|
||||
public:
|
||||
AddrLabel(SourceLocation AALoc, SourceLocation LLoc, LabelStmt *L, QualType t)
|
||||
: Expr(AddrLabelClass, t), AmpAmpLoc(AALoc), LabelLoc(LLoc), Label(L) {}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AmpAmpLoc, LabelLoc);
|
||||
}
|
||||
|
||||
LabelStmt *getLabel() const { return Label; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == AddrLabelClass;
|
||||
}
|
||||
static bool classof(const AddrLabel *) { return true; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,81 @@
|
|||
//===--- ExprCXX.h - Classes for representing expressions -------*- 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 file defines the Expr interface and subclasses for C++ expressions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_EXPRCXX_H
|
||||
#define LLVM_CLANG_AST_EXPRCXX_H
|
||||
|
||||
#include "clang/AST/Expr.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ Expressions.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// CXXCastExpr - [C++ 5.2.7, 5.2.9, 5.2.10, 5.2.11] C++ Cast Operators.
|
||||
///
|
||||
class CXXCastExpr : public Expr {
|
||||
public:
|
||||
enum Opcode {
|
||||
DynamicCast,
|
||||
StaticCast,
|
||||
ReinterpretCast,
|
||||
ConstCast
|
||||
};
|
||||
private:
|
||||
QualType Ty;
|
||||
Opcode Opc;
|
||||
Expr *Op;
|
||||
SourceLocation Loc; // the location of the casting op
|
||||
public:
|
||||
CXXCastExpr(Opcode op, QualType ty, Expr *expr, SourceLocation l)
|
||||
: Expr(CXXCastExprClass, ty), Ty(ty), Opc(op), Op(expr), Loc(l) {}
|
||||
|
||||
QualType getDestType() const { return Ty; }
|
||||
Expr *getSubExpr() const { return Op; }
|
||||
|
||||
Opcode getOpcode() const { return Opc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(Loc, getSubExpr()->getSourceRange().End());
|
||||
}
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXCastExprClass;
|
||||
}
|
||||
static bool classof(const CXXCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CXXBoolLiteralExpr - [C++ 2.13.5] C++ Boolean Literal.
|
||||
///
|
||||
class CXXBoolLiteralExpr : public Expr {
|
||||
bool Value;
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
CXXBoolLiteralExpr(bool val, SourceLocation l) :
|
||||
Expr(CXXBoolLiteralExprClass, QualType()), Value(val), Loc(l) {}
|
||||
|
||||
bool getValue() const { return Value; }
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXBoolLiteralExprClass;
|
||||
}
|
||||
static bool classof(const CXXBoolLiteralExpr *) { return true; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,378 @@
|
|||
//===--- Stmt.h - Classes for representing statements -----------*- 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 Stmt interface and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_STMT_H
|
||||
#define LLVM_CLANG_AST_STMT_H
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <iosfwd>
|
||||
|
||||
namespace clang {
|
||||
class Expr;
|
||||
class Decl;
|
||||
class IdentifierInfo;
|
||||
class StmtVisitor;
|
||||
|
||||
/// Stmt - This represents one statement.
|
||||
///
|
||||
class Stmt {
|
||||
public:
|
||||
enum StmtClass {
|
||||
#define STMT(N, CLASS, PARENT) CLASS##Class = N,
|
||||
#define FIRST_STMT(N) firstStmtConstant = N,
|
||||
#define LAST_STMT(N) lastStmtConstant = N,
|
||||
#define FIRST_EXPR(N) firstExprConstant = N,
|
||||
#define LAST_EXPR(N) lastExprConstant = N
|
||||
#include "clang/AST/StmtNodes.def"
|
||||
};
|
||||
private:
|
||||
const StmtClass sClass;
|
||||
public:
|
||||
Stmt(StmtClass SC) : sClass(SC) {
|
||||
if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
|
||||
}
|
||||
virtual ~Stmt() {}
|
||||
|
||||
StmtClass getStmtClass() const { return sClass; }
|
||||
const char *getStmtClassName() const;
|
||||
|
||||
// global temp stats (until we have a per-module visitor)
|
||||
static void addStmtClass(const StmtClass s);
|
||||
static bool CollectingStats(bool enable=false);
|
||||
static void PrintStats();
|
||||
|
||||
void dump() const;
|
||||
void print(std::ostream &OS) const;
|
||||
|
||||
// Implement visitor support.
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
|
||||
// Implement isa<T> support.
|
||||
static bool classof(const Stmt *) { return true; }
|
||||
};
|
||||
|
||||
/// DeclStmt - Adaptor class for mixing declarations with statements and
|
||||
/// expressions. For example, CompoundStmt mixes statements, expressions
|
||||
/// and declarations (variables, types). Another example is ForStmt, where
|
||||
/// the first statement can be an expression or a declaration.
|
||||
///
|
||||
class DeclStmt : public Stmt {
|
||||
Decl *TheDecl;
|
||||
public:
|
||||
DeclStmt(Decl *D) : Stmt(DeclStmtClass), TheDecl(D) {}
|
||||
|
||||
const Decl *getDecl() const { return TheDecl; }
|
||||
Decl *getDecl() { return TheDecl; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DeclStmtClass;
|
||||
}
|
||||
static bool classof(const DeclStmt *) { return true; }
|
||||
};
|
||||
|
||||
/// NullStmt - This is the null statement ";": C99 6.8.3p3.
|
||||
///
|
||||
class NullStmt : public Stmt {
|
||||
SourceLocation SemiLoc;
|
||||
public:
|
||||
NullStmt(SourceLocation L) : Stmt(NullStmtClass), SemiLoc(L) {}
|
||||
|
||||
SourceLocation getSemiLoc() const { return SemiLoc; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == NullStmtClass;
|
||||
}
|
||||
static bool classof(const NullStmt *) { return true; }
|
||||
};
|
||||
|
||||
/// CompoundStmt - This represents a group of statements like { stmt stmt }.
|
||||
///
|
||||
class CompoundStmt : public Stmt {
|
||||
llvm::SmallVector<Stmt*, 16> Body;
|
||||
public:
|
||||
CompoundStmt(Stmt **StmtStart, unsigned NumStmts)
|
||||
: Stmt(CompoundStmtClass), Body(StmtStart, StmtStart+NumStmts) {}
|
||||
|
||||
typedef llvm::SmallVector<Stmt*, 16>::iterator body_iterator;
|
||||
body_iterator body_begin() { return Body.begin(); }
|
||||
body_iterator body_end() { return Body.end(); }
|
||||
|
||||
typedef llvm::SmallVector<Stmt*, 16>::const_iterator const_body_iterator;
|
||||
const_body_iterator body_begin() const { return Body.begin(); }
|
||||
const_body_iterator body_end() const { return Body.end(); }
|
||||
|
||||
void push_back(Stmt *S) { Body.push_back(S); }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CompoundStmtClass;
|
||||
}
|
||||
static bool classof(const CompoundStmt *) { return true; }
|
||||
};
|
||||
|
||||
class CaseStmt : public Stmt {
|
||||
Expr *LHSVal;
|
||||
Expr *RHSVal; // Non-null for GNU "case 1 ... 4" extension
|
||||
Stmt *SubStmt;
|
||||
public:
|
||||
CaseStmt(Expr *lhs, Expr *rhs, Stmt *substmt)
|
||||
: Stmt(CaseStmtClass), LHSVal(lhs), RHSVal(rhs), SubStmt(substmt) {}
|
||||
|
||||
Expr *getLHS() { return LHSVal; }
|
||||
Expr *getRHS() { return RHSVal; }
|
||||
Stmt *getSubStmt() { return SubStmt; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CaseStmtClass;
|
||||
}
|
||||
static bool classof(const CaseStmt *) { return true; }
|
||||
};
|
||||
|
||||
class DefaultStmt : public Stmt {
|
||||
Stmt *SubStmt;
|
||||
public:
|
||||
DefaultStmt(Stmt *substmt) : Stmt(DefaultStmtClass), SubStmt(substmt) {}
|
||||
|
||||
Stmt *getSubStmt() { return SubStmt; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DefaultStmtClass;
|
||||
}
|
||||
static bool classof(const DefaultStmt *) { return true; }
|
||||
};
|
||||
|
||||
class LabelStmt : public Stmt {
|
||||
SourceLocation IdentLoc;
|
||||
IdentifierInfo *Label;
|
||||
Stmt *SubStmt;
|
||||
public:
|
||||
LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt)
|
||||
: Stmt(LabelStmtClass), IdentLoc(IL), Label(label), SubStmt(substmt) {}
|
||||
|
||||
SourceLocation getIdentLoc() const { return IdentLoc; }
|
||||
IdentifierInfo *getID() const { return Label; }
|
||||
const char *getName() const;
|
||||
Stmt *getSubStmt() { return SubStmt; }
|
||||
const Stmt *getSubStmt() const { return SubStmt; }
|
||||
|
||||
void setIdentLoc(SourceLocation L) { IdentLoc = L; }
|
||||
void setSubStmt(Stmt *SS) { SubStmt = SS; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == LabelStmtClass;
|
||||
}
|
||||
static bool classof(const LabelStmt *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// IfStmt - This represents an if/then/else.
|
||||
///
|
||||
class IfStmt : public Stmt {
|
||||
Expr *Cond;
|
||||
Stmt *Then, *Else;
|
||||
public:
|
||||
IfStmt(Expr *cond, Stmt *then, Stmt *elsev = 0)
|
||||
: Stmt(IfStmtClass), Cond(cond), Then(then), Else(elsev) {}
|
||||
|
||||
const Expr *getCond() const { return Cond; }
|
||||
const Stmt *getThen() const { return Then; }
|
||||
const Stmt *getElse() const { return Else; }
|
||||
|
||||
Expr *getCond() { return Cond; }
|
||||
Stmt *getThen() { return Then; }
|
||||
Stmt *getElse() { return Else; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == IfStmtClass;
|
||||
}
|
||||
static bool classof(const IfStmt *) { return true; }
|
||||
};
|
||||
|
||||
/// SwitchStmt - This represents a 'switch' stmt.
|
||||
///
|
||||
class SwitchStmt : public Stmt {
|
||||
Expr *Cond;
|
||||
Stmt *Body;
|
||||
public:
|
||||
SwitchStmt(Expr *cond, Stmt *body)
|
||||
: Stmt(SwitchStmtClass), Cond(cond), Body(body) {}
|
||||
|
||||
Expr *getCond() { return Cond; }
|
||||
Stmt *getBody() { return Body; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == SwitchStmtClass;
|
||||
}
|
||||
static bool classof(const SwitchStmt *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// WhileStmt - This represents a 'while' stmt.
|
||||
///
|
||||
class WhileStmt : public Stmt {
|
||||
Expr *Cond;
|
||||
Stmt *Body;
|
||||
public:
|
||||
WhileStmt(Expr *cond, Stmt *body)
|
||||
: Stmt(WhileStmtClass), Cond(cond), Body(body) {}
|
||||
|
||||
Expr *getCond() { return Cond; }
|
||||
const Expr *getCond() const { return Cond; }
|
||||
Stmt *getBody() { return Body; }
|
||||
const Stmt *getBody() const { return Body; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == WhileStmtClass;
|
||||
}
|
||||
static bool classof(const WhileStmt *) { return true; }
|
||||
};
|
||||
|
||||
/// DoStmt - This represents a 'do/while' stmt.
|
||||
///
|
||||
class DoStmt : public Stmt {
|
||||
Stmt *Body;
|
||||
Expr *Cond;
|
||||
public:
|
||||
DoStmt(Stmt *body, Expr *cond)
|
||||
: Stmt(DoStmtClass), Body(body), Cond(cond) {}
|
||||
|
||||
Stmt *getBody() { return Body; }
|
||||
const Stmt *getBody() const { return Body; }
|
||||
Expr *getCond() { return Cond; }
|
||||
const Expr *getCond() const { return Cond; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DoStmtClass;
|
||||
}
|
||||
static bool classof(const DoStmt *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// ForStmt - This represents a 'for (init;cond;inc)' stmt. Note that any of
|
||||
/// the init/cond/inc parts of the ForStmt will be null if they were not
|
||||
/// specified in the source.
|
||||
///
|
||||
class ForStmt : public Stmt {
|
||||
Stmt *Init; // Expression or declstmt.
|
||||
Expr *Cond, *Inc;
|
||||
Stmt *Body;
|
||||
public:
|
||||
ForStmt(Stmt *init, Expr *cond, Expr *inc, Stmt *body)
|
||||
: Stmt(ForStmtClass), Init(init), Cond(cond), Inc(inc), Body(body) {}
|
||||
|
||||
Stmt *getInit() { return Init; }
|
||||
Expr *getCond() { return Cond; }
|
||||
Expr *getInc() { return Inc; }
|
||||
Stmt *getBody() { return Body; }
|
||||
|
||||
const Stmt *getInit() const { return Init; }
|
||||
const Expr *getCond() const { return Cond; }
|
||||
const Expr *getInc() const { return Inc; }
|
||||
const Stmt *getBody() const { return Body; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ForStmtClass;
|
||||
}
|
||||
static bool classof(const ForStmt *) { return true; }
|
||||
};
|
||||
|
||||
/// GotoStmt - This represents a direct goto.
|
||||
///
|
||||
class GotoStmt : public Stmt {
|
||||
LabelStmt *Label;
|
||||
public:
|
||||
GotoStmt(LabelStmt *label) : Stmt(GotoStmtClass), Label(label) {}
|
||||
|
||||
LabelStmt *getLabel() const { return Label; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == GotoStmtClass;
|
||||
}
|
||||
static bool classof(const GotoStmt *) { return true; }
|
||||
};
|
||||
|
||||
/// IndirectGotoStmt - This represents an indirect goto.
|
||||
///
|
||||
class IndirectGotoStmt : public Stmt {
|
||||
Expr *Target;
|
||||
public:
|
||||
IndirectGotoStmt(Expr *target) : Stmt(IndirectGotoStmtClass),
|
||||
Target(target) {}
|
||||
|
||||
Expr *getTarget() { return Target; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == IndirectGotoStmtClass;
|
||||
}
|
||||
static bool classof(const IndirectGotoStmt *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// ContinueStmt - This represents a continue.
|
||||
///
|
||||
class ContinueStmt : public Stmt {
|
||||
public:
|
||||
ContinueStmt() : Stmt(ContinueStmtClass) {}
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ContinueStmtClass;
|
||||
}
|
||||
static bool classof(const ContinueStmt *) { return true; }
|
||||
};
|
||||
|
||||
/// BreakStmt - This represents a break.
|
||||
///
|
||||
class BreakStmt : public Stmt {
|
||||
public:
|
||||
BreakStmt() : Stmt(BreakStmtClass) {}
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == BreakStmtClass;
|
||||
}
|
||||
static bool classof(const BreakStmt *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// ReturnStmt - This represents a return, optionally of an expression.
|
||||
///
|
||||
class ReturnStmt : public Stmt {
|
||||
Expr *RetExpr;
|
||||
public:
|
||||
ReturnStmt(Expr *E = 0) : Stmt(ReturnStmtClass), RetExpr(E) {}
|
||||
|
||||
const Expr *getRetValue() const { return RetExpr; }
|
||||
Expr *getRetValue() { return RetExpr; }
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ReturnStmtClass;
|
||||
}
|
||||
static bool classof(const ReturnStmt *) { return true; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,74 @@
|
|||
//===-- StmtNodes.def - Metadata about Stmt AST nodes -----------*- 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 AST Node info database.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef FIRST_STMT
|
||||
#define FIRST_STMT(n)
|
||||
#define LAST_STMT(n)
|
||||
#endif
|
||||
|
||||
#ifndef FIRST_EXPR
|
||||
#define FIRST_EXPR(n)
|
||||
#define LAST_EXPR(n)
|
||||
#endif
|
||||
|
||||
// Normal Statements.
|
||||
FIRST_STMT(1)
|
||||
STMT( 1, NullStmt , Stmt)
|
||||
STMT( 2, CompoundStmt , Stmt)
|
||||
STMT( 3, CaseStmt , Stmt)
|
||||
STMT( 4, DefaultStmt , Stmt)
|
||||
STMT( 5, LabelStmt , Stmt)
|
||||
STMT( 6, IfStmt , Stmt)
|
||||
STMT( 7, SwitchStmt , Stmt)
|
||||
STMT( 8, WhileStmt , Stmt)
|
||||
STMT( 9, DoStmt , Stmt)
|
||||
STMT(10, ForStmt , Stmt)
|
||||
STMT(11, GotoStmt , Stmt)
|
||||
STMT(12, IndirectGotoStmt, Stmt)
|
||||
STMT(13, ContinueStmt , Stmt)
|
||||
STMT(14, BreakStmt , Stmt)
|
||||
STMT(15, ReturnStmt , Stmt)
|
||||
STMT(16, DeclStmt , Stmt)
|
||||
LAST_STMT(16)
|
||||
|
||||
FIRST_EXPR(32)
|
||||
// Expressions.
|
||||
STMT(32, Expr , Stmt)
|
||||
STMT(33, DeclRefExpr , Expr)
|
||||
STMT(34, IntegerLiteral , Expr)
|
||||
STMT(35, FloatingLiteral , Expr)
|
||||
STMT(36, StringLiteral , Expr)
|
||||
STMT(37, CharacterLiteral , Expr)
|
||||
STMT(38, ParenExpr , Expr)
|
||||
STMT(39, UnaryOperator , Expr)
|
||||
STMT(40, SizeOfAlignOfTypeExpr, Expr)
|
||||
STMT(41, ArraySubscriptExpr , Expr)
|
||||
STMT(42, CallExpr , Expr)
|
||||
STMT(43, MemberExpr , Expr)
|
||||
STMT(44, CastExpr , Expr)
|
||||
STMT(45, BinaryOperator , Expr)
|
||||
STMT(46, ConditionalOperator , Expr)
|
||||
|
||||
// GNU Extensions.
|
||||
STMT(47, AddrLabel , Expr)
|
||||
|
||||
// C++ Expressions.
|
||||
STMT(48, CXXCastExpr , Expr)
|
||||
STMT(49, CXXBoolLiteralExpr , Expr)
|
||||
LAST_EXPR(49)
|
||||
|
||||
#undef STMT
|
||||
#undef FIRST_STMT
|
||||
#undef LAST_STMT
|
||||
#undef FIRST_EXPR
|
||||
#undef LAST_EXPR
|
|
@ -0,0 +1,40 @@
|
|||
//===--- StmtVisitor.h - Visitor for Stmt subclasses ------------*- 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 StmtVisitor interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_STMTVISITOR_H
|
||||
#define LLVM_CLANG_AST_STMTVISITOR_H
|
||||
|
||||
namespace clang {
|
||||
class Stmt;
|
||||
// Add prototypes for all AST node classes.
|
||||
#define STMT(N, CLASS, PARENT) \
|
||||
class CLASS;
|
||||
#include "clang/AST/StmtNodes.def"
|
||||
|
||||
/// StmtVisitor - This class implements a simple visitor for Stmt subclasses.
|
||||
/// Since Expr derives from Stmt, this also includes support for visiting Exprs.
|
||||
class StmtVisitor {
|
||||
public:
|
||||
virtual ~StmtVisitor();
|
||||
|
||||
virtual void VisitStmt(Stmt *Node) {}
|
||||
|
||||
// Implement all the methods with the StmtNodes.def file.
|
||||
#define STMT(N, CLASS, PARENT) \
|
||||
virtual void Visit##CLASS(CLASS *Node);
|
||||
#include "clang/AST/StmtNodes.def"
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,648 @@
|
|||
//===--- Type.h - C Language Family Type Representation ---------*- 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 Type interface and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_TYPE_H
|
||||
#define LLVM_CLANG_AST_TYPE_H
|
||||
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
|
||||
using llvm::isa;
|
||||
using llvm::cast;
|
||||
using llvm::cast_or_null;
|
||||
using llvm::dyn_cast;
|
||||
using llvm::dyn_cast_or_null;
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class Type;
|
||||
class TypedefDecl;
|
||||
class TagDecl;
|
||||
class RecordDecl;
|
||||
class EnumDecl;
|
||||
class Expr;
|
||||
class SourceLocation;
|
||||
|
||||
/// QualType - For efficiency, we don't store CVR-qualified types as nodes on
|
||||
/// their own: instead each reference to a type stores the qualifiers. This
|
||||
/// greatly reduces the number of nodes we need to allocate for types (for
|
||||
/// example we only need one for 'int', 'const int', 'volatile int',
|
||||
/// 'const volatile int', etc).
|
||||
///
|
||||
/// As an added efficiency bonus, instead of making this a pair, we just store
|
||||
/// the three bits we care about in the low bits of the pointer. To handle the
|
||||
/// packing/unpacking, we make QualType be a simple wrapper class that acts like
|
||||
/// a smart pointer.
|
||||
class QualType {
|
||||
uintptr_t ThePtr;
|
||||
public:
|
||||
enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ.
|
||||
Const = 0x1,
|
||||
Restrict = 0x2,
|
||||
Volatile = 0x4,
|
||||
CVRFlags = Const|Restrict|Volatile
|
||||
};
|
||||
|
||||
QualType() : ThePtr(0) {}
|
||||
|
||||
QualType(Type *Ptr, unsigned Quals) {
|
||||
assert((Quals & ~CVRFlags) == 0 && "Invalid type qualifiers!");
|
||||
ThePtr = reinterpret_cast<uintptr_t>(Ptr);
|
||||
assert((ThePtr & CVRFlags) == 0 && "Type pointer not 8-byte aligned?");
|
||||
ThePtr |= Quals;
|
||||
}
|
||||
|
||||
static QualType getFromOpaquePtr(void *Ptr) {
|
||||
QualType T;
|
||||
T.ThePtr = reinterpret_cast<uintptr_t>(Ptr);
|
||||
return T;
|
||||
}
|
||||
|
||||
unsigned getQualifiers() const {
|
||||
return ThePtr & CVRFlags;
|
||||
}
|
||||
Type *getTypePtr() const {
|
||||
return reinterpret_cast<Type*>(ThePtr & ~CVRFlags);
|
||||
}
|
||||
|
||||
void *getAsOpaquePtr() const {
|
||||
return reinterpret_cast<void*>(ThePtr);
|
||||
}
|
||||
|
||||
Type &operator*() const {
|
||||
return *getTypePtr();
|
||||
}
|
||||
|
||||
Type *operator->() const {
|
||||
return getTypePtr();
|
||||
}
|
||||
|
||||
/// isNull - Return true if this QualType doesn't point to a type yet.
|
||||
bool isNull() const {
|
||||
return ThePtr == 0;
|
||||
}
|
||||
|
||||
bool isConstQualified() const {
|
||||
return ThePtr & Const;
|
||||
}
|
||||
bool isVolatileQualified() const {
|
||||
return ThePtr & Volatile;
|
||||
}
|
||||
bool isRestrictQualified() const {
|
||||
return ThePtr & Restrict;
|
||||
}
|
||||
|
||||
QualType getQualifiedType(unsigned TQs) const {
|
||||
return QualType(getTypePtr(), TQs);
|
||||
}
|
||||
|
||||
QualType getUnqualifiedType() const {
|
||||
return QualType(getTypePtr(), 0);
|
||||
}
|
||||
|
||||
/// operator==/!= - Indicate whether the specified types and qualifiers are
|
||||
/// identical.
|
||||
bool operator==(const QualType &RHS) const {
|
||||
return ThePtr == RHS.ThePtr;
|
||||
}
|
||||
bool operator!=(const QualType &RHS) const {
|
||||
return ThePtr != RHS.ThePtr;
|
||||
}
|
||||
std::string getAsString() const {
|
||||
std::string S;
|
||||
getAsStringInternal(S);
|
||||
return S;
|
||||
}
|
||||
void getAsStringInternal(std::string &Str) const;
|
||||
|
||||
void dump(const char *s = 0) const;
|
||||
|
||||
/// getCanonicalType - Return the canonical version of this type, with the
|
||||
/// appropriate type qualifiers on it.
|
||||
inline QualType getCanonicalType() const;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // end clang.
|
||||
|
||||
namespace llvm {
|
||||
/// Implement simplify_type for QualType, so that we can dyn_cast from QualType
|
||||
/// to a specific Type class.
|
||||
template<> struct simplify_type<const ::clang::QualType> {
|
||||
typedef ::clang::Type* SimpleType;
|
||||
static SimpleType getSimplifiedValue(const ::clang::QualType &Val) {
|
||||
return Val.getTypePtr();
|
||||
}
|
||||
};
|
||||
template<> struct simplify_type< ::clang::QualType>
|
||||
: public simplify_type<const ::clang::QualType> {};
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// Type - This is the base class of the type hierarchy. A central concept
|
||||
/// with types is that each type always has a canonical type. A canonical type
|
||||
/// is the type with any typedef names stripped out of it or the types it
|
||||
/// references. For example, consider:
|
||||
///
|
||||
/// typedef int foo;
|
||||
/// typedef foo* bar;
|
||||
/// 'int *' 'foo *' 'bar'
|
||||
///
|
||||
/// There will be a Type object created for 'int'. Since int is canonical, its
|
||||
/// canonicaltype pointer points to itself. There is also a Type for 'foo' (a
|
||||
/// TypeNameType). Its CanonicalType pointer points to the 'int' Type. Next
|
||||
/// there is a PointerType that represents 'int*', which, like 'int', is
|
||||
/// canonical. Finally, there is a PointerType type for 'foo*' whose canonical
|
||||
/// type is 'int*', and there is a TypeNameType for 'bar', whose canonical type
|
||||
/// is also 'int*'.
|
||||
///
|
||||
/// Non-canonical types are useful for emitting diagnostics, without losing
|
||||
/// information about typedefs being used. Canonical types are useful for type
|
||||
/// comparisons (they allow by-pointer equality tests) and useful for reasoning
|
||||
/// about whether something has a particular form (e.g. is a function type),
|
||||
/// because they implicitly, recursively, strip all typedefs out of a type.
|
||||
///
|
||||
/// Types, once created, are immutable.
|
||||
///
|
||||
class Type {
|
||||
public:
|
||||
enum TypeClass {
|
||||
Builtin, Complex, Pointer, Reference, Array, Vector,
|
||||
FunctionNoProto, FunctionProto,
|
||||
TypeName, Tagged
|
||||
};
|
||||
private:
|
||||
QualType CanonicalType;
|
||||
|
||||
/// TypeClass bitfield - Enum that specifies what subclass this belongs to.
|
||||
/// Note that this should stay at the end of the ivars for Type so that
|
||||
/// subclasses can pack their bitfields into the same word.
|
||||
TypeClass TC : 4;
|
||||
protected:
|
||||
Type(TypeClass tc, QualType Canonical)
|
||||
: CanonicalType(Canonical.isNull() ? QualType(this,0) : Canonical), TC(tc){}
|
||||
virtual ~Type();
|
||||
friend class ASTContext;
|
||||
public:
|
||||
TypeClass getTypeClass() const { return TC; }
|
||||
|
||||
bool isCanonical() const { return CanonicalType.getTypePtr() == this; }
|
||||
|
||||
/// Types are partitioned into 3 broad categories (C99 6.2.5p1):
|
||||
/// object types, function types, and incomplete types.
|
||||
|
||||
/// isObjectType - types that fully describe objects. An object is a region
|
||||
/// of memory that can be examined and stored into (H&S).
|
||||
bool isObjectType() const;
|
||||
|
||||
/// isFunctionType - types that describe functions.
|
||||
bool isFunctionType() const;
|
||||
|
||||
/// isIncompleteType - Return true if this is an incomplete type.
|
||||
/// A type that can describe objects, but which lacks information needed to
|
||||
/// determine its size (e.g. void, or a fwd declared struct). Clients of this
|
||||
/// routine will need to determine if the size is actually required.
|
||||
bool isIncompleteType() const;
|
||||
|
||||
/// Helper methods to distinguish type categories. All type predicates
|
||||
/// operate on the canonical type, ignoring typedefs.
|
||||
bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum)
|
||||
|
||||
/// Floating point categories.
|
||||
bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double)
|
||||
bool isComplexType() const; // C99 6.2.5p11 (complex)
|
||||
bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex)
|
||||
bool isRealType() const; // C99 6.2.5p17 (real floating + integer)
|
||||
bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating)
|
||||
|
||||
/// Vector types
|
||||
bool isVectorType() const; // GCC vector type.
|
||||
|
||||
/// Derived types (C99 6.2.5p20). isFunctionType() is also a derived type.
|
||||
bool isDerivedType() const;
|
||||
bool isPointerType() const;
|
||||
bool isReferenceType() const;
|
||||
bool isArrayType() const;
|
||||
bool isStructureType() const;
|
||||
bool isUnionType() const;
|
||||
|
||||
bool isVoidType() const; // C99 6.2.5p19
|
||||
bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers)
|
||||
bool isAggregateType() const; // C99 6.2.5p21 (arrays, structures)
|
||||
|
||||
/// More type predicates useful for type checking/promotion
|
||||
bool isPromotableIntegerType() const; // C99 6.3.1.1p2
|
||||
|
||||
/// isSignedIntegerType - Return true if this is an integer type that is
|
||||
/// signed, according to C99 6.2.5p4.
|
||||
bool isSignedIntegerType() const;
|
||||
|
||||
/// isUnsignedIntegerType - Return true if this is an integer type that is
|
||||
/// unsigned, according to C99 6.2.5p6. Note that this returns true for _Bool.
|
||||
bool isUnsignedIntegerType() const;
|
||||
|
||||
/// isConstantSizeType - Return true if this is not a variable sized type,
|
||||
/// according to the rules of C99 6.7.5p3. If Loc is non-null, it is set to
|
||||
/// the location of the subexpression that makes it a vla type. It is not
|
||||
/// legal to call this on incomplete types.
|
||||
bool isConstantSizeType(SourceLocation *Loc = 0) const;
|
||||
|
||||
/// Compatibility predicates used to check assignment expressions.
|
||||
static bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
|
||||
static bool tagTypesAreCompatible(QualType, QualType); // C99 6.2.7p1
|
||||
static bool pointerTypesAreCompatible(QualType, QualType); // C99 6.7.5.1p2
|
||||
static bool referenceTypesAreCompatible(QualType, QualType); // C++ 5.17p6
|
||||
static bool functionTypesAreCompatible(QualType, QualType); // C99 6.7.5.3p15
|
||||
static bool arrayTypesAreCompatible(QualType, QualType); // C99 6.7.5.2p6
|
||||
private:
|
||||
QualType getCanonicalTypeInternal() const { return CanonicalType; }
|
||||
friend class QualType;
|
||||
public:
|
||||
virtual void getAsStringInternal(std::string &InnerString) const = 0;
|
||||
|
||||
static bool classof(const Type *) { return true; }
|
||||
};
|
||||
|
||||
/// BuiltinType - This class is used for builtin types like 'int'. Builtin
|
||||
/// types are always canonical and have a literal name field.
|
||||
class BuiltinType : public Type {
|
||||
public:
|
||||
enum Kind {
|
||||
Void,
|
||||
|
||||
Bool, // This is bool and/or _Bool.
|
||||
Char_U, // This is 'char' for targets where char is unsigned.
|
||||
UChar, // This is explicitly qualified unsigned char.
|
||||
UShort,
|
||||
UInt,
|
||||
ULong,
|
||||
ULongLong,
|
||||
|
||||
Char_S, // This is 'char' for targets where char is signed.
|
||||
SChar, // This is explicitly qualified signed char.
|
||||
Short,
|
||||
Int,
|
||||
Long,
|
||||
LongLong,
|
||||
|
||||
Float, Double, LongDouble
|
||||
};
|
||||
private:
|
||||
Kind TypeKind;
|
||||
public:
|
||||
BuiltinType(Kind K) : Type(Builtin, QualType()), TypeKind(K) {}
|
||||
|
||||
Kind getKind() const { return TypeKind; }
|
||||
const char *getName() const;
|
||||
|
||||
// the number of bits to represent the builtin type.
|
||||
unsigned getSize() const;
|
||||
|
||||
virtual void getAsStringInternal(std::string &InnerString) const;
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
|
||||
static bool classof(const BuiltinType *) { return true; }
|
||||
};
|
||||
|
||||
/// ComplexType - C99 6.2.5p11 - Complex values. This supports the C99 complex
|
||||
/// types (_Complex float etc) as well as the GCC integer complex extensions.
|
||||
///
|
||||
class ComplexType : public Type, public llvm::FoldingSetNode {
|
||||
QualType ElementType;
|
||||
ComplexType(QualType Element, QualType CanonicalPtr) :
|
||||
Type(Complex, CanonicalPtr), ElementType(Element) {
|
||||
}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
public:
|
||||
QualType getElementType() const { return ElementType; }
|
||||
|
||||
virtual void getAsStringInternal(std::string &InnerString) const;
|
||||
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getElementType());
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) {
|
||||
ID.AddPointer(Element.getAsOpaquePtr());
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Complex; }
|
||||
static bool classof(const ComplexType *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// PointerType - C99 6.7.5.1 - Pointer Declarators.
|
||||
///
|
||||
class PointerType : public Type, public llvm::FoldingSetNode {
|
||||
QualType PointeeType;
|
||||
PointerType(QualType Pointee, QualType CanonicalPtr) :
|
||||
Type(Pointer, CanonicalPtr), PointeeType(Pointee) {
|
||||
}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
public:
|
||||
|
||||
QualType getPointeeType() const { return PointeeType; }
|
||||
|
||||
virtual void getAsStringInternal(std::string &InnerString) const;
|
||||
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getPointeeType());
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) {
|
||||
ID.AddPointer(Pointee.getAsOpaquePtr());
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Pointer; }
|
||||
static bool classof(const PointerType *) { return true; }
|
||||
};
|
||||
|
||||
/// ReferenceType - C++ 8.3.2 - Reference Declarators.
|
||||
///
|
||||
class ReferenceType : public Type, public llvm::FoldingSetNode {
|
||||
QualType ReferenceeType;
|
||||
ReferenceType(QualType Referencee, QualType CanonicalRef) :
|
||||
Type(Reference, CanonicalRef), ReferenceeType(Referencee) {
|
||||
}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
public:
|
||||
virtual void getAsStringInternal(std::string &InnerString) const;
|
||||
|
||||
QualType getReferenceeType() const { return ReferenceeType; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getReferenceeType());
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType Referencee) {
|
||||
ID.AddPointer(Referencee.getAsOpaquePtr());
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Reference; }
|
||||
static bool classof(const ReferenceType *) { return true; }
|
||||
};
|
||||
|
||||
/// ArrayType - C99 6.7.5.2 - Array Declarators.
|
||||
///
|
||||
class ArrayType : public Type, public llvm::FoldingSetNode {
|
||||
public:
|
||||
/// ArraySizeModifier - Capture whether this is a normal array (e.g. int X[4])
|
||||
/// an array with a static size (e.g. int X[static 4]), or with a star size
|
||||
/// (e.g. int X[*]).
|
||||
enum ArraySizeModifier {
|
||||
Normal, Static, Star
|
||||
};
|
||||
private:
|
||||
/// NOTE: These fields are packed into the bitfields space in the Type class.
|
||||
ArraySizeModifier SizeModifier : 2;
|
||||
|
||||
/// IndexTypeQuals - Capture qualifiers in declarations like:
|
||||
/// 'int X[static restrict 4]'.
|
||||
unsigned IndexTypeQuals : 3;
|
||||
|
||||
/// ElementType - The element type of the array.
|
||||
QualType ElementType;
|
||||
|
||||
/// SizeExpr - The size is either a constant or assignment expression (for
|
||||
/// Variable Length Arrays). VLA's are only permitted within a function block.
|
||||
Expr *SizeExpr;
|
||||
|
||||
ArrayType(QualType et, ArraySizeModifier sm, unsigned tq, QualType can,
|
||||
Expr *e)
|
||||
: Type(Array, can), SizeModifier(sm), IndexTypeQuals(tq), ElementType(et),
|
||||
SizeExpr(e) {}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
public:
|
||||
|
||||
QualType getElementType() const { return ElementType; }
|
||||
ArraySizeModifier getSizeModifier() const { return SizeModifier; }
|
||||
unsigned getIndexTypeQualifier() const { return IndexTypeQuals; }
|
||||
Expr *getSize() const { return SizeExpr; }
|
||||
|
||||
virtual void getAsStringInternal(std::string &InnerString) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getSizeModifier(), getIndexTypeQualifier(), getElementType(),
|
||||
getSize());
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
ArraySizeModifier SizeModifier,
|
||||
unsigned IndexTypeQuals, QualType ElementType,
|
||||
Expr *SizeExpr) {
|
||||
ID.AddInteger(SizeModifier);
|
||||
ID.AddInteger(IndexTypeQuals);
|
||||
ID.AddPointer(ElementType.getAsOpaquePtr());
|
||||
ID.AddPointer(SizeExpr);
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Array; }
|
||||
static bool classof(const ArrayType *) { return true; }
|
||||
};
|
||||
|
||||
/// VectorType -
|
||||
///
|
||||
class VectorType : public Type, public llvm::FoldingSetNode {
|
||||
/// ElementType - The element type of the vector.
|
||||
QualType ElementType;
|
||||
|
||||
/// NumElements - The number of elements in the vector.
|
||||
unsigned NumElements;
|
||||
|
||||
VectorType(QualType vecType, unsigned vectorSize, QualType canonType) :
|
||||
Type(Vector, canonType), ElementType(vecType), NumElements(vectorSize) {}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
public:
|
||||
|
||||
QualType getElementType() const { return ElementType; }
|
||||
unsigned getNumElements() const { return NumElements; }
|
||||
|
||||
virtual void getAsStringInternal(std::string &InnerString) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getElementType(), getNumElements());
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
QualType ElementType, unsigned NumElements) {
|
||||
ID.AddPointer(ElementType.getAsOpaquePtr());
|
||||
ID.AddInteger(NumElements);
|
||||
}
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Vector; }
|
||||
static bool classof(const VectorType *) { return true; }
|
||||
};
|
||||
|
||||
/// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base
|
||||
/// class of FunctionTypeNoProto and FunctionTypeProto.
|
||||
///
|
||||
class FunctionType : public Type {
|
||||
/// SubClassData - This field is owned by the subclass, put here to pack
|
||||
/// tightly with the ivars in Type.
|
||||
bool SubClassData : 1;
|
||||
|
||||
// The type returned by the function.
|
||||
QualType ResultType;
|
||||
protected:
|
||||
FunctionType(TypeClass tc, QualType res, bool SubclassInfo,QualType Canonical)
|
||||
: Type(tc, Canonical), SubClassData(SubclassInfo), ResultType(res) {}
|
||||
bool getSubClassData() const { return SubClassData; }
|
||||
public:
|
||||
|
||||
QualType getResultType() const { return ResultType; }
|
||||
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == FunctionNoProto ||
|
||||
T->getTypeClass() == FunctionProto;
|
||||
}
|
||||
static bool classof(const FunctionType *) { return true; }
|
||||
};
|
||||
|
||||
/// FunctionTypeNoProto - Represents a K&R-style 'int foo()' function, which has
|
||||
/// no information available about its arguments.
|
||||
class FunctionTypeNoProto : public FunctionType, public llvm::FoldingSetNode {
|
||||
FunctionTypeNoProto(QualType Result, QualType Canonical)
|
||||
: FunctionType(FunctionNoProto, Result, false, Canonical) {}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
public:
|
||||
// No additional state past what FunctionType provides.
|
||||
|
||||
virtual void getAsStringInternal(std::string &InnerString) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getResultType());
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType) {
|
||||
ID.AddPointer(ResultType.getAsOpaquePtr());
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == FunctionNoProto;
|
||||
}
|
||||
static bool classof(const FunctionTypeNoProto *) { return true; }
|
||||
};
|
||||
|
||||
/// FunctionTypeProto - Represents a prototype with argument type info, e.g.
|
||||
/// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no
|
||||
/// arguments, not as having a single void argument.
|
||||
class FunctionTypeProto : public FunctionType, public llvm::FoldingSetNode {
|
||||
FunctionTypeProto(QualType Result, QualType *ArgArray, unsigned numArgs,
|
||||
bool isVariadic, QualType Canonical)
|
||||
: FunctionType(FunctionProto, Result, isVariadic, Canonical),
|
||||
NumArgs(numArgs) {
|
||||
for (unsigned i = 0; i != numArgs; ++i)
|
||||
ArgInfo[i] = ArgArray[i];
|
||||
}
|
||||
|
||||
/// NumArgs - The number of arguments this function has, not counting '...'.
|
||||
unsigned NumArgs;
|
||||
|
||||
/// ArgInfo - This array holds the argument types. Note that this is actually
|
||||
/// a variable-sized array, so it must be the last instance variable in the
|
||||
/// class.
|
||||
QualType ArgInfo[1];
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
public:
|
||||
unsigned getNumArgs() const { return NumArgs; }
|
||||
QualType getArgType(unsigned i) const {
|
||||
assert(i < NumArgs && "Invalid argument number!");
|
||||
return ArgInfo[i];
|
||||
}
|
||||
|
||||
bool isVariadic() const { return getSubClassData(); }
|
||||
|
||||
typedef const QualType *arg_type_iterator;
|
||||
arg_type_iterator arg_type_begin() const { return ArgInfo; }
|
||||
arg_type_iterator arg_type_end() const { return ArgInfo+NumArgs; }
|
||||
|
||||
virtual void getAsStringInternal(std::string &InnerString) const;
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == FunctionProto;
|
||||
}
|
||||
static bool classof(const FunctionTypeProto *) { return true; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
|
||||
QualType* ArgTys, unsigned NumArgs, bool isVariadic);
|
||||
};
|
||||
|
||||
|
||||
class TypedefType : public Type {
|
||||
TypedefDecl *Decl;
|
||||
TypedefType(TypedefDecl *D, QualType can) : Type(TypeName, can), Decl(D) {
|
||||
assert(!isa<TypedefType>(can) && "Invalid canonical type");
|
||||
}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
public:
|
||||
|
||||
TypedefDecl *getDecl() const { return Decl; }
|
||||
|
||||
virtual void getAsStringInternal(std::string &InnerString) const;
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == TypeName; }
|
||||
static bool classof(const TypedefType *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
class TagType : public Type {
|
||||
TagDecl *Decl;
|
||||
TagType(TagDecl *D, QualType can) : Type(Tagged, can), Decl(D) {}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
public:
|
||||
|
||||
TagDecl *getDecl() const { return Decl; }
|
||||
|
||||
virtual void getAsStringInternal(std::string &InnerString) const;
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Tagged; }
|
||||
static bool classof(const TagType *) { return true; }
|
||||
};
|
||||
|
||||
/// RecordType - This is a helper class that allows the use of isa/cast/dyncast
|
||||
/// to detect TagType objects of structs/unions/classes.
|
||||
class RecordType : public TagType {
|
||||
RecordType(); // DO NOT IMPLEMENT
|
||||
public:
|
||||
|
||||
RecordDecl *getDecl() const {
|
||||
return reinterpret_cast<RecordDecl*>(TagType::getDecl());
|
||||
}
|
||||
// FIXME: This predicate is a helper to QualType/Type. It needs to
|
||||
// recursively check all fields for const-ness. If any field is declared
|
||||
// const, it needs to return false.
|
||||
bool hasConstFields() const { return false; }
|
||||
|
||||
static bool classof(const Type *T);
|
||||
static bool classof(const RecordType *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// ...
|
||||
|
||||
// TODO: When we support C++, we should have types for uses of template with
|
||||
// default parameters. We should be able to distinguish source use of
|
||||
// 'std::vector<int>' from 'std::vector<int, std::allocator<int> >'. Though they
|
||||
// specify the same type, we want to print the default argument only if
|
||||
// specified in the source code.
|
||||
|
||||
/// getCanonicalType - Return the canonical version of this type, with the
|
||||
/// appropriate type qualifiers on it.
|
||||
inline QualType QualType::getCanonicalType() const {
|
||||
return QualType(getTypePtr()->getCanonicalTypeInternal().getTypePtr(),
|
||||
getQualifiers() |
|
||||
getTypePtr()->getCanonicalTypeInternal().getQualifiers());
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,158 @@
|
|||
//===--- Diagnostic.h - C Language Family Diagnostic Handling ---*- 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 Diagnostic-related interfaces.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_DIAGNOSTIC_H
|
||||
#define LLVM_CLANG_DIAGNOSTIC_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
class DiagnosticClient;
|
||||
class SourceLocation;
|
||||
class SourceRange;
|
||||
|
||||
// Import the diagnostic enums themselves.
|
||||
namespace diag {
|
||||
/// diag::kind - All of the diagnostics that can be emitted by the frontend.
|
||||
enum kind {
|
||||
#define DIAG(ENUM,FLAGS,DESC) ENUM,
|
||||
#include "DiagnosticKinds.def"
|
||||
NUM_DIAGNOSTICS
|
||||
};
|
||||
|
||||
/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
|
||||
/// to either MAP_IGNORE (nothing), MAP_WARNING (emit a warning), MAP_ERROR
|
||||
/// (emit as an error), or MAP_DEFAULT (handle the default way).
|
||||
enum Mapping {
|
||||
MAP_DEFAULT = 0, //< Do not map this diagnostic.
|
||||
MAP_IGNORE = 1, //< Map this diagnostic to nothing, ignore it.
|
||||
MAP_WARNING = 2, //< Map this diagnostic to a warning.
|
||||
MAP_ERROR = 3 //< Map this diagnostic to an error.
|
||||
};
|
||||
}
|
||||
|
||||
/// Diagnostic - This concrete class is used by the front-end to report
|
||||
/// problems and issues. It massages the diagnostics (e.g. handling things like
|
||||
/// "report warnings as errors" and passes them off to the DiagnosticClient for
|
||||
/// reporting to the user.
|
||||
class Diagnostic {
|
||||
bool WarningsAsErrors; // Treat warnings like errors:
|
||||
bool WarnOnExtensions; // Enables warnings for gcc extensions: -pedantic.
|
||||
bool ErrorOnExtensions; // Error on extensions: -pedantic-errors.
|
||||
DiagnosticClient &Client;
|
||||
|
||||
/// DiagMappings - Mapping information for diagnostics. Mapping info is
|
||||
/// packed into two bits per diagnostic.
|
||||
unsigned char DiagMappings[(diag::NUM_DIAGNOSTICS+3)/4];
|
||||
|
||||
/// ErrorOccurred - This is set to true when an error is emitted, and is
|
||||
/// sticky.
|
||||
bool ErrorOccurred;
|
||||
|
||||
unsigned NumDiagnostics; // Number of diagnostics reported
|
||||
unsigned NumErrors; // Number of diagnostics that are errors
|
||||
public:
|
||||
explicit Diagnostic(DiagnosticClient &client);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Diagnostic characterization methods, used by a client to customize how
|
||||
//
|
||||
const DiagnosticClient &getClient() const { return Client; };
|
||||
|
||||
/// setWarningsAsErrors - When set to true, any warnings reported are issued
|
||||
/// as errors.
|
||||
void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; }
|
||||
bool getWarningsAsErrors() const { return WarningsAsErrors; }
|
||||
|
||||
/// setWarnOnExtensions - When set to true, issue warnings on GCC extensions,
|
||||
/// the equivalent of GCC's -pedantic.
|
||||
void setWarnOnExtensions(bool Val) { WarnOnExtensions = Val; }
|
||||
bool getWarnOnExtensions() const { return WarnOnExtensions; }
|
||||
|
||||
/// setErrorOnExtensions - When set to true issue errors for GCC extensions
|
||||
/// instead of warnings. This is the equivalent to GCC's -pedantic-errors.
|
||||
void setErrorOnExtensions(bool Val) { ErrorOnExtensions = Val; }
|
||||
bool getErrorOnExtensions() const { return ErrorOnExtensions; }
|
||||
|
||||
/// setDiagnosticMapping - This allows the client to specify that certain
|
||||
/// warnings are ignored. Only NOTEs, WARNINGs, and EXTENSIONs can be mapped.
|
||||
void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) {
|
||||
assert(isNoteWarningOrExtension(Diag) && "Cannot map errors!");
|
||||
unsigned char &Slot = DiagMappings[Diag/4];
|
||||
unsigned Bits = (Diag & 3)*2;
|
||||
Slot &= ~(3 << Bits);
|
||||
Slot |= Map << Bits;
|
||||
}
|
||||
|
||||
/// getDiagnosticMapping - Return the mapping currently set for the specified
|
||||
/// diagnostic.
|
||||
diag::Mapping getDiagnosticMapping(diag::kind Diag) const {
|
||||
return (diag::Mapping)((DiagMappings[Diag/4] >> (Diag & 3)*2) & 3);
|
||||
}
|
||||
|
||||
bool hasErrorOccurred() const { return ErrorOccurred; }
|
||||
|
||||
unsigned getNumErrors() const { return NumErrors; }
|
||||
unsigned getNumDiagnostics() const { return NumDiagnostics; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Diagnostic classification and reporting interfaces.
|
||||
//
|
||||
|
||||
/// getDescription - Given a diagnostic ID, return a description of the
|
||||
/// issue.
|
||||
static const char *getDescription(unsigned DiagID);
|
||||
|
||||
/// Level - The level of the diagnostic
|
||||
enum Level {
|
||||
Ignored, Note, Warning, Error, Fatal, Sorry
|
||||
};
|
||||
|
||||
/// isNoteWarningOrExtension - Return true if the unmapped diagnostic level of
|
||||
/// the specified diagnostic ID is a Note, Warning, or Extension.
|
||||
static bool isNoteWarningOrExtension(unsigned DiagID);
|
||||
|
||||
/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
|
||||
/// object, classify the specified diagnostic ID into a Level, consumable by
|
||||
/// the DiagnosticClient.
|
||||
Level getDiagnosticLevel(unsigned DiagID) const;
|
||||
|
||||
/// Report - Issue the message to the client. DiagID is a member of the
|
||||
/// diag::kind enum.
|
||||
void Report(SourceLocation Pos, unsigned DiagID,
|
||||
const std::string *Strs = 0, unsigned NumStrs = 0,
|
||||
const SourceRange *Ranges = 0, unsigned NumRanges = 0);
|
||||
};
|
||||
|
||||
/// DiagnosticClient - This is an abstract interface implemented by clients of
|
||||
/// the front-end, which formats and prints fully processed diagnostics.
|
||||
class DiagnosticClient {
|
||||
public:
|
||||
virtual ~DiagnosticClient();
|
||||
|
||||
/// IgnoreDiagnostic - If the client wants to ignore this diagnostic, then
|
||||
/// return true.
|
||||
virtual bool IgnoreDiagnostic(Diagnostic::Level DiagLevel,
|
||||
SourceLocation Pos) = 0;
|
||||
|
||||
/// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
|
||||
/// capturing it to a log as needed.
|
||||
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, SourceLocation Pos,
|
||||
diag::kind ID, const std::string *Strs,
|
||||
unsigned NumStrs, const SourceRange *Ranges,
|
||||
unsigned NumRanges) = 0;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,668 @@
|
|||
//===-- DiagnosticKinds.def - C Family Diagnostic Kind 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 DiagnosticKind database.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Flags for diagnostic:
|
||||
//
|
||||
// DIAG_TYPE - Allows one of:
|
||||
// NOTE - Informational message.
|
||||
// WARNING - Warning.
|
||||
// EXTENSION - Notification that an extension to the language is being used.
|
||||
// ERROR - Error, compilation will stop after parsing completes.
|
||||
// FATAL - Fatal error: parsing must stop.
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Portability
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
DIAG(port_target_macro_use, NOTE,
|
||||
"use of a target-specific macro, source is not 'portable'")
|
||||
|
||||
DIAG(port_target_builtin_use, NOTE,
|
||||
"use of a target-specific builtin function, source is not 'portable'")
|
||||
|
||||
DIAG(port_wchar_t, NOTE,
|
||||
"sizeof(wchar_t) varies between targets, source is not 'portable'")
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Lexer Diagnostics
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
DIAG(null_in_string, WARNING,
|
||||
"null character(s) preserved in string literal")
|
||||
DIAG(null_in_char , WARNING,
|
||||
"null character(s) preserved in character literal")
|
||||
DIAG(null_in_file , WARNING,
|
||||
"null character ignored")
|
||||
DIAG(nested_block_comment, WARNING,
|
||||
"\"/*\" within block comment")
|
||||
DIAG(escaped_newline_block_comment_end, WARNING,
|
||||
"escaped newline between */ characters at block comment end")
|
||||
DIAG(backslash_newline_space, WARNING,
|
||||
"backslash and newline separated by space")
|
||||
|
||||
// Trigraphs.
|
||||
DIAG(trigraph_ignored, WARNING, "trigraph ignored")
|
||||
DIAG(trigraph_ignored_block_comment, WARNING,
|
||||
"ignored trigraph would end block comment")
|
||||
DIAG(trigraph_ends_block_comment, WARNING,
|
||||
"trigraph ends block comment")
|
||||
DIAG(trigraph_converted, WARNING,
|
||||
"trigraph converted to '%0' character")
|
||||
|
||||
DIAG(ext_multi_line_bcpl_comment, EXTENSION,
|
||||
"multi-line // comment")
|
||||
DIAG(ext_bcpl_comment, EXTENSION,
|
||||
"// comments are not allowed in this language")
|
||||
DIAG(ext_no_newline_eof, EXTENSION,
|
||||
"no newline at end of file")
|
||||
DIAG(ext_backslash_newline_eof, EXTENSION,
|
||||
"backslash-newline at end of file")
|
||||
DIAG(ext_dollar_in_identifier, EXTENSION,
|
||||
"'$' in identifier")
|
||||
DIAG(charize_microsoft_ext, EXTENSION,
|
||||
"@# is a microsoft extension")
|
||||
|
||||
DIAG(ext_token_used, EXTENSION,
|
||||
"extension used")
|
||||
|
||||
DIAG(err_unterminated_string, ERROR,
|
||||
"missing terminating \" character")
|
||||
DIAG(err_unterminated_char, ERROR,
|
||||
"missing terminating ' character")
|
||||
DIAG(err_empty_character, ERROR,
|
||||
"empty character constant")
|
||||
DIAG(err_unterminated_block_comment, ERROR,
|
||||
"unterminated /* comment")
|
||||
DIAG(err_invalid_character_to_charify, ERROR,
|
||||
"invalid argument to convert to character")
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Preprocessor Diagnostics
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
DIAG(pp_hash_warning, WARNING,
|
||||
"#warning%0")
|
||||
DIAG(pp_include_next_in_primary, WARNING,
|
||||
"#include_next in primary source file")
|
||||
DIAG(pp_include_next_absolute_path, WARNING,
|
||||
"#include_next with absolute path")
|
||||
DIAG(ext_c99_whitespace_required_after_macro_name, WARNING,
|
||||
"ISO C99 requires whitespace after the macro name")
|
||||
DIAG(pp_pragma_once_in_main_file, WARNING,
|
||||
"#pragma once in main file")
|
||||
DIAG(pp_pragma_sysheader_in_main_file, WARNING,
|
||||
"#pragma system_header ignored in main file")
|
||||
DIAG(pp_poisoning_existing_macro, WARNING,
|
||||
"poisoning existing macro")
|
||||
DIAG(pp_out_of_date_dependency, WARNING,
|
||||
"current file is older than dependency %0")
|
||||
DIAG(pp_undef_builtin_macro, WARNING,
|
||||
"undefining builtin macro")
|
||||
DIAG(pp_redef_builtin_macro, WARNING,
|
||||
"redefining builtin macro")
|
||||
DIAG(pp_macro_not_used, WARNING, // -Wunused-macros
|
||||
"macro is not used")
|
||||
DIAG(pp_invalid_string_literal, WARNING,
|
||||
"invalid string literal, ignoring final '\\'")
|
||||
DIAG(warn_pp_expr_overflow, WARNING,
|
||||
"integer overflow in preprocessor expression")
|
||||
DIAG(warn_pp_convert_lhs_to_positive, WARNING,
|
||||
"left side of operator converted from negative value to unsigned: %0")
|
||||
DIAG(warn_pp_convert_rhs_to_positive, WARNING,
|
||||
"right side of operator converted from negative value to unsigned: %0")
|
||||
|
||||
DIAG(ext_pp_import_directive, EXTENSION,
|
||||
"#import is a language extension")
|
||||
DIAG(ext_pp_ident_directive, EXTENSION,
|
||||
"#ident is a language extension")
|
||||
DIAG(ext_pp_include_next_directive, EXTENSION,
|
||||
"#include_next is a language extension")
|
||||
DIAG(ext_pp_warning_directive, EXTENSION,
|
||||
"#warning is a language extension")
|
||||
DIAG(ext_pp_extra_tokens_at_eol, EXTENSION,
|
||||
"extra tokens at end of %0 directive")
|
||||
DIAG(ext_pp_comma_expr, EXTENSION,
|
||||
"comma operator in operand of #if")
|
||||
DIAG(ext_pp_bad_vaargs_use, EXTENSION,
|
||||
"__VA_ARGS__ can only appear in the expansion of a C99 variadic macro")
|
||||
DIAG(ext_pp_macro_redef, EXTENSION,
|
||||
"\"%0\" macro redefined")
|
||||
DIAG(ext_pp_macro_redef2, EXTENSION,
|
||||
"this is previous definition")
|
||||
DIAG(ext_variadic_macro, EXTENSION,
|
||||
"variadic macros were introduced in C99")
|
||||
DIAG(ext_named_variadic_macro, EXTENSION,
|
||||
"named variadic macros are a GNU extension")
|
||||
DIAG(ext_embedded_directive, EXTENSION,
|
||||
"embedding a directive within macro arguments is not portable")
|
||||
DIAG(ext_missing_varargs_arg, EXTENSION,
|
||||
"varargs argument missing, but tolerated as an extension")
|
||||
DIAG(ext_empty_fnmacro_arg, EXTENSION,
|
||||
"empty macro arguments were standardized in C99")
|
||||
|
||||
DIAG(ext_pp_base_file, EXTENSION,
|
||||
"__BASE_FILE__ is a language extension")
|
||||
DIAG(ext_pp_include_level, EXTENSION,
|
||||
"__INCLUDE_LEVEL__ is a language extension")
|
||||
DIAG(ext_pp_timestamp, EXTENSION,
|
||||
"__TIMESTAMP__ is a language extension")
|
||||
|
||||
DIAG(err_pp_invalid_directive, ERROR,
|
||||
"invalid preprocessing directive")
|
||||
DIAG(err_pp_hash_error, ERROR,
|
||||
"#error%0")
|
||||
DIAG(err_pp_file_not_found, ERROR,
|
||||
"'%0' file not found")
|
||||
DIAG(err_pp_empty_filename, ERROR,
|
||||
"empty filename")
|
||||
DIAG(err_pp_include_too_deep, ERROR,
|
||||
"#include nested too deeply")
|
||||
DIAG(err_pp_expects_filename, ERROR,
|
||||
"expected \"FILENAME\" or <FILENAME>")
|
||||
DIAG(err_pp_macro_not_identifier, ERROR,
|
||||
"macro names must be identifiers")
|
||||
DIAG(err_pp_missing_macro_name, ERROR,
|
||||
"macro name missing")
|
||||
DIAG(err_pp_missing_rparen_in_macro_def, ERROR,
|
||||
"missing ')' in macro parameter list")
|
||||
DIAG(err_pp_invalid_tok_in_arg_list, ERROR,
|
||||
"invalid token in macro parameter list")
|
||||
DIAG(err_pp_expected_ident_in_arg_list, ERROR,
|
||||
"expected identifier in macro parameter list")
|
||||
DIAG(err_pp_expected_comma_in_arg_list, ERROR,
|
||||
"expected comma in macro parameter list")
|
||||
DIAG(err_pp_duplicate_name_in_arg_list, ERROR,
|
||||
"duplicate macro parameter name \"%0\"")
|
||||
DIAG(err_pp_stringize_not_parameter, ERROR,
|
||||
"'#' is not followed by a macro parameter")
|
||||
DIAG(err_pp_malformed_ident, ERROR,
|
||||
"invalid #ident directive")
|
||||
DIAG(err_pp_unterminated_conditional, ERROR,
|
||||
"unterminated conditional directive")
|
||||
DIAG(pp_err_else_after_else, ERROR,
|
||||
"#else after #else")
|
||||
DIAG(pp_err_elif_after_else, ERROR,
|
||||
"#elif after #else")
|
||||
DIAG(pp_err_else_without_if, ERROR,
|
||||
"#else without #if")
|
||||
DIAG(pp_err_elif_without_if, ERROR,
|
||||
"#elif without #if")
|
||||
DIAG(err_pp_endif_without_if, ERROR,
|
||||
"#endif without #if")
|
||||
DIAG(err_pp_expected_value_in_expr, ERROR,
|
||||
"expected value in expression")
|
||||
DIAG(err_pp_missing_val_before_operator, ERROR,
|
||||
"missing value before operator")
|
||||
DIAG(err_pp_expected_rparen, ERROR,
|
||||
"expected ')' in preprocessor expression")
|
||||
DIAG(err_pp_expected_eol, ERROR,
|
||||
"expected end of line in preprocessor expression")
|
||||
DIAG(err_pp_defined_requires_identifier, ERROR,
|
||||
"operator \"defined\" requires an identifier")
|
||||
DIAG(err_pp_missing_rparen, ERROR,
|
||||
"missing ')' after \"defined\"")
|
||||
DIAG(err_pp_colon_without_question, ERROR,
|
||||
"':' without preceding '?'")
|
||||
DIAG(err_pp_question_without_colon, ERROR,
|
||||
"'?' without following ':'")
|
||||
DIAG(err_pp_division_by_zero, ERROR,
|
||||
"division by zero in preprocessor expression")
|
||||
DIAG(err_pp_remainder_by_zero, ERROR,
|
||||
"remainder by zero in preprocessor expression")
|
||||
DIAG(err_pp_expr_bad_token, ERROR,
|
||||
"token is not valid in preprocessor expressions")
|
||||
DIAG(err_pp_invalid_poison, ERROR,
|
||||
"can only poison identifier tokens")
|
||||
DIAG(err_pp_used_poisoned_id, ERROR,
|
||||
"attempt to use a poisoned identifier")
|
||||
DIAG(err__Pragma_malformed, ERROR,
|
||||
"_Pragma takes a parenthesized string literal")
|
||||
DIAG(err_defined_macro_name, ERROR,
|
||||
"\"defined\" cannot be used as a macro name")
|
||||
DIAG(err_paste_at_start, ERROR,
|
||||
"\"##\" cannot appear at start of macro expansion")
|
||||
DIAG(err_paste_at_end, ERROR,
|
||||
"\"##\" cannot appear at end of macro expansion")
|
||||
DIAG(err_unterm_macro_invoc, ERROR,
|
||||
"unterminated function-like macro invocation")
|
||||
DIAG(err_too_many_args_in_macro_invoc, ERROR,
|
||||
"too many arguments provided to function-like macro invocation")
|
||||
DIAG(err_too_few_args_in_macro_invoc, ERROR,
|
||||
"too few arguments provided to function-like macro invocation")
|
||||
DIAG(err_pp_bad_paste, ERROR,
|
||||
"pasting formed \"%0\", an invalid preprocessing token")
|
||||
DIAG(err_pp_operator_used_as_macro_name, ERROR,
|
||||
"C++ operator \"%0\" cannot be used as a macro name")
|
||||
DIAG(err_pp_illegal_floating_literal, ERROR,
|
||||
"floating point literal in preprocessor expression")
|
||||
|
||||
// Should be a sorry?
|
||||
DIAG(err_pp_I_dash_not_supported, ERROR,
|
||||
"-I- not supported, please use -iquote instead")
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Parser Diagnostics
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
DIAG(w_type_defaults_to_int, WARNING,
|
||||
"type defaults to 'int'")
|
||||
DIAG(w_no_declarators, WARNING,
|
||||
"declaration does not declare anything")
|
||||
DIAG(w_asm_qualifier_ignored, WARNING,
|
||||
"ignored %0 qualifier on asm")
|
||||
|
||||
DIAG(ext_empty_source_file, EXTENSION,
|
||||
"ISO C forbids an empty source file")
|
||||
DIAG(ext_top_level_semi, EXTENSION,
|
||||
"ISO C does not allow an extra ';' outside of a function")
|
||||
DIAG(ext_extra_struct_semi, EXTENSION,
|
||||
"ISO C does not allow an extra ';' inside a struct or union")
|
||||
DIAG(ext_duplicate_declspec, EXTENSION,
|
||||
"duplicate '%0' declaration specifier")
|
||||
DIAG(ext_plain_complex, EXTENSION,
|
||||
"ISO C does not support plain '_Complex' meaning '_Complex double'")
|
||||
DIAG(ext_integer_complex, EXTENSION,
|
||||
"ISO C does not support complex integer types")
|
||||
DIAG(ext_thread_before, EXTENSION,
|
||||
"'__thread' before 'static'")
|
||||
|
||||
DIAG(ext_empty_struct_union_enum, EXTENSION,
|
||||
"use of empty %0 extension")
|
||||
|
||||
DIAG(ext_ident_list_in_param, EXTENSION,
|
||||
"type-less parameter names in function declaration")
|
||||
DIAG(ext_c99_array_usage, EXTENSION,
|
||||
"use of C99-specific array features")
|
||||
DIAG(ext_c99_variable_decl_in_for_loop, EXTENSION,
|
||||
"variable declaration in for loop is a C99-specific feature")
|
||||
DIAG(ext_c99_compound_literal, EXTENSION,
|
||||
"compound literals are a C99-specific feature")
|
||||
DIAG(ext_c99_enumerator_list_comma, EXTENSION,
|
||||
"commas at the end of enumerator lists are a C99-specific feature")
|
||||
|
||||
DIAG(ext_gnu_indirect_goto, EXTENSION,
|
||||
"use of GNU indirect-goto extension")
|
||||
DIAG(ext_gnu_address_of_label, EXTENSION,
|
||||
"use of GNU address-of-label extension")
|
||||
DIAG(ext_gnu_statement_expr, EXTENSION,
|
||||
"use of GNU statement expression extension")
|
||||
DIAG(ext_gnu_conditional_expr, EXTENSION,
|
||||
"use of GNU ?: expression extension, eliding middle term")
|
||||
DIAG(ext_gnu_empty_initializer, EXTENSION,
|
||||
"use of GNU empty initializer extension")
|
||||
DIAG(ext_gnu_array_range, EXTENSION,
|
||||
"use of GNU array range extension")
|
||||
DIAG(ext_gnu_missing_equal_designator, EXTENSION,
|
||||
"use of GNU 'missing =' extension in designator")
|
||||
DIAG(ext_gnu_old_style_field_designator, EXTENSION,
|
||||
"use of GNU old-style field designator extension")
|
||||
DIAG(ext_gnu_case_range, EXTENSION,
|
||||
"use of GNU case range extension")
|
||||
|
||||
// Generic errors.
|
||||
DIAG(err_parse_error, ERROR,
|
||||
"parse error")
|
||||
DIAG(err_expected_expression, ERROR,
|
||||
"expected expression")
|
||||
DIAG(err_expected_external_declaration, ERROR,
|
||||
"expected external declaration")
|
||||
DIAG(err_expected_ident, ERROR,
|
||||
"expected identifier")
|
||||
DIAG(err_expected_ident_lparen, ERROR,
|
||||
"expected identifier or '('")
|
||||
DIAG(err_expected_ident_lbrace, ERROR,
|
||||
"expected identifier or '{'")
|
||||
DIAG(err_expected_rparen, ERROR,
|
||||
"expected ')'")
|
||||
DIAG(err_expected_rsquare, ERROR,
|
||||
"expected ']'")
|
||||
DIAG(err_expected_rbrace, ERROR,
|
||||
"expected '}'")
|
||||
DIAG(err_expected_greater, ERROR,
|
||||
"expected '>'")
|
||||
DIAG(err_expected_semi_decl_list, ERROR,
|
||||
"expected ';' at end of declaration list")
|
||||
DIAG(ext_expected_semi_decl_list, EXTENSION,
|
||||
"expected ';' at end of declaration list")
|
||||
DIAG(err_expected_fn_body, ERROR,
|
||||
"expected function body after function declarator")
|
||||
DIAG(err_expected_after_declarator, ERROR,
|
||||
"expected '=', ',', ';', 'asm', or '__attribute__' after declarator")
|
||||
DIAG(err_expected_statement, ERROR,
|
||||
"expected statement")
|
||||
DIAG(err_expected_lparen_after, ERROR,
|
||||
"expected '(' after '%0'")
|
||||
DIAG(err_expected_less_after, ERROR,
|
||||
"expected '<' after '%0'")
|
||||
DIAG(err_expected_comma, ERROR,
|
||||
"expected ','")
|
||||
DIAG(err_expected_lbrace_in_compound_literal, ERROR,
|
||||
"expected '{' in compound literal")
|
||||
DIAG(err_expected_while, ERROR,
|
||||
"expected 'while' in do/while loop")
|
||||
DIAG(err_expected_semi_after, ERROR,
|
||||
"expected ';' after %0")
|
||||
DIAG(err_expected_semi_after_expr, ERROR,
|
||||
"expected ';' after expression")
|
||||
DIAG(err_expected_semi_for, ERROR,
|
||||
"expected ';' in 'for' statement specifier")
|
||||
DIAG(err_expected_colon_after, ERROR,
|
||||
"expected ':' after %0")
|
||||
DIAG(err_label_end_of_compound_statement, ERROR,
|
||||
"label at end of compound statement: expected statement")
|
||||
DIAG(err_expected_colon, ERROR,
|
||||
"expected ':'")
|
||||
DIAG(err_expected_string_literal, ERROR,
|
||||
"expected string literal")
|
||||
DIAG(err_expected_asm_operand, ERROR,
|
||||
"expected string literal or '[' for asm operand")
|
||||
|
||||
DIAG(err_unexpected_at, ERROR,
|
||||
"unexpected '@' in program")
|
||||
|
||||
/// err_matching - this is used as a continuation of a previous error, e.g. to
|
||||
/// specify the '(' when we expected a ')'. This should probably be some
|
||||
/// special sort of diagnostic kind to indicate that it is the second half of
|
||||
/// the previous diagnostic.
|
||||
DIAG(err_matching, ERROR,
|
||||
"to match this '%0'")
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Semantic Analysis
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Semantic analysis of string and character constant literals.
|
||||
DIAG(ext_nonstandard_escape, EXTENSION,
|
||||
"use of non-standard escape character '\\%0'")
|
||||
DIAG(ext_unknown_escape, EXTENSION,
|
||||
"unknown escape sequence '\\%0'")
|
||||
DIAG(warn_extraneous_wide_char_constant, WARNING,
|
||||
"extraneous characters in wide character constant ignored")
|
||||
DIAG(warn_char_constant_too_large, WARNING,
|
||||
"character constant too long for its type")
|
||||
DIAG(warn_hex_escape_too_large, WARNING,
|
||||
"hex escape sequence out of range")
|
||||
DIAG(warn_octal_escape_too_large, WARNING,
|
||||
"octal escape sequence out of range")
|
||||
|
||||
DIAG(err_hex_escape_no_digits, ERROR,
|
||||
"\\x used with no following hex digits")
|
||||
|
||||
// Declarations.
|
||||
DIAG(err_typename_requires_specqual, ERROR,
|
||||
"type name requires a specifier or qualifier")
|
||||
DIAG(err_typename_invalid_storageclass, ERROR,
|
||||
"type name does not allow storage class to be specified")
|
||||
DIAG(err_typename_invalid_functionspec, ERROR,
|
||||
"type name does not allow function specifier to be specified")
|
||||
DIAG(err_invalid_decl_spec_combination, ERROR,
|
||||
"cannot combine with previous '%0' declaration specifier")
|
||||
DIAG(err_invalid_sign_spec, ERROR,
|
||||
"'%0' cannot be signed or unsigned")
|
||||
DIAG(err_invalid_short_spec, ERROR,
|
||||
"'short %0' is invalid")
|
||||
DIAG(err_invalid_long_spec, ERROR,
|
||||
"'long %0' is invalid")
|
||||
DIAG(err_invalid_longlong_spec, ERROR,
|
||||
"'long long %0' is invalid")
|
||||
DIAG(err_invalid_complex_spec, ERROR,
|
||||
"'_Complex %0' is invalid")
|
||||
DIAG(err_invalid_thread_spec, ERROR,
|
||||
"'__thread %0' is invalid")
|
||||
DIAG(err_ellipsis_first_arg, ERROR,
|
||||
"ISO C requires a named argument before '...'")
|
||||
DIAG(err_unspecified_vla_size_with_static, ERROR,
|
||||
"'static' may not be used with an unspecified variable length array size")
|
||||
DIAG(err_invalid_storage_class_in_func_decl, ERROR,
|
||||
"invalid storage class specifier in function declarator")
|
||||
DIAG(err_invalid_reference_qualifier_application, ERROR,
|
||||
"'%0' qualifier may not be applied to a reference")
|
||||
|
||||
// Attributes
|
||||
DIAG(err_attribute_wrong_number_arguments, ERROR,
|
||||
"attribute requires %0 argument(s)")
|
||||
DIAG(err_attribute_invalid_vector_type, ERROR,
|
||||
"invalid vector type '%0'")
|
||||
DIAG(err_attribute_vector_size_not_int, ERROR,
|
||||
"vector_size requires integer constant")
|
||||
DIAG(err_attribute_invalid_size, ERROR,
|
||||
"vector size not an integral multiple of component size")
|
||||
DIAG(err_attribute_zero_size, ERROR,
|
||||
"zero vector size")
|
||||
DIAG(err_typecheck_vector_not_convertable, ERROR,
|
||||
"can't convert between vector values of different size ('%0' and '%1')")
|
||||
|
||||
// Function Parameter Semantic Analysis.
|
||||
DIAG(err_void_param_with_identifier, ERROR,
|
||||
"void argument may not have a name")
|
||||
DIAG(err_void_only_param, ERROR,
|
||||
"'void' must be the first and only parameter if specified")
|
||||
DIAG(err_void_param_qualified, ERROR,
|
||||
"'void' as parameter must not have type qualifiers")
|
||||
DIAG(err_param_redefinition, ERROR,
|
||||
"redefinition of parameter '%0'")
|
||||
DIAG(err_ident_list_in_fn_declaration, ERROR,
|
||||
"a parameter list without types is only allowed in a function definition")
|
||||
DIAG(err_declaration_does_not_declare_param, ERROR,
|
||||
"declaration does not declare a parameter")
|
||||
DIAG(err_no_matching_param, ERROR,
|
||||
"parameter named '%0' is missing")
|
||||
DIAG(ext_param_not_declared, EXTENSION,
|
||||
"parameter '%0' was not declared, defaulting to type 'int'")
|
||||
|
||||
DIAG(err_previous_definition, ERROR,
|
||||
"previous definition is here")
|
||||
DIAG(err_previous_use, ERROR,
|
||||
"previous use is here")
|
||||
|
||||
DIAG(err_unexpected_typedef, ERROR,
|
||||
"unexpected type name '%0': expected expression")
|
||||
DIAG(err_undeclared_var_use, ERROR,
|
||||
"use of undeclared identifier '%0'")
|
||||
DIAG(err_redefinition, ERROR,
|
||||
"redefinition of '%0'")
|
||||
DIAG(err_redefinition_different_kind, ERROR,
|
||||
"redefinition of '%0' as different kind of symbol")
|
||||
DIAG(err_nested_redefinition, ERROR,
|
||||
"nested redefinition of '%0'")
|
||||
DIAG(err_use_with_wrong_tag, ERROR,
|
||||
"use of '%0' with tag type that does not match previous declaration")
|
||||
DIAG(ext_forward_ref_enum, EXTENSION,
|
||||
"ISO C forbids forward references to 'enum' types")
|
||||
DIAG(err_redefinition_of_enumerator, ERROR,
|
||||
"redefinition of enumerator '%0'")
|
||||
DIAG(err_duplicate_member, ERROR,
|
||||
"duplicate member '%0'")
|
||||
DIAG(err_enum_value_not_integer_constant_expr, ERROR,
|
||||
"enumerator value for '%0' is not an integer constant")
|
||||
DIAG(err_case_label_not_integer_constant_expr, ERROR,
|
||||
"case label does not reduce to an integer constant")
|
||||
DIAG(err_typecheck_illegal_vla, ERROR,
|
||||
"variable length array declared outside of any function")
|
||||
DIAG(err_typecheck_negative_array_size, ERROR,
|
||||
"array size is negative")
|
||||
DIAG(err_typecheck_zero_array_size, EXTENSION,
|
||||
"zero size arrays are an extension")
|
||||
DIAG(err_array_size_non_int, ERROR,
|
||||
"size of array has non-integer type '%0'")
|
||||
|
||||
DIAG(err_redefinition_of_label, ERROR,
|
||||
"redefinition of label '%0'")
|
||||
DIAG(err_undeclared_label_use, ERROR,
|
||||
"use of undeclared label '%0'")
|
||||
|
||||
DIAG(warn_implicit_function_decl, WARNING,
|
||||
"implicit declaration of function '%0'")
|
||||
DIAG(ext_implicit_function_decl, EXTENSION,
|
||||
"implicit declaration of function '%0' is invalid in C99")
|
||||
|
||||
DIAG(err_field_declared_as_function, ERROR,
|
||||
"field '%0' declared as a function")
|
||||
DIAG(err_field_incomplete, ERROR,
|
||||
"field '%0' has incomplete type")
|
||||
DIAG(err_variable_sized_type_in_struct, EXTENSION,
|
||||
"variable sized type '%0' must be at end of struct or class")
|
||||
DIAG(err_flexible_array_empty_struct, ERROR,
|
||||
"flexible array '%0' not allowed in otherwise empty struct")
|
||||
DIAG(ext_flexible_array_in_struct, EXTENSION,
|
||||
"'%0' may not be nested in a struct due to flexible array member")
|
||||
DIAG(err_flexible_array_in_array, ERROR,
|
||||
"'%0' may not be used as an array element due to flexible array member")
|
||||
DIAG(err_illegal_decl_array_of_functions, ERROR,
|
||||
"'%0' declared as array of functions")
|
||||
DIAG(err_illegal_decl_array_incomplete_type, ERROR,
|
||||
"array has incomplete element type '%0'")
|
||||
DIAG(err_illegal_decl_array_of_references, ERROR,
|
||||
"'%0' declared as array of references")
|
||||
DIAG(err_illegal_decl_pointer_to_reference, ERROR,
|
||||
"'%0' declared as a pointer to a reference")
|
||||
DIAG(err_illegal_decl_reference_to_reference, ERROR,
|
||||
"'%0' declared as a reference to a reference")
|
||||
|
||||
// Expressions.
|
||||
DIAG(ext_sizeof_function_type, EXTENSION,
|
||||
"invalid application of 'sizeof' to a function type")
|
||||
DIAG(ext_sizeof_void_type, EXTENSION,
|
||||
"invalid application of '%0' to a void type")
|
||||
DIAG(err_sizeof_incomplete_type, ERROR,
|
||||
"invalid application of 'sizeof' to an incomplete type '%0'")
|
||||
DIAG(err_alignof_incomplete_type, ERROR,
|
||||
"invalid application of '__alignof' to an incomplete type '%0'")
|
||||
DIAG(err_invalid_suffix_integer_constant, ERROR,
|
||||
"invalid suffix '%0' on integer constant")
|
||||
DIAG(err_invalid_suffix_float_constant, ERROR,
|
||||
"invalid suffix '%0' on floating constant")
|
||||
DIAG(warn_integer_too_large, WARNING,
|
||||
"integer constant is too large for its type")
|
||||
DIAG(warn_integer_too_large_for_signed, WARNING,
|
||||
"integer constant is so large that it is unsigned")
|
||||
DIAG(err_exponent_has_no_digits, ERROR,
|
||||
"exponent has no digits")
|
||||
DIAG(ext_binary_literal, EXTENSION,
|
||||
"binary integer literals are an extension")
|
||||
DIAG(err_invalid_binary_digit, ERROR,
|
||||
"invalid digit '%0' in binary constant")
|
||||
DIAG(err_invalid_octal_digit, ERROR,
|
||||
"invalid digit '%0' in octal constant")
|
||||
DIAG(err_invalid_decimal_digit, ERROR,
|
||||
"invalid digit '%0' in decimal constant")
|
||||
DIAG(err_hexconstant_requires_exponent, ERROR,
|
||||
"hexadecimal floating constants require an exponent")
|
||||
DIAG(err_typecheck_subscript_value, ERROR,
|
||||
"subscripted value is neither array nor pointer")
|
||||
DIAG(err_typecheck_subscript, ERROR,
|
||||
"array subscript is not an integer")
|
||||
DIAG(err_typecheck_subscript_not_object, ERROR,
|
||||
"illegal subscript of non-object type '%0'")
|
||||
DIAG(err_typecheck_member_reference_structUnion, ERROR,
|
||||
"member reference is not to a structure or union")
|
||||
DIAG(err_typecheck_member_reference_arrow, ERROR,
|
||||
"member reference is not a pointer")
|
||||
DIAG(err_typecheck_incomplete_tag, ERROR,
|
||||
"incomplete definition of type '%0'")
|
||||
DIAG(err_typecheck_no_member, ERROR,
|
||||
"no member named '%0'")
|
||||
DIAG(err_typecheck_illegal_increment_decrement, ERROR,
|
||||
"cannot modify value of type '%0'")
|
||||
DIAG(err_typecheck_invalid_lvalue_incr_decr, ERROR,
|
||||
"invalid lvalue in increment/decrement expression")
|
||||
DIAG(err_typecheck_arithmetic_incomplete_type, ERROR,
|
||||
"arithmetic on pointer to incomplete type '%0'")
|
||||
DIAG(err_typecheck_decl_incomplete_type, ERROR,
|
||||
"variable has incomplete type '%0'")
|
||||
DIAG(err_typecheck_sclass_fscope, ERROR,
|
||||
"illegal storage class on file-scoped variable")
|
||||
DIAG(err_typecheck_sclass_func, ERROR,
|
||||
"illegal storage class on function")
|
||||
DIAG(err_typecheck_address_of_register, ERROR,
|
||||
"address of register variable requested")
|
||||
DIAG(err_typecheck_invalid_lvalue_addrof, ERROR,
|
||||
"invalid lvalue in address expression")
|
||||
DIAG(err_typecheck_unary_expr, ERROR,
|
||||
"invalid argument type to unary expression '%0'")
|
||||
DIAG(err_typecheck_indirection_requires_pointer, ERROR,
|
||||
"indirection requires pointer operand ('%0' invalid)")
|
||||
DIAG(err_typecheck_deref_incomplete_type, ERROR,
|
||||
"dereferencing pointer to incomplete type '%0'")
|
||||
DIAG(ext_typecheck_deref_ptr_to_void, EXTENSION,
|
||||
"dereferencing '%0' pointer")
|
||||
DIAG(err_typecheck_invalid_operands, ERROR,
|
||||
"invalid operands to binary expression ('%0' and '%1')")
|
||||
DIAG(ext_typecheck_comparison_of_pointer_integer, EXTENSION,
|
||||
"comparison between pointer and integer")
|
||||
DIAG(err_typecheck_assign_const, ERROR,
|
||||
"read-only variable is not assignable")
|
||||
DIAG(err_typecheck_assign_incompatible, ERROR,
|
||||
"incompatible types assigning '%1' to '%0'")
|
||||
DIAG(ext_typecheck_assign_pointer_int, EXTENSION,
|
||||
"incompatible types assigning '%1' to '%0'")
|
||||
DIAG(ext_typecheck_assign_incompatible_pointer, EXTENSION,
|
||||
"incompatible pointer types assigning '%1' to '%0'")
|
||||
DIAG(ext_typecheck_assign_discards_qualifiers, EXTENSION,
|
||||
"assigning '%1' to '%0' discards qualifiers")
|
||||
DIAG(err_typecheck_array_not_modifiable_lvalue, ERROR,
|
||||
"array type '%0' is not assignable")
|
||||
DIAG(err_typecheck_non_object_not_modifiable_lvalue, ERROR,
|
||||
"non-object type '%0' is not assignable")
|
||||
DIAG(err_typecheck_expression_not_modifiable_lvalue, ERROR,
|
||||
"expression is not assignable")
|
||||
DIAG(err_typecheck_incomplete_type_not_modifiable_lvalue, ERROR,
|
||||
"incomplete type '%0' is not assignable")
|
||||
DIAG(err_typecheck_call_not_function, ERROR,
|
||||
"called object is not a function or function pointer")
|
||||
DIAG(err_typecheck_call_too_few_args, ERROR,
|
||||
"too few arguments to function")
|
||||
DIAG(err_typecheck_call_too_many_args, ERROR,
|
||||
"too many arguments to function")
|
||||
DIAG(err_typecheck_passing_incompatible, ERROR,
|
||||
"incompatible types passing '%0' to function expecting '%1'")
|
||||
DIAG(ext_typecheck_passing_incompatible_pointer, EXTENSION,
|
||||
"incompatible pointer types passing '%0' to function expecting '%1'")
|
||||
DIAG(ext_typecheck_passing_pointer_int, EXTENSION,
|
||||
"incompatible types passing '%1' to function expecting '%0'")
|
||||
DIAG(ext_typecheck_passing_discards_qualifiers, EXTENSION,
|
||||
"passing '%0' to '%1' discards qualifiers")
|
||||
DIAG(err_typecheck_cond_expect_scalar, ERROR,
|
||||
"used type '%0' where arithmetic or pointer type is required")
|
||||
DIAG(err_typecheck_cond_incompatible_operands, ERROR,
|
||||
"incompatible operand types ('%0' and '%1')")
|
||||
DIAG(ext_typecheck_cond_incompatible_pointers, EXTENSION,
|
||||
"pointer type mismatch ('%0' and '%1')")
|
||||
|
||||
DIAG(warn_unused_expr, WARNING,
|
||||
"expression result unused")
|
||||
|
||||
// Statements.
|
||||
DIAG(err_continue_not_in_loop, ERROR,
|
||||
"'continue' statement not in loop statement")
|
||||
DIAG(err_break_not_in_loop_or_switch, ERROR,
|
||||
"'break' statement not in loop or switch statement")
|
||||
DIAG(err_typecheck_return_incompatible, ERROR,
|
||||
"incompatible type returning '%1', expected '%0'")
|
||||
DIAG(ext_typecheck_return_pointer_int, EXTENSION,
|
||||
"incompatible type returning '%1', expected '%0'")
|
||||
DIAG(ext_typecheck_return_incompatible_pointer, EXTENSION,
|
||||
"incompatible pointer type returning '%1', expected '%0'")
|
||||
DIAG(ext_typecheck_return_discards_qualifiers, EXTENSION,
|
||||
"returning '%1' from function expecting '%0' discards qualifiers")
|
||||
DIAG(err_typecheck_statement_requires_scalar, ERROR,
|
||||
"statement requires expression of scalar type ('%0' invalid)")
|
||||
|
||||
DIAG(warn_return_missing_expr, WARNING,
|
||||
"non-void function '%0' should return a value")
|
||||
DIAG(ext_return_missing_expr, EXTENSION,
|
||||
"non-void function '%0' should return a value")
|
||||
DIAG(ext_return_has_expr, EXTENSION,
|
||||
"void function '%0' should not return a value")
|
||||
|
||||
#undef DIAG
|
|
@ -0,0 +1,111 @@
|
|||
//===--- FileManager.h - File System Probing and Caching --------*- 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 FileManager interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_FILEMANAGER_H
|
||||
#define LLVM_CLANG_FILEMANAGER_H
|
||||
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
// FIXME: Enhance libsystem to support inode and other fields in stat.
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace clang {
|
||||
class FileManager;
|
||||
|
||||
/// DirectoryEntry - Cached information about one directory on the disk.
|
||||
///
|
||||
class DirectoryEntry {
|
||||
const char *Name; // Name of the directory.
|
||||
friend class FileManager;
|
||||
public:
|
||||
DirectoryEntry() : Name(0) {}
|
||||
const char *getName() const { return Name; }
|
||||
};
|
||||
|
||||
/// FileEntry - Cached information about one file on the disk.
|
||||
///
|
||||
class FileEntry {
|
||||
const char *Name; // Name of the directory.
|
||||
off_t Size; // File size in bytes.
|
||||
time_t ModTime; // Modification time of file.
|
||||
const DirectoryEntry *Dir; // Directory file lives in.
|
||||
unsigned UID; // A unique (small) ID for the file.
|
||||
friend class FileManager;
|
||||
public:
|
||||
FileEntry() : Name(0) {}
|
||||
|
||||
const char *getName() const { return Name; }
|
||||
off_t getSize() const { return Size; }
|
||||
unsigned getUID() const { return UID; }
|
||||
time_t getModificationTime() const { return ModTime; }
|
||||
|
||||
/// getDir - Return the directory the file lives in.
|
||||
///
|
||||
const DirectoryEntry *getDir() const { return Dir; }
|
||||
};
|
||||
|
||||
|
||||
/// FileManager - Implements support for file system lookup, file system
|
||||
/// caching, and directory search management. This also handles more advanced
|
||||
/// properties, such as uniquing files based on "inode", so that a file with two
|
||||
/// names (e.g. symlinked) will be treated as a single file.
|
||||
///
|
||||
class FileManager {
|
||||
/// UniqueDirs/UniqueFiles - Cache from ID's to existing directories/files.
|
||||
///
|
||||
std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs;
|
||||
std::map<std::pair<dev_t, ino_t>, FileEntry> UniqueFiles;
|
||||
|
||||
/// DirEntries/FileEntries - This is a cache of directory/file entries we have
|
||||
/// looked up. The actual Entry is owned by UniqueFiles/UniqueDirs above.
|
||||
///
|
||||
llvm::StringMap<DirectoryEntry*> DirEntries;
|
||||
llvm::StringMap<FileEntry*> FileEntries;
|
||||
|
||||
/// NextFileUID - Each FileEntry we create is assigned a unique ID #.
|
||||
///
|
||||
unsigned NextFileUID;
|
||||
|
||||
// Statistics.
|
||||
unsigned NumDirLookups, NumFileLookups;
|
||||
unsigned NumDirCacheMisses, NumFileCacheMisses;
|
||||
public:
|
||||
FileManager() : DirEntries(64), FileEntries(64), NextFileUID(0) {
|
||||
NumDirLookups = NumFileLookups = 0;
|
||||
NumDirCacheMisses = NumFileCacheMisses = 0;
|
||||
}
|
||||
|
||||
/// getDirectory - Lookup, cache, and verify the specified directory. This
|
||||
/// returns null if the directory doesn't exist.
|
||||
///
|
||||
const DirectoryEntry *getDirectory(const std::string &Filename) {
|
||||
return getDirectory(&Filename[0], &Filename[0] + Filename.size());
|
||||
}
|
||||
const DirectoryEntry *getDirectory(const char *FileStart,const char *FileEnd);
|
||||
|
||||
/// getFile - Lookup, cache, and verify the specified file. This returns null
|
||||
/// if the file doesn't exist.
|
||||
///
|
||||
const FileEntry *getFile(const std::string &Filename) {
|
||||
return getFile(&Filename[0], &Filename[0] + Filename.size());
|
||||
}
|
||||
const FileEntry *getFile(const char *FilenameStart,
|
||||
const char *FilenameEnd);
|
||||
|
||||
void PrintStats() const;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue