Compare commits
17 Commits
llvmorg-6.
...
llvmorg-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef55b5d87a | ||
|
|
1c4be00c9e | ||
|
|
06834b2734 | ||
|
|
3e45ec8ee2 | ||
|
|
4149ab2eb3 | ||
|
|
23177b1ff0 | ||
|
|
7ae6b34d1d | ||
|
|
d18515a257 | ||
|
|
99d99dcaa2 | ||
|
|
e41e59505e | ||
|
|
c1dde534b1 | ||
|
|
a489619ead | ||
|
|
2e1232ef6f | ||
|
|
f2190a5c18 | ||
|
|
93f7a28af9 | ||
|
|
e1a9bf1233 | ||
|
|
cf9988be1f |
@@ -1,27 +0,0 @@
|
||||
//===--- ASTConsumer.cpp - Abstract interface for reading ASTs --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the ASTConsumer class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
void ASTConsumer::HandleTopLevelDeclaration(Decl* d) {
|
||||
if (ScopedDecl* sd = dyn_cast<ScopedDecl>(d))
|
||||
while (sd) {
|
||||
HandleTopLevelDecl(sd);
|
||||
sd = sd->getNextDeclarator();
|
||||
}
|
||||
else
|
||||
HandleTopLevelDecl(d);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,200 +0,0 @@
|
||||
//===--- Builtins.cpp - Builtin function implementation -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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/Basic/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,
|
||||
bool AllowTypeModifiers = true) {
|
||||
// Modifiers.
|
||||
bool Long = false, LongLong = false, Signed = false, Unsigned = false;
|
||||
|
||||
// Read the modifiers first.
|
||||
bool Done = false;
|
||||
while (!Done) {
|
||||
switch (*Str++) {
|
||||
default: Done = true; --Str; break;
|
||||
case 'S':
|
||||
assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!");
|
||||
assert(!Signed && "Can't use 'S' modifier multiple times!");
|
||||
Signed = true;
|
||||
break;
|
||||
case 'U':
|
||||
assert(!Signed && "Can't use both 'S' and 'U' modifiers!");
|
||||
assert(!Unsigned && "Can't use 'S' modifier multiple times!");
|
||||
Unsigned = true;
|
||||
break;
|
||||
case 'L':
|
||||
assert(!LongLong && "Can't have LLL modifier");
|
||||
if (Long)
|
||||
LongLong = true;
|
||||
else
|
||||
Long = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QualType Type;
|
||||
|
||||
// Read the base type.
|
||||
switch (*Str++) {
|
||||
default: assert(0 && "Unknown builtin type letter!");
|
||||
case 'v':
|
||||
assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'v'!");
|
||||
Type = Context.VoidTy;
|
||||
break;
|
||||
case 'f':
|
||||
assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'f'!");
|
||||
Type = Context.FloatTy;
|
||||
break;
|
||||
case 'd':
|
||||
assert(!LongLong && !Signed && !Unsigned && "Bad modifiers used with 'd'!");
|
||||
if (Long)
|
||||
Type = Context.LongDoubleTy;
|
||||
else
|
||||
Type = Context.DoubleTy;
|
||||
break;
|
||||
case 's':
|
||||
assert(!LongLong && "Bad modifiers used with 's'!");
|
||||
if (Unsigned)
|
||||
Type = Context.UnsignedShortTy;
|
||||
else
|
||||
Type = Context.ShortTy;
|
||||
break;
|
||||
case 'i':
|
||||
if (LongLong)
|
||||
Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy;
|
||||
else if (Long)
|
||||
Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy;
|
||||
else if (Unsigned)
|
||||
Type = Context.UnsignedIntTy;
|
||||
else
|
||||
Type = Context.IntTy; // default is signed.
|
||||
break;
|
||||
case 'c':
|
||||
assert(!Long && !LongLong && "Bad modifiers used with 'c'!");
|
||||
if (Signed)
|
||||
Type = Context.SignedCharTy;
|
||||
else if (Unsigned)
|
||||
Type = Context.UnsignedCharTy;
|
||||
else
|
||||
Type = Context.CharTy;
|
||||
break;
|
||||
case 'z': // size_t.
|
||||
assert(!Long && !Signed && !Unsigned && "Bad modifiers for 'z'!");
|
||||
Type = Context.getSizeType();
|
||||
break;
|
||||
case 'F':
|
||||
Type = Context.getCFConstantStringType();
|
||||
break;
|
||||
case 'a':
|
||||
Type = Context.getBuiltinVaListType();
|
||||
assert(!Type.isNull() && "builtin va list type not initialized!");
|
||||
break;
|
||||
case 'V': {
|
||||
char *End;
|
||||
|
||||
unsigned NumElements = strtoul(Str, &End, 10);
|
||||
assert(End != Str && "Missing vector size");
|
||||
|
||||
Str = End;
|
||||
|
||||
QualType ElementType = DecodeTypeFromStr(Str, Context, false);
|
||||
Type = Context.getVectorType(ElementType, NumElements);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AllowTypeModifiers)
|
||||
return Type;
|
||||
|
||||
Done = false;
|
||||
while (!Done) {
|
||||
switch (*Str++) {
|
||||
default: Done = true; --Str; break;
|
||||
case '*':
|
||||
Type = Context.getPointerType(Type);
|
||||
break;
|
||||
case '&':
|
||||
Type = Context.getReferenceType(Type);
|
||||
break;
|
||||
case 'C':
|
||||
Type = Type.getQualifiedType(QualType::Const);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Type;
|
||||
}
|
||||
|
||||
/// GetBuiltinType - Return the type for the specified builtin.
|
||||
QualType Builtin::Context::GetBuiltinType(unsigned id,
|
||||
ASTContext &Context) const {
|
||||
const char *TypeStr = GetRecord(id).Type;
|
||||
|
||||
llvm::SmallVector<QualType, 8> ArgTypes;
|
||||
|
||||
QualType ResType = DecodeTypeFromStr(TypeStr, Context);
|
||||
while (TypeStr[0] && TypeStr[0] != '.')
|
||||
ArgTypes.push_back(DecodeTypeFromStr(TypeStr, Context));
|
||||
|
||||
assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
|
||||
"'.' should only occur at end of builtin type list!");
|
||||
|
||||
// handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);".
|
||||
if (ArgTypes.size() == 0 && TypeStr[0] == '.')
|
||||
return Context.getFunctionTypeNoProto(ResType);
|
||||
return Context.getFunctionType(ResType, &ArgTypes[0], ArgTypes.size(),
|
||||
TypeStr[0] == '.');
|
||||
}
|
||||
1405
clang/AST/CFG.cpp
1405
clang/AST/CFG.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,574 +0,0 @@
|
||||
//===--- Decl.cpp - Declaration AST Node Implementation -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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/AST/DeclObjC.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
using namespace clang;
|
||||
|
||||
// temporary statistics gathering
|
||||
static unsigned nFuncs = 0;
|
||||
static unsigned nBlockVars = 0;
|
||||
static unsigned nFileVars = 0;
|
||||
static unsigned nParmVars = 0;
|
||||
static unsigned nSUC = 0;
|
||||
static unsigned nEnumConst = 0;
|
||||
static unsigned nEnumDecls = 0;
|
||||
static unsigned nTypedef = 0;
|
||||
static unsigned nFieldDecls = 0;
|
||||
static unsigned nInterfaceDecls = 0;
|
||||
static unsigned nClassDecls = 0;
|
||||
static unsigned nMethodDecls = 0;
|
||||
static unsigned nProtocolDecls = 0;
|
||||
static unsigned nForwardProtocolDecls = 0;
|
||||
static unsigned nCategoryDecls = 0;
|
||||
static unsigned nIvarDecls = 0;
|
||||
static unsigned nObjCImplementationDecls = 0;
|
||||
static unsigned nObjCCategoryImpl = 0;
|
||||
static unsigned nObjCCompatibleAlias = 0;
|
||||
static unsigned nObjCPropertyDecl = 0;
|
||||
static unsigned nLinkageSpecDecl = 0;
|
||||
|
||||
static bool StatSwitch = false;
|
||||
|
||||
const char *Decl::getDeclKindName() const {
|
||||
switch (DeclKind) {
|
||||
default: assert(0 && "Unknown decl kind!");
|
||||
case Typedef:
|
||||
return "Typedef";
|
||||
case Function:
|
||||
return "Function";
|
||||
case BlockVar:
|
||||
return "BlockVar";
|
||||
case FileVar:
|
||||
return "FileVar";
|
||||
case ParmVar:
|
||||
return "ParmVar";
|
||||
case EnumConstant:
|
||||
return "EnumConstant";
|
||||
case ObjCInterface:
|
||||
return "ObjCInterface";
|
||||
case ObjCClass:
|
||||
return "ObjCClass";
|
||||
case ObjCMethod:
|
||||
return "ObjCMethod";
|
||||
case ObjCProtocol:
|
||||
return "ObjCProtocol";
|
||||
case ObjCForwardProtocol:
|
||||
return "ObjCForwardProtocol";
|
||||
case Struct:
|
||||
return "Struct";
|
||||
case Union:
|
||||
return "Union";
|
||||
case Class:
|
||||
return "Class";
|
||||
case Enum:
|
||||
return "Enum";
|
||||
}
|
||||
}
|
||||
|
||||
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+nInterfaceDecls+nClassDecls+
|
||||
nMethodDecls+nProtocolDecls+nCategoryDecls+nIvarDecls));
|
||||
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)));
|
||||
// Objective-C decls...
|
||||
fprintf(stderr, " %d interface decls, %d each (%d bytes)\n",
|
||||
nInterfaceDecls, (int)sizeof(ObjCInterfaceDecl),
|
||||
int(nInterfaceDecls*sizeof(ObjCInterfaceDecl)));
|
||||
fprintf(stderr, " %d instance variable decls, %d each (%d bytes)\n",
|
||||
nIvarDecls, (int)sizeof(ObjCIvarDecl),
|
||||
int(nIvarDecls*sizeof(ObjCIvarDecl)));
|
||||
fprintf(stderr, " %d class decls, %d each (%d bytes)\n",
|
||||
nClassDecls, (int)sizeof(ObjCClassDecl),
|
||||
int(nClassDecls*sizeof(ObjCClassDecl)));
|
||||
fprintf(stderr, " %d method decls, %d each (%d bytes)\n",
|
||||
nMethodDecls, (int)sizeof(ObjCMethodDecl),
|
||||
int(nMethodDecls*sizeof(ObjCMethodDecl)));
|
||||
fprintf(stderr, " %d protocol decls, %d each (%d bytes)\n",
|
||||
nProtocolDecls, (int)sizeof(ObjCProtocolDecl),
|
||||
int(nProtocolDecls*sizeof(ObjCProtocolDecl)));
|
||||
fprintf(stderr, " %d forward protocol decls, %d each (%d bytes)\n",
|
||||
nForwardProtocolDecls, (int)sizeof(ObjCForwardProtocolDecl),
|
||||
int(nForwardProtocolDecls*sizeof(ObjCForwardProtocolDecl)));
|
||||
fprintf(stderr, " %d category decls, %d each (%d bytes)\n",
|
||||
nCategoryDecls, (int)sizeof(ObjCCategoryDecl),
|
||||
int(nCategoryDecls*sizeof(ObjCCategoryDecl)));
|
||||
|
||||
fprintf(stderr, " %d class implementation decls, %d each (%d bytes)\n",
|
||||
nObjCImplementationDecls, (int)sizeof(ObjCImplementationDecl),
|
||||
int(nObjCImplementationDecls*sizeof(ObjCImplementationDecl)));
|
||||
|
||||
fprintf(stderr, " %d class implementation decls, %d each (%d bytes)\n",
|
||||
nObjCCategoryImpl, (int)sizeof(ObjCCategoryImplDecl),
|
||||
int(nObjCCategoryImpl*sizeof(ObjCCategoryImplDecl)));
|
||||
|
||||
fprintf(stderr, " %d compatibility alias decls, %d each (%d bytes)\n",
|
||||
nObjCCompatibleAlias, (int)sizeof(ObjCCompatibleAliasDecl),
|
||||
int(nObjCCompatibleAlias*sizeof(ObjCCompatibleAliasDecl)));
|
||||
|
||||
fprintf(stderr, " %d property decls, %d each (%d bytes)\n",
|
||||
nObjCPropertyDecl, (int)sizeof(ObjCPropertyDecl),
|
||||
int(nObjCPropertyDecl*sizeof(ObjCPropertyDecl)));
|
||||
|
||||
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)+
|
||||
nLinkageSpecDecl*sizeof(LinkageSpecDecl))
|
||||
/* FIXME: add ObjC decls */);
|
||||
}
|
||||
|
||||
void Decl::addDeclKind(const Kind k) {
|
||||
switch (k) {
|
||||
case Typedef:
|
||||
nTypedef++;
|
||||
break;
|
||||
case Function:
|
||||
nFuncs++;
|
||||
break;
|
||||
case BlockVar:
|
||||
nBlockVars++;
|
||||
break;
|
||||
case FileVar:
|
||||
nFileVars++;
|
||||
break;
|
||||
case ParmVar:
|
||||
nParmVars++;
|
||||
break;
|
||||
case EnumConstant:
|
||||
nEnumConst++;
|
||||
break;
|
||||
case Field:
|
||||
nFieldDecls++;
|
||||
break;
|
||||
case Struct:
|
||||
case Union:
|
||||
case Class:
|
||||
nSUC++;
|
||||
break;
|
||||
case Enum:
|
||||
nEnumDecls++;
|
||||
break;
|
||||
case ObjCInterface:
|
||||
nInterfaceDecls++;
|
||||
break;
|
||||
case ObjCClass:
|
||||
nClassDecls++;
|
||||
break;
|
||||
case ObjCMethod:
|
||||
nMethodDecls++;
|
||||
break;
|
||||
case ObjCProtocol:
|
||||
nProtocolDecls++;
|
||||
break;
|
||||
case ObjCForwardProtocol:
|
||||
nForwardProtocolDecls++;
|
||||
break;
|
||||
case ObjCCategory:
|
||||
nCategoryDecls++;
|
||||
break;
|
||||
case ObjCIvar:
|
||||
nIvarDecls++;
|
||||
break;
|
||||
case ObjCImplementation:
|
||||
nObjCImplementationDecls++;
|
||||
break;
|
||||
case ObjCCategoryImpl:
|
||||
nObjCCategoryImpl++;
|
||||
break;
|
||||
case CompatibleAlias:
|
||||
nObjCCompatibleAlias++;
|
||||
break;
|
||||
case PropertyDecl:
|
||||
nObjCPropertyDecl++;
|
||||
break;
|
||||
case LinkageSpec:
|
||||
nLinkageSpecDecl++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Out-of-line virtual method providing a home for Decl.
|
||||
Decl::~Decl() {
|
||||
}
|
||||
|
||||
const char *NamedDecl::getName() const {
|
||||
if (const IdentifierInfo *II = getIdentifier())
|
||||
return II->getName();
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
FunctionDecl::~FunctionDecl() {
|
||||
delete[] ParamInfo;
|
||||
}
|
||||
|
||||
unsigned FunctionDecl::getNumParams() const {
|
||||
if (isa<FunctionTypeNoProto>(getCanonicalType())) return 0;
|
||||
return cast<FunctionTypeProto>(getCanonicalType())->getNumArgs();
|
||||
}
|
||||
|
||||
void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) {
|
||||
assert(ParamInfo == 0 && "Already has param info!");
|
||||
assert(NumParams == getNumParams() && "Parameter count mismatch!");
|
||||
|
||||
// Zero params -> null pointer.
|
||||
if (NumParams) {
|
||||
ParamInfo = new ParmVarDecl*[NumParams];
|
||||
memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// defineBody - When created, RecordDecl's correspond to a forward declared
|
||||
/// record. This method is used to mark the decl as being defined, with the
|
||||
/// specified contents.
|
||||
void RecordDecl::defineBody(FieldDecl **members, unsigned numMembers) {
|
||||
assert(!isDefinition() && "Cannot redefine record!");
|
||||
setDefinition(true);
|
||||
NumMembers = numMembers;
|
||||
if (numMembers) {
|
||||
Members = new FieldDecl*[numMembers];
|
||||
memcpy(Members, members, numMembers*sizeof(Decl*));
|
||||
}
|
||||
}
|
||||
|
||||
FieldDecl* RecordDecl::getMember(IdentifierInfo *name) {
|
||||
if (Members == 0 || NumMembers < 0)
|
||||
return 0;
|
||||
|
||||
// linear search. When C++ classes come along, will likely need to revisit.
|
||||
for (int i = 0; i < NumMembers; ++i) {
|
||||
if (Members[i]->getIdentifier() == name)
|
||||
return Members[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ObjCMethodDecl::setMethodParams(ParmVarDecl **NewParamInfo,
|
||||
unsigned NumParams) {
|
||||
assert(ParamInfo == 0 && "Already has param info!");
|
||||
|
||||
// Zero params -> null pointer.
|
||||
if (NumParams) {
|
||||
ParamInfo = new ParmVarDecl*[NumParams];
|
||||
memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
|
||||
NumMethodParams = NumParams;
|
||||
}
|
||||
}
|
||||
|
||||
ObjCMethodDecl::~ObjCMethodDecl() {
|
||||
delete[] ParamInfo;
|
||||
}
|
||||
|
||||
/// ObjCAddInstanceVariablesToClass - Inserts instance variables
|
||||
/// into ObjCInterfaceDecl's fields.
|
||||
///
|
||||
void ObjCInterfaceDecl::addInstanceVariablesToClass(ObjCIvarDecl **ivars,
|
||||
unsigned numIvars,
|
||||
SourceLocation RBrac) {
|
||||
NumIvars = numIvars;
|
||||
if (numIvars) {
|
||||
Ivars = new ObjCIvarDecl*[numIvars];
|
||||
memcpy(Ivars, ivars, numIvars*sizeof(ObjCIvarDecl*));
|
||||
}
|
||||
setLocEnd(RBrac);
|
||||
}
|
||||
|
||||
/// ObjCAddInstanceVariablesToClassImpl - Checks for correctness of Instance
|
||||
/// Variables (Ivars) relative to what declared in @implementation;s class.
|
||||
/// Ivars into ObjCImplementationDecl's fields.
|
||||
///
|
||||
void ObjCImplementationDecl::ObjCAddInstanceVariablesToClassImpl(
|
||||
ObjCIvarDecl **ivars, unsigned numIvars) {
|
||||
NumIvars = numIvars;
|
||||
if (numIvars) {
|
||||
Ivars = new ObjCIvarDecl*[numIvars];
|
||||
memcpy(Ivars, ivars, numIvars*sizeof(ObjCIvarDecl*));
|
||||
}
|
||||
}
|
||||
|
||||
/// addMethods - Insert instance and methods declarations into
|
||||
/// ObjCInterfaceDecl's InsMethods and ClsMethods fields.
|
||||
///
|
||||
void ObjCInterfaceDecl::addMethods(ObjCMethodDecl **insMethods,
|
||||
unsigned numInsMembers,
|
||||
ObjCMethodDecl **clsMethods,
|
||||
unsigned numClsMembers,
|
||||
SourceLocation endLoc) {
|
||||
NumInstanceMethods = numInsMembers;
|
||||
if (numInsMembers) {
|
||||
InstanceMethods = new ObjCMethodDecl*[numInsMembers];
|
||||
memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjCMethodDecl*));
|
||||
}
|
||||
NumClassMethods = numClsMembers;
|
||||
if (numClsMembers) {
|
||||
ClassMethods = new ObjCMethodDecl*[numClsMembers];
|
||||
memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjCMethodDecl*));
|
||||
}
|
||||
AtEndLoc = endLoc;
|
||||
}
|
||||
|
||||
/// addMethods - Insert instance and methods declarations into
|
||||
/// ObjCProtocolDecl's ProtoInsMethods and ProtoClsMethods fields.
|
||||
///
|
||||
void ObjCProtocolDecl::addMethods(ObjCMethodDecl **insMethods,
|
||||
unsigned numInsMembers,
|
||||
ObjCMethodDecl **clsMethods,
|
||||
unsigned numClsMembers,
|
||||
SourceLocation endLoc) {
|
||||
NumInstanceMethods = numInsMembers;
|
||||
if (numInsMembers) {
|
||||
InstanceMethods = new ObjCMethodDecl*[numInsMembers];
|
||||
memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjCMethodDecl*));
|
||||
}
|
||||
NumClassMethods = numClsMembers;
|
||||
if (numClsMembers) {
|
||||
ClassMethods = new ObjCMethodDecl*[numClsMembers];
|
||||
memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjCMethodDecl*));
|
||||
}
|
||||
AtEndLoc = endLoc;
|
||||
}
|
||||
|
||||
/// addMethods - Insert instance and methods declarations into
|
||||
/// ObjCCategoryDecl's CatInsMethods and CatClsMethods fields.
|
||||
///
|
||||
void ObjCCategoryDecl::addMethods(ObjCMethodDecl **insMethods,
|
||||
unsigned numInsMembers,
|
||||
ObjCMethodDecl **clsMethods,
|
||||
unsigned numClsMembers,
|
||||
SourceLocation endLoc) {
|
||||
NumInstanceMethods = numInsMembers;
|
||||
if (numInsMembers) {
|
||||
InstanceMethods = new ObjCMethodDecl*[numInsMembers];
|
||||
memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjCMethodDecl*));
|
||||
}
|
||||
NumClassMethods = numClsMembers;
|
||||
if (numClsMembers) {
|
||||
ClassMethods = new ObjCMethodDecl*[numClsMembers];
|
||||
memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjCMethodDecl*));
|
||||
}
|
||||
AtEndLoc = endLoc;
|
||||
}
|
||||
|
||||
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(
|
||||
IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) {
|
||||
ObjCInterfaceDecl* ClassDecl = this;
|
||||
while (ClassDecl != NULL) {
|
||||
for (ivar_iterator I = ClassDecl->ivar_begin(), E = ClassDecl->ivar_end();
|
||||
I != E; ++I) {
|
||||
if ((*I)->getIdentifier() == ID) {
|
||||
clsDeclared = ClassDecl;
|
||||
return *I;
|
||||
}
|
||||
}
|
||||
ClassDecl = ClassDecl->getSuperClass();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// lookupInstanceMethod - This method returns an instance method by looking in
|
||||
/// the class, its categories, and its super classes (using a linear search).
|
||||
ObjCMethodDecl *ObjCInterfaceDecl::lookupInstanceMethod(Selector Sel) {
|
||||
ObjCInterfaceDecl* ClassDecl = this;
|
||||
ObjCMethodDecl *MethodDecl = 0;
|
||||
|
||||
while (ClassDecl != NULL) {
|
||||
if ((MethodDecl = ClassDecl->getInstanceMethod(Sel)))
|
||||
return MethodDecl;
|
||||
|
||||
// Didn't find one yet - look through protocols.
|
||||
ObjCProtocolDecl **protocols = ClassDecl->getReferencedProtocols();
|
||||
int numProtocols = ClassDecl->getNumIntfRefProtocols();
|
||||
for (int pIdx = 0; pIdx < numProtocols; pIdx++) {
|
||||
if ((MethodDecl = protocols[pIdx]->getInstanceMethod(Sel)))
|
||||
return MethodDecl;
|
||||
}
|
||||
// Didn't find one yet - now look through categories.
|
||||
ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList();
|
||||
while (CatDecl) {
|
||||
if ((MethodDecl = CatDecl->getInstanceMethod(Sel)))
|
||||
return MethodDecl;
|
||||
CatDecl = CatDecl->getNextClassCategory();
|
||||
}
|
||||
ClassDecl = ClassDecl->getSuperClass();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// lookupClassMethod - This method returns a class method by looking in the
|
||||
// class, its categories, and its super classes (using a linear search).
|
||||
ObjCMethodDecl *ObjCInterfaceDecl::lookupClassMethod(Selector Sel) {
|
||||
ObjCInterfaceDecl* ClassDecl = this;
|
||||
ObjCMethodDecl *MethodDecl = 0;
|
||||
|
||||
while (ClassDecl != NULL) {
|
||||
if ((MethodDecl = ClassDecl->getClassMethod(Sel)))
|
||||
return MethodDecl;
|
||||
|
||||
// Didn't find one yet - look through protocols.
|
||||
ObjCProtocolDecl **protocols = ClassDecl->getReferencedProtocols();
|
||||
int numProtocols = ClassDecl->getNumIntfRefProtocols();
|
||||
for (int pIdx = 0; pIdx < numProtocols; pIdx++) {
|
||||
if ((MethodDecl = protocols[pIdx]->getClassMethod(Sel)))
|
||||
return MethodDecl;
|
||||
}
|
||||
// Didn't find one yet - now look through categories.
|
||||
ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList();
|
||||
while (CatDecl) {
|
||||
if ((MethodDecl = CatDecl->getClassMethod(Sel)))
|
||||
return MethodDecl;
|
||||
CatDecl = CatDecl->getNextClassCategory();
|
||||
}
|
||||
ClassDecl = ClassDecl->getSuperClass();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// lookupInstanceMethod - This method returns an instance method by looking in
|
||||
/// the class implementation. Unlike interfaces, we don't look outside the
|
||||
/// implementation.
|
||||
ObjCMethodDecl *ObjCImplementationDecl::getInstanceMethod(Selector Sel) {
|
||||
for (instmeth_iterator I = instmeth_begin(), E = instmeth_end(); I != E; ++I)
|
||||
if ((*I)->getSelector() == Sel)
|
||||
return *I;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// lookupClassMethod - This method returns a class method by looking in
|
||||
/// the class implementation. Unlike interfaces, we don't look outside the
|
||||
/// implementation.
|
||||
ObjCMethodDecl *ObjCImplementationDecl::getClassMethod(Selector Sel) {
|
||||
for (classmeth_iterator I = classmeth_begin(), E = classmeth_end();
|
||||
I != E; ++I)
|
||||
if ((*I)->getSelector() == Sel)
|
||||
return *I;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// lookupInstanceMethod - This method returns an instance method by looking in
|
||||
// the class implementation. Unlike interfaces, we don't look outside the
|
||||
// implementation.
|
||||
ObjCMethodDecl *ObjCCategoryImplDecl::getInstanceMethod(Selector Sel) {
|
||||
for (instmeth_iterator I = instmeth_begin(), E = instmeth_end(); I != E; ++I)
|
||||
if ((*I)->getSelector() == Sel)
|
||||
return *I;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// lookupClassMethod - This method returns an instance method by looking in
|
||||
// the class implementation. Unlike interfaces, we don't look outside the
|
||||
// implementation.
|
||||
ObjCMethodDecl *ObjCCategoryImplDecl::getClassMethod(Selector Sel) {
|
||||
for (classmeth_iterator I = classmeth_begin(), E = classmeth_end();
|
||||
I != E; ++I)
|
||||
if ((*I)->getSelector() == Sel)
|
||||
return *I;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// lookupInstanceMethod - Lookup a instance method in the protocol and protocols
|
||||
// it inherited.
|
||||
ObjCMethodDecl *ObjCProtocolDecl::lookupInstanceMethod(Selector Sel) {
|
||||
ObjCMethodDecl *MethodDecl = NULL;
|
||||
|
||||
if ((MethodDecl = getInstanceMethod(Sel)))
|
||||
return MethodDecl;
|
||||
|
||||
if (getNumReferencedProtocols() > 0) {
|
||||
ObjCProtocolDecl **RefPDecl = getReferencedProtocols();
|
||||
|
||||
for (unsigned i = 0; i < getNumReferencedProtocols(); i++) {
|
||||
if ((MethodDecl = RefPDecl[i]->getInstanceMethod(Sel)))
|
||||
return MethodDecl;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// lookupInstanceMethod - Lookup a class method in the protocol and protocols
|
||||
// it inherited.
|
||||
ObjCMethodDecl *ObjCProtocolDecl::lookupClassMethod(Selector Sel) {
|
||||
ObjCMethodDecl *MethodDecl = NULL;
|
||||
|
||||
if ((MethodDecl = getClassMethod(Sel)))
|
||||
return MethodDecl;
|
||||
|
||||
if (getNumReferencedProtocols() > 0) {
|
||||
ObjCProtocolDecl **RefPDecl = getReferencedProtocols();
|
||||
|
||||
for(unsigned i = 0; i < getNumReferencedProtocols(); i++) {
|
||||
if ((MethodDecl = RefPDecl[i]->getClassMethod(Sel)))
|
||||
return MethodDecl;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ObjCMethodDecl::getSynthesizedSelectorSize() const {
|
||||
// syntesized method name is a concatenation of -/+[class-name selector]
|
||||
// Get length of this name.
|
||||
int length = 4; // for '+' or '-', '[', space in between and ']'
|
||||
length += getSelector().getName().size(); // for selector name.
|
||||
length += strlen(getMethodContext()->getName()); // for its class name
|
||||
return length;
|
||||
}
|
||||
|
||||
ObjCInterfaceDecl *const ObjCMethodDecl::getClassInterface() const {
|
||||
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(MethodContext))
|
||||
return ID;
|
||||
if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(MethodContext))
|
||||
return CD->getClassInterface();
|
||||
if (ObjCImplementationDecl *IMD =
|
||||
dyn_cast<ObjCImplementationDecl>(MethodContext))
|
||||
return IMD->getClassInterface();
|
||||
if (ObjCCategoryImplDecl *CID =
|
||||
dyn_cast<ObjCCategoryImplDecl>(MethodContext))
|
||||
return CID->getClassInterface();
|
||||
assert(false && "unknown method context");
|
||||
return 0;
|
||||
}
|
||||
@@ -1,440 +0,0 @@
|
||||
//===--- DeclSerialization.cpp - Serialization of Decls ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This files defines methods that implement bitcode serialization for Decls.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "llvm/Bitcode/Serialize.h"
|
||||
#include "llvm/Bitcode/Deserialize.h"
|
||||
|
||||
using llvm::Serializer;
|
||||
using llvm::Deserializer;
|
||||
using llvm::SerializedPtrID;
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Decl Serialization: Dispatch code to handle specialized decl types.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void Decl::Emit(Serializer& S) const {
|
||||
S.EmitInt(getKind());
|
||||
EmitImpl(S);
|
||||
}
|
||||
|
||||
Decl* Decl::Create(Deserializer& D) {
|
||||
|
||||
Kind k = static_cast<Kind>(D.ReadInt());
|
||||
|
||||
switch (k) {
|
||||
default:
|
||||
assert (false && "Not implemented.");
|
||||
break;
|
||||
|
||||
case BlockVar:
|
||||
return BlockVarDecl::CreateImpl(D);
|
||||
|
||||
case Enum:
|
||||
return EnumDecl::CreateImpl(D);
|
||||
|
||||
case EnumConstant:
|
||||
return EnumConstantDecl::CreateImpl(D);
|
||||
|
||||
case Field:
|
||||
return FieldDecl::CreateImpl(D);
|
||||
|
||||
case FileVar:
|
||||
return FileVarDecl::CreateImpl(D);
|
||||
|
||||
case ParmVar:
|
||||
return ParmVarDecl::CreateImpl(D);
|
||||
|
||||
case Function:
|
||||
return FunctionDecl::CreateImpl(D);
|
||||
|
||||
case Union:
|
||||
case Struct:
|
||||
return RecordDecl::CreateImpl(k,D);
|
||||
|
||||
case Typedef:
|
||||
return TypedefDecl::CreateImpl(D);
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Common serialization logic for subclasses of Decl.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void Decl::EmitInRec(Serializer& S) const {
|
||||
S.Emit(getLocation()); // From Decl.
|
||||
}
|
||||
|
||||
void Decl::ReadInRec(Deserializer& D) {
|
||||
Loc = SourceLocation::ReadVal(D); // From Decl.
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Common serialization logic for subclasses of NamedDecl.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void NamedDecl::EmitInRec(Serializer& S) const {
|
||||
Decl::EmitInRec(S);
|
||||
S.EmitPtr(getIdentifier()); // From NamedDecl.
|
||||
}
|
||||
|
||||
void NamedDecl::ReadInRec(Deserializer& D) {
|
||||
Decl::ReadInRec(D);
|
||||
D.ReadPtr(Identifier); // From NamedDecl.
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Common serialization logic for subclasses of ScopedDecl.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void ScopedDecl::EmitInRec(Serializer& S) const {
|
||||
NamedDecl::EmitInRec(S);
|
||||
S.EmitPtr(getNext()); // From ScopedDecl.
|
||||
}
|
||||
|
||||
void ScopedDecl::ReadInRec(Deserializer& D) {
|
||||
NamedDecl::ReadInRec(D);
|
||||
D.ReadPtr(Next); // From ScopedDecl.
|
||||
}
|
||||
|
||||
//===------------------------------------------------------------===//
|
||||
// NOTE: Not all subclasses of ScopedDecl will use the "OutRec" //
|
||||
// methods. This is because owned pointers are usually "batched" //
|
||||
// together for efficiency. //
|
||||
//===------------------------------------------------------------===//
|
||||
|
||||
void ScopedDecl::EmitOutRec(Serializer& S) const {
|
||||
S.EmitOwnedPtr(getNextDeclarator()); // From ScopedDecl.
|
||||
}
|
||||
|
||||
void ScopedDecl::ReadOutRec(Deserializer& D) {
|
||||
NextDeclarator =
|
||||
cast_or_null<ScopedDecl>(D.ReadOwnedPtr<Decl>()); // From ScopedDecl.
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Common serialization logic for subclasses of ValueDecl.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void ValueDecl::EmitInRec(Serializer& S) const {
|
||||
ScopedDecl::EmitInRec(S);
|
||||
S.Emit(getType()); // From ValueDecl.
|
||||
}
|
||||
|
||||
void ValueDecl::ReadInRec(Deserializer& D) {
|
||||
ScopedDecl::ReadInRec(D);
|
||||
DeclType = QualType::ReadVal(D); // From ValueDecl.
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Common serialization logic for subclasses of VarDecl.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void VarDecl::EmitInRec(Serializer& S) const {
|
||||
ValueDecl::EmitInRec(S);
|
||||
S.EmitInt(getStorageClass()); // From VarDecl.
|
||||
}
|
||||
|
||||
void VarDecl::ReadInRec(Deserializer& D) {
|
||||
ValueDecl::ReadInRec(D);
|
||||
SClass = static_cast<StorageClass>(D.ReadInt()); // From VarDecl.
|
||||
}
|
||||
|
||||
//===------------------------------------------------------------===//
|
||||
// NOTE: VarDecl has its own "OutRec" methods that doesn't use //
|
||||
// the one define in ScopedDecl. This is to batch emit the //
|
||||
// owned pointers, which results in a smaller output.
|
||||
//===------------------------------------------------------------===//
|
||||
|
||||
void VarDecl::EmitOutRec(Serializer& S) const {
|
||||
// Emit these last because they will create records of their own.
|
||||
S.BatchEmitOwnedPtrs(getInit(), // From VarDecl.
|
||||
getNextDeclarator()); // From ScopedDecl.
|
||||
}
|
||||
|
||||
void VarDecl::ReadOutRec(Deserializer& D) {
|
||||
Decl* next_declarator;
|
||||
|
||||
D.BatchReadOwnedPtrs(Init, // From VarDecl.
|
||||
next_declarator); // From ScopedDecl.
|
||||
|
||||
setNextDeclarator(cast_or_null<ScopedDecl>(next_declarator));
|
||||
}
|
||||
|
||||
|
||||
void VarDecl::EmitImpl(Serializer& S) const {
|
||||
VarDecl::EmitInRec(S);
|
||||
VarDecl::EmitOutRec(S);
|
||||
}
|
||||
|
||||
void VarDecl::ReadImpl(Deserializer& D) {
|
||||
ReadInRec(D);
|
||||
ReadOutRec(D);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BlockVarDecl Serialization.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
BlockVarDecl* BlockVarDecl::CreateImpl(Deserializer& D) {
|
||||
BlockVarDecl* decl =
|
||||
new BlockVarDecl(SourceLocation(),NULL,QualType(),None,NULL);
|
||||
|
||||
decl->VarDecl::ReadImpl(D);
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FileVarDecl Serialization.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
FileVarDecl* FileVarDecl::CreateImpl(Deserializer& D) {
|
||||
FileVarDecl* decl =
|
||||
new FileVarDecl(SourceLocation(),NULL,QualType(),None,NULL);
|
||||
|
||||
decl->VarDecl::ReadImpl(D);
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ParmDecl Serialization.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void ParmVarDecl::EmitImpl(llvm::Serializer& S) const {
|
||||
VarDecl::EmitImpl(S);
|
||||
S.EmitInt(getObjCDeclQualifier()); // From ParmVarDecl.
|
||||
}
|
||||
|
||||
ParmVarDecl* ParmVarDecl::CreateImpl(Deserializer& D) {
|
||||
ParmVarDecl* decl =
|
||||
new ParmVarDecl(SourceLocation(),NULL,QualType(),None,NULL);
|
||||
|
||||
decl->VarDecl::ReadImpl(D);
|
||||
decl->objcDeclQualifier = static_cast<ObjCDeclQualifier>(D.ReadInt());
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// EnumDecl Serialization.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void EnumDecl::EmitImpl(Serializer& S) const {
|
||||
ScopedDecl::EmitInRec(S);
|
||||
S.EmitBool(isDefinition());
|
||||
S.Emit(IntegerType);
|
||||
S.BatchEmitOwnedPtrs(ElementList,getNextDeclarator());
|
||||
}
|
||||
|
||||
EnumDecl* EnumDecl::CreateImpl(Deserializer& D) {
|
||||
EnumDecl* decl = new EnumDecl(SourceLocation(),NULL,NULL);
|
||||
|
||||
decl->ScopedDecl::ReadInRec(D);
|
||||
decl->setDefinition(D.ReadBool());
|
||||
decl->IntegerType = QualType::ReadVal(D);
|
||||
|
||||
Decl* next_declarator;
|
||||
Decl* Elist;
|
||||
|
||||
D.BatchReadOwnedPtrs(Elist,next_declarator);
|
||||
|
||||
decl->ElementList = cast_or_null<EnumConstantDecl>(Elist);
|
||||
decl->setNextDeclarator(cast_or_null<ScopedDecl>(next_declarator));
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// EnumConstantDecl Serialization.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void EnumConstantDecl::EmitImpl(Serializer& S) const {
|
||||
S.Emit(Val);
|
||||
ValueDecl::EmitInRec(S);
|
||||
S.BatchEmitOwnedPtrs(getNextDeclarator(),Init);
|
||||
}
|
||||
|
||||
EnumConstantDecl* EnumConstantDecl::CreateImpl(Deserializer& D) {
|
||||
llvm::APSInt val(1);
|
||||
D.Read(val);
|
||||
|
||||
EnumConstantDecl* decl =
|
||||
new EnumConstantDecl(SourceLocation(),NULL,QualType(),NULL,
|
||||
val,NULL);
|
||||
|
||||
decl->ValueDecl::ReadInRec(D);
|
||||
|
||||
Decl* next_declarator;
|
||||
|
||||
D.BatchReadOwnedPtrs(next_declarator,decl->Init);
|
||||
|
||||
decl->setNextDeclarator(cast_or_null<ScopedDecl>(next_declarator));
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FieldDecl Serialization.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void FieldDecl::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
NamedDecl::EmitInRec(S);
|
||||
S.EmitOwnedPtr(BitWidth);
|
||||
}
|
||||
|
||||
FieldDecl* FieldDecl::CreateImpl(Deserializer& D) {
|
||||
FieldDecl* decl = new FieldDecl(SourceLocation(),NULL,QualType());
|
||||
decl->DeclType.ReadBackpatch(D);
|
||||
decl->ReadInRec(D);
|
||||
decl->BitWidth = D.ReadOwnedPtr<Expr>();
|
||||
return decl;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FunctionDecl Serialization.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void FunctionDecl::EmitImpl(Serializer& S) const {
|
||||
S.EmitInt(SClass); // From FunctionDecl.
|
||||
S.EmitBool(IsInline); // From FunctionDecl.
|
||||
ValueDecl::EmitInRec(S);
|
||||
S.EmitPtr(DeclChain);
|
||||
|
||||
// NOTE: We do not need to serialize out the number of parameters, because
|
||||
// that is encoded in the type (accessed via getNumParams()).
|
||||
|
||||
if (ParamInfo != NULL) {
|
||||
S.EmitBool(true);
|
||||
S.BatchEmitOwnedPtrs(getNumParams(),&ParamInfo[0], Body,
|
||||
getNextDeclarator());
|
||||
}
|
||||
else {
|
||||
S.EmitBool(false);
|
||||
S.BatchEmitOwnedPtrs(Body,getNextDeclarator());
|
||||
}
|
||||
}
|
||||
|
||||
FunctionDecl* FunctionDecl::CreateImpl(Deserializer& D) {
|
||||
StorageClass SClass = static_cast<StorageClass>(D.ReadInt());
|
||||
bool IsInline = D.ReadBool();
|
||||
|
||||
FunctionDecl* decl =
|
||||
new FunctionDecl(SourceLocation(),NULL,QualType(),SClass,IsInline);
|
||||
|
||||
decl->ValueDecl::ReadInRec(D);
|
||||
D.ReadPtr(decl->DeclChain);
|
||||
|
||||
Decl* next_declarator;
|
||||
|
||||
bool hasParamDecls = D.ReadBool();
|
||||
|
||||
decl->ParamInfo = hasParamDecls
|
||||
? new ParmVarDecl*[decl->getNumParams()]
|
||||
: NULL;
|
||||
|
||||
if (hasParamDecls)
|
||||
D.BatchReadOwnedPtrs(decl->getNumParams(),
|
||||
reinterpret_cast<Decl**>(&decl->ParamInfo[0]),
|
||||
decl->Body, next_declarator);
|
||||
else
|
||||
D.BatchReadOwnedPtrs(decl->Body, next_declarator);
|
||||
|
||||
decl->setNextDeclarator(cast_or_null<ScopedDecl>(next_declarator));
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// RecordDecl Serialization.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void RecordDecl::EmitImpl(Serializer& S) const {
|
||||
ScopedDecl::EmitInRec(S);
|
||||
S.EmitBool(isDefinition());
|
||||
S.EmitBool(hasFlexibleArrayMember());
|
||||
S.EmitSInt(getNumMembers());
|
||||
if (getNumMembers() > 0) {
|
||||
assert (Members);
|
||||
S.BatchEmitOwnedPtrs((unsigned) getNumMembers(),
|
||||
(Decl**) &Members[0],getNextDeclarator());
|
||||
}
|
||||
else
|
||||
ScopedDecl::EmitOutRec(S);
|
||||
}
|
||||
|
||||
RecordDecl* RecordDecl::CreateImpl(Decl::Kind DK, Deserializer& D) {
|
||||
RecordDecl* decl = new RecordDecl(DK,SourceLocation(),NULL,NULL);
|
||||
|
||||
decl->ScopedDecl::ReadInRec(D);
|
||||
decl->setDefinition(D.ReadBool());
|
||||
decl->setHasFlexibleArrayMember(D.ReadBool());
|
||||
decl->NumMembers = D.ReadSInt();
|
||||
|
||||
if (decl->getNumMembers() > 0) {
|
||||
Decl* next_declarator;
|
||||
decl->Members = new FieldDecl*[(unsigned) decl->getNumMembers()];
|
||||
|
||||
D.BatchReadOwnedPtrs((unsigned) decl->getNumMembers(),
|
||||
(Decl**) &decl->Members[0],
|
||||
next_declarator);
|
||||
|
||||
decl->setNextDeclarator(cast_or_null<ScopedDecl>(next_declarator));
|
||||
}
|
||||
else
|
||||
decl->ScopedDecl::ReadOutRec(D);
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TypedefDecl Serialization.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void TypedefDecl::EmitImpl(Serializer& S) const {
|
||||
S.Emit(UnderlyingType);
|
||||
ScopedDecl::EmitInRec(S);
|
||||
ScopedDecl::EmitOutRec(S);
|
||||
}
|
||||
|
||||
TypedefDecl* TypedefDecl::CreateImpl(Deserializer& D) {
|
||||
QualType T = QualType::ReadVal(D);
|
||||
|
||||
TypedefDecl* decl = new TypedefDecl(SourceLocation(),NULL,T,NULL);
|
||||
|
||||
decl->ScopedDecl::ReadInRec(D);
|
||||
decl->ScopedDecl::ReadOutRec(D);
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LinkageSpec Serialization.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void LinkageSpecDecl::EmitInRec(Serializer& S) const {
|
||||
Decl::EmitInRec(S);
|
||||
S.EmitInt(getLanguage());
|
||||
S.EmitPtr(D);
|
||||
}
|
||||
|
||||
void LinkageSpecDecl::ReadInRec(Deserializer& D) {
|
||||
Decl::ReadInRec(D);
|
||||
Language = static_cast<LanguageIDs>(D.ReadInt());
|
||||
D.ReadPtr(this->D);
|
||||
}
|
||||
1285
clang/AST/Expr.cpp
1285
clang/AST/Expr.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,37 +0,0 @@
|
||||
//===--- ExprCXX.cpp - (C++) Expression AST Node Implementation -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the subclesses of Expr class declared in ExprCXX.h
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Child Iterators for iterating over subexpressions/substatements
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
// CXXCastExpr
|
||||
Stmt::child_iterator CXXCastExpr::child_begin() {
|
||||
return reinterpret_cast<Stmt**>(&Op);
|
||||
}
|
||||
|
||||
Stmt::child_iterator CXXCastExpr::child_end() {
|
||||
return reinterpret_cast<Stmt**>(&Op)+1;
|
||||
}
|
||||
|
||||
// CXXBoolLiteralExpr
|
||||
Stmt::child_iterator CXXBoolLiteralExpr::child_begin() {
|
||||
return child_iterator();
|
||||
}
|
||||
Stmt::child_iterator CXXBoolLiteralExpr::child_end() {
|
||||
return child_iterator();
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
##===- clang/AST/Makefile ----------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# This implements the AST library for the C-Language front-end.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../..
|
||||
LIBRARYNAME := clangAST
|
||||
BUILD_ARCHIVE = 1
|
||||
CXXFLAGS = -fno-rtti
|
||||
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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/Basic/IdentifierTable.h"
|
||||
using namespace clang;
|
||||
|
||||
static struct StmtClassNameTable {
|
||||
const char *Name;
|
||||
unsigned Counter;
|
||||
unsigned Size;
|
||||
} StmtClassInfo[Stmt::lastExprConstant+1];
|
||||
|
||||
static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
|
||||
static bool Initialized = false;
|
||||
if (Initialized)
|
||||
return StmtClassInfo[E];
|
||||
|
||||
// Intialize the table on the first use.
|
||||
Initialized = true;
|
||||
#define STMT(N, CLASS, PARENT) \
|
||||
StmtClassInfo[N].Name = #CLASS; \
|
||||
StmtClassInfo[N].Size = sizeof(CLASS);
|
||||
#include "clang/AST/StmtNodes.def"
|
||||
|
||||
return StmtClassInfo[E];
|
||||
}
|
||||
|
||||
const char *Stmt::getStmtClassName() const {
|
||||
return getStmtInfoTableEntry(sClass).Name;
|
||||
}
|
||||
|
||||
void Stmt::PrintStats() {
|
||||
// Ensure the table is primed.
|
||||
getStmtInfoTableEntry(Stmt::NullStmtClass);
|
||||
|
||||
unsigned sum = 0;
|
||||
fprintf(stderr, "*** Stmt/Expr Stats:\n");
|
||||
for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
|
||||
if (StmtClassInfo[i].Name == 0) continue;
|
||||
sum += StmtClassInfo[i].Counter;
|
||||
}
|
||||
fprintf(stderr, " %d stmts/exprs total.\n", sum);
|
||||
sum = 0;
|
||||
for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
|
||||
if (StmtClassInfo[i].Name == 0) continue;
|
||||
fprintf(stderr, " %d %s, %d each (%d bytes)\n",
|
||||
StmtClassInfo[i].Counter, StmtClassInfo[i].Name,
|
||||
StmtClassInfo[i].Size,
|
||||
StmtClassInfo[i].Counter*StmtClassInfo[i].Size);
|
||||
sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size;
|
||||
}
|
||||
fprintf(stderr, "Total bytes = %d\n", sum);
|
||||
}
|
||||
|
||||
void Stmt::addStmtClass(StmtClass s) {
|
||||
++getStmtInfoTableEntry(s).Counter;
|
||||
}
|
||||
|
||||
static bool StatSwitch = false;
|
||||
|
||||
bool Stmt::CollectingStats(bool enable) {
|
||||
if (enable) StatSwitch = true;
|
||||
return StatSwitch;
|
||||
}
|
||||
|
||||
|
||||
const char *LabelStmt::getName() const {
|
||||
return getID()->getName();
|
||||
}
|
||||
|
||||
// This is defined here to avoid polluting Stmt.h with importing Expr.h
|
||||
SourceRange ReturnStmt::getSourceRange() const {
|
||||
if (RetExpr)
|
||||
return SourceRange(RetLoc, RetExpr->getLocEnd());
|
||||
else
|
||||
return SourceRange(RetLoc);
|
||||
}
|
||||
|
||||
bool Stmt::hasImplicitControlFlow() const {
|
||||
switch (sClass) {
|
||||
default:
|
||||
return false;
|
||||
|
||||
case CallExprClass:
|
||||
case ConditionalOperatorClass:
|
||||
case ChooseExprClass:
|
||||
case StmtExprClass:
|
||||
case DeclStmtClass:
|
||||
return true;
|
||||
|
||||
case Stmt::BinaryOperatorClass: {
|
||||
const BinaryOperator* B = cast<BinaryOperator>(this);
|
||||
if (B->isLogicalOp() || B->getOpcode() == BinaryOperator::Comma)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AsmStmt::AsmStmt(SourceLocation asmloc,
|
||||
bool isvolatile,
|
||||
unsigned numoutputs,
|
||||
unsigned numinputs,
|
||||
std::string *names,
|
||||
StringLiteral **constraints,
|
||||
Expr **exprs,
|
||||
StringLiteral *asmstr,
|
||||
unsigned numclobbers,
|
||||
StringLiteral **clobbers,
|
||||
SourceLocation rparenloc)
|
||||
: Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
|
||||
, IsVolatile(isvolatile), NumOutputs(numoutputs), NumInputs(numinputs)
|
||||
{
|
||||
for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) {
|
||||
Names.push_back(names[i]);
|
||||
Exprs.push_back(exprs[i]);
|
||||
Constraints.push_back(constraints[i]);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i != numclobbers; i++)
|
||||
Clobbers.push_back(clobbers[i]);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Child Iterators for iterating over subexpressions/substatements
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// DeclStmt
|
||||
Stmt::child_iterator DeclStmt::child_begin() { return getDecl(); }
|
||||
Stmt::child_iterator DeclStmt::child_end() { return child_iterator(); }
|
||||
|
||||
// NullStmt
|
||||
Stmt::child_iterator NullStmt::child_begin() { return child_iterator(); }
|
||||
Stmt::child_iterator NullStmt::child_end() { return child_iterator(); }
|
||||
|
||||
// CompoundStmt
|
||||
Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; }
|
||||
Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+Body.size(); }
|
||||
|
||||
// CaseStmt
|
||||
Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; }
|
||||
Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; }
|
||||
|
||||
// DefaultStmt
|
||||
Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; }
|
||||
Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; }
|
||||
|
||||
// LabelStmt
|
||||
Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; }
|
||||
Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; }
|
||||
|
||||
// IfStmt
|
||||
Stmt::child_iterator IfStmt::child_begin() { return &SubExprs[0]; }
|
||||
Stmt::child_iterator IfStmt::child_end() { return &SubExprs[0]+END_EXPR; }
|
||||
|
||||
// SwitchStmt
|
||||
Stmt::child_iterator SwitchStmt::child_begin() { return &SubExprs[0]; }
|
||||
Stmt::child_iterator SwitchStmt::child_end() { return &SubExprs[0]+END_EXPR; }
|
||||
|
||||
// WhileStmt
|
||||
Stmt::child_iterator WhileStmt::child_begin() { return &SubExprs[0]; }
|
||||
Stmt::child_iterator WhileStmt::child_end() { return &SubExprs[0]+END_EXPR; }
|
||||
|
||||
// DoStmt
|
||||
Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; }
|
||||
Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; }
|
||||
|
||||
// ForStmt
|
||||
Stmt::child_iterator ForStmt::child_begin() { return &SubExprs[0]; }
|
||||
Stmt::child_iterator ForStmt::child_end() { return &SubExprs[0]+END_EXPR; }
|
||||
|
||||
// ObjCForCollectionStmt
|
||||
Stmt::child_iterator ObjCForCollectionStmt::child_begin() {
|
||||
return &SubExprs[0];
|
||||
}
|
||||
Stmt::child_iterator ObjCForCollectionStmt::child_end() {
|
||||
return &SubExprs[0]+END_EXPR;
|
||||
}
|
||||
|
||||
// GotoStmt
|
||||
Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); }
|
||||
Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); }
|
||||
|
||||
// IndirectGotoStmt
|
||||
Stmt::child_iterator IndirectGotoStmt::child_begin() {
|
||||
return reinterpret_cast<Stmt**>(&Target);
|
||||
}
|
||||
|
||||
Stmt::child_iterator IndirectGotoStmt::child_end() { return ++child_begin(); }
|
||||
|
||||
// ContinueStmt
|
||||
Stmt::child_iterator ContinueStmt::child_begin() { return child_iterator(); }
|
||||
Stmt::child_iterator ContinueStmt::child_end() { return child_iterator(); }
|
||||
|
||||
// BreakStmt
|
||||
Stmt::child_iterator BreakStmt::child_begin() { return child_iterator(); }
|
||||
Stmt::child_iterator BreakStmt::child_end() { return child_iterator(); }
|
||||
|
||||
// ReturnStmt
|
||||
Stmt::child_iterator ReturnStmt::child_begin() {
|
||||
if (RetExpr) return reinterpret_cast<Stmt**>(&RetExpr);
|
||||
else return child_iterator();
|
||||
}
|
||||
|
||||
Stmt::child_iterator ReturnStmt::child_end() {
|
||||
if (RetExpr) return reinterpret_cast<Stmt**>(&RetExpr)+1;
|
||||
else return child_iterator();
|
||||
}
|
||||
|
||||
// AsmStmt
|
||||
Stmt::child_iterator AsmStmt::child_begin() { return child_iterator(); }
|
||||
Stmt::child_iterator AsmStmt::child_end() { return child_iterator(); }
|
||||
|
||||
// ObjCAtCatchStmt
|
||||
Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; }
|
||||
Stmt::child_iterator ObjCAtCatchStmt::child_end() {
|
||||
return &SubExprs[0]+END_EXPR;
|
||||
}
|
||||
|
||||
// ObjCAtFinallyStmt
|
||||
Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; }
|
||||
Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; }
|
||||
|
||||
// ObjCAtTryStmt
|
||||
Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; }
|
||||
Stmt::child_iterator ObjCAtTryStmt::child_end() {
|
||||
return &SubStmts[0]+END_EXPR;
|
||||
}
|
||||
|
||||
// ObjCAtThrowStmt
|
||||
Stmt::child_iterator ObjCAtThrowStmt::child_begin() {
|
||||
return &Throw;
|
||||
}
|
||||
|
||||
Stmt::child_iterator ObjCAtThrowStmt::child_end() {
|
||||
return &Throw+1;
|
||||
}
|
||||
@@ -1,472 +0,0 @@
|
||||
//===--- StmtDumper.cpp - Dumping implementation for Stmt ASTs ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the Stmt::dump/Stmt::print methods, which dump out the
|
||||
// AST in a form that exposes type details and other fields.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <cstdio>
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// StmtDumper Visitor
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor<StmtDumper> {
|
||||
SourceManager *SM;
|
||||
FILE *F;
|
||||
unsigned IndentLevel;
|
||||
|
||||
/// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
|
||||
/// the first few levels of an AST. This keeps track of how many ast levels
|
||||
/// are left.
|
||||
unsigned MaxDepth;
|
||||
|
||||
/// LastLocFilename/LastLocLine - Keep track of the last location we print
|
||||
/// out so that we can print out deltas from then on out.
|
||||
const char *LastLocFilename;
|
||||
unsigned LastLocLine;
|
||||
public:
|
||||
StmtDumper(SourceManager *sm, FILE *f, unsigned maxDepth)
|
||||
: SM(sm), F(f), IndentLevel(0-1), MaxDepth(maxDepth) {
|
||||
LastLocFilename = "";
|
||||
LastLocLine = ~0U;
|
||||
}
|
||||
|
||||
void DumpSubTree(Stmt *S) {
|
||||
// Prune the recursion if not using dump all.
|
||||
if (MaxDepth == 0) return;
|
||||
|
||||
++IndentLevel;
|
||||
if (S) {
|
||||
if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
|
||||
VisitDeclStmt(DS);
|
||||
else {
|
||||
Visit(S);
|
||||
|
||||
// Print out children.
|
||||
Stmt::child_iterator CI = S->child_begin(), CE = S->child_end();
|
||||
if (CI != CE) {
|
||||
while (CI != CE) {
|
||||
fprintf(F, "\n");
|
||||
DumpSubTree(*CI++);
|
||||
}
|
||||
}
|
||||
fprintf(F, ")");
|
||||
}
|
||||
} else {
|
||||
Indent();
|
||||
fprintf(F, "<<<NULL>>>");
|
||||
}
|
||||
--IndentLevel;
|
||||
}
|
||||
|
||||
void DumpDeclarator(Decl *D);
|
||||
|
||||
void Indent() const {
|
||||
for (int i = 0, e = IndentLevel; i < e; ++i)
|
||||
fprintf(F, " ");
|
||||
}
|
||||
|
||||
void DumpType(QualType T) {
|
||||
fprintf(F, "'%s'", T.getAsString().c_str());
|
||||
|
||||
// If the type is directly a typedef, strip off typedefness to give at
|
||||
// least one level of concreteness.
|
||||
if (TypedefType *TDT = dyn_cast<TypedefType>(T))
|
||||
fprintf(F, ":'%s'", TDT->LookThroughTypedefs().getAsString().c_str());
|
||||
}
|
||||
void DumpStmt(const Stmt *Node) {
|
||||
Indent();
|
||||
fprintf(F, "(%s %p", Node->getStmtClassName(), (void*)Node);
|
||||
DumpSourceRange(Node);
|
||||
}
|
||||
void DumpExpr(const Expr *Node) {
|
||||
DumpStmt(Node);
|
||||
fprintf(F, " ");
|
||||
DumpType(Node->getType());
|
||||
}
|
||||
void DumpSourceRange(const Stmt *Node);
|
||||
void DumpLocation(SourceLocation Loc);
|
||||
|
||||
// Stmts.
|
||||
void VisitStmt(Stmt *Node);
|
||||
void VisitDeclStmt(DeclStmt *Node);
|
||||
void VisitLabelStmt(LabelStmt *Node);
|
||||
void VisitGotoStmt(GotoStmt *Node);
|
||||
|
||||
// Exprs
|
||||
void VisitExpr(Expr *Node);
|
||||
void VisitDeclRefExpr(DeclRefExpr *Node);
|
||||
void VisitPreDefinedExpr(PreDefinedExpr *Node);
|
||||
void VisitCharacterLiteral(CharacterLiteral *Node);
|
||||
void VisitIntegerLiteral(IntegerLiteral *Node);
|
||||
void VisitFloatingLiteral(FloatingLiteral *Node);
|
||||
void VisitStringLiteral(StringLiteral *Str);
|
||||
void VisitUnaryOperator(UnaryOperator *Node);
|
||||
void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node);
|
||||
void VisitMemberExpr(MemberExpr *Node);
|
||||
void VisitOCUVectorElementExpr(OCUVectorElementExpr *Node);
|
||||
void VisitBinaryOperator(BinaryOperator *Node);
|
||||
void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
|
||||
void VisitAddrLabelExpr(AddrLabelExpr *Node);
|
||||
void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node);
|
||||
|
||||
// C++
|
||||
void VisitCXXCastExpr(CXXCastExpr *Node);
|
||||
void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node);
|
||||
|
||||
// ObjC
|
||||
void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
|
||||
void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
|
||||
void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
|
||||
};
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utilities
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void StmtDumper::DumpLocation(SourceLocation Loc) {
|
||||
SourceLocation PhysLoc = SM->getPhysicalLoc(Loc);
|
||||
|
||||
// The general format we print out is filename:line:col, but we drop pieces
|
||||
// that haven't changed since the last loc printed.
|
||||
const char *Filename = SM->getSourceName(PhysLoc);
|
||||
unsigned LineNo = SM->getLineNumber(PhysLoc);
|
||||
if (strcmp(Filename, LastLocFilename) != 0) {
|
||||
fprintf(stderr, "%s:%u:%u", Filename, LineNo, SM->getColumnNumber(PhysLoc));
|
||||
LastLocFilename = Filename;
|
||||
LastLocLine = LineNo;
|
||||
} else if (LineNo != LastLocLine) {
|
||||
fprintf(stderr, "line:%u:%u", LineNo, SM->getColumnNumber(PhysLoc));
|
||||
LastLocLine = LineNo;
|
||||
} else {
|
||||
fprintf(stderr, "col:%u", SM->getColumnNumber(PhysLoc));
|
||||
}
|
||||
}
|
||||
|
||||
void StmtDumper::DumpSourceRange(const Stmt *Node) {
|
||||
// Can't translate locations if a SourceManager isn't available.
|
||||
if (SM == 0) return;
|
||||
|
||||
// TODO: If the parent expression is available, we can print a delta vs its
|
||||
// location.
|
||||
SourceRange R = Node->getSourceRange();
|
||||
|
||||
fprintf(stderr, " <");
|
||||
DumpLocation(R.getBegin());
|
||||
if (R.getBegin() != R.getEnd()) {
|
||||
fprintf(stderr, ", ");
|
||||
DumpLocation(R.getEnd());
|
||||
}
|
||||
fprintf(stderr, ">");
|
||||
|
||||
// <t2.c:123:421[blah], t2.c:412:321>
|
||||
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Stmt printing methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void StmtDumper::VisitStmt(Stmt *Node) {
|
||||
DumpStmt(Node);
|
||||
}
|
||||
|
||||
void StmtDumper::DumpDeclarator(Decl *D) {
|
||||
// FIXME: Need to complete/beautify this... this code simply shows the
|
||||
// nodes are where they need to be.
|
||||
if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
|
||||
fprintf(F, "\"typedef %s %s\"",
|
||||
localType->getUnderlyingType().getAsString().c_str(),
|
||||
localType->getName());
|
||||
} else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
|
||||
fprintf(F, "\"");
|
||||
// Emit storage class for vardecls.
|
||||
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
|
||||
switch (V->getStorageClass()) {
|
||||
default: assert(0 && "Unknown storage class!");
|
||||
case VarDecl::None: break;
|
||||
case VarDecl::Extern: fprintf(F, "extern "); break;
|
||||
case VarDecl::Static: fprintf(F, "static "); break;
|
||||
case VarDecl::Auto: fprintf(F, "auto "); break;
|
||||
case VarDecl::Register: fprintf(F, "register "); break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Name = VD->getName();
|
||||
VD->getType().getAsStringInternal(Name);
|
||||
fprintf(F, "%s", Name.c_str());
|
||||
|
||||
// If this is a vardecl with an initializer, emit it.
|
||||
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
|
||||
if (V->getInit()) {
|
||||
fprintf(F, " =\n");
|
||||
DumpSubTree(V->getInit());
|
||||
}
|
||||
}
|
||||
fprintf(F, "\"");
|
||||
} else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
|
||||
// print a free standing tag decl (e.g. "struct x;").
|
||||
const char *tagname;
|
||||
if (const IdentifierInfo *II = TD->getIdentifier())
|
||||
tagname = II->getName();
|
||||
else
|
||||
tagname = "<anonymous>";
|
||||
fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname);
|
||||
// FIXME: print tag bodies.
|
||||
} else {
|
||||
assert(0 && "Unexpected decl");
|
||||
}
|
||||
}
|
||||
|
||||
void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
|
||||
DumpStmt(Node);
|
||||
fprintf(F,"\n");
|
||||
for (ScopedDecl *D = Node->getDecl(); D; D = D->getNextDeclarator()) {
|
||||
++IndentLevel;
|
||||
Indent();
|
||||
fprintf(F, "%p ", (void*) D);
|
||||
DumpDeclarator(D);
|
||||
if (D->getNextDeclarator())
|
||||
fprintf(F,"\n");
|
||||
--IndentLevel;
|
||||
}
|
||||
}
|
||||
|
||||
void StmtDumper::VisitLabelStmt(LabelStmt *Node) {
|
||||
DumpStmt(Node);
|
||||
fprintf(F, " '%s'\n", Node->getName());
|
||||
}
|
||||
|
||||
void StmtDumper::VisitGotoStmt(GotoStmt *Node) {
|
||||
DumpStmt(Node);
|
||||
fprintf(F, " '%s':%p", Node->getLabel()->getName(), (void*)Node->getLabel());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Expr printing methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void StmtDumper::VisitExpr(Expr *Node) {
|
||||
DumpExpr(Node);
|
||||
}
|
||||
|
||||
void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
|
||||
fprintf(F, " ");
|
||||
switch (Node->getDecl()->getKind()) {
|
||||
case Decl::Function: fprintf(F,"FunctionDecl"); break;
|
||||
case Decl::BlockVar: fprintf(F,"BlockVar"); break;
|
||||
case Decl::FileVar: fprintf(F,"FileVar"); break;
|
||||
case Decl::ParmVar: fprintf(F,"ParmVar"); break;
|
||||
case Decl::EnumConstant: fprintf(F,"EnumConstant"); break;
|
||||
case Decl::Typedef: fprintf(F,"Typedef"); break;
|
||||
case Decl::Struct: fprintf(F,"Struct"); break;
|
||||
case Decl::Union: fprintf(F,"Union"); break;
|
||||
case Decl::Class: fprintf(F,"Class"); break;
|
||||
case Decl::Enum: fprintf(F,"Enum"); break;
|
||||
case Decl::ObjCInterface: fprintf(F,"ObjCInterface"); break;
|
||||
case Decl::ObjCClass: fprintf(F,"ObjCClass"); break;
|
||||
default: fprintf(F,"Decl"); break;
|
||||
}
|
||||
|
||||
fprintf(F, "='%s' %p", Node->getDecl()->getName(), (void*)Node->getDecl());
|
||||
}
|
||||
|
||||
void StmtDumper::VisitPreDefinedExpr(PreDefinedExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
switch (Node->getIdentType()) {
|
||||
default:
|
||||
assert(0 && "unknown case");
|
||||
case PreDefinedExpr::Func:
|
||||
fprintf(F, " __func__");
|
||||
break;
|
||||
case PreDefinedExpr::Function:
|
||||
fprintf(F, " __FUNCTION__");
|
||||
break;
|
||||
case PreDefinedExpr::PrettyFunction:
|
||||
fprintf(F, " __PRETTY_FUNCTION__");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) {
|
||||
DumpExpr(Node);
|
||||
fprintf(F, " %d", Node->getValue());
|
||||
}
|
||||
|
||||
void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) {
|
||||
DumpExpr(Node);
|
||||
|
||||
bool isSigned = Node->getType()->isSignedIntegerType();
|
||||
fprintf(F, " %s", Node->getValue().toString(10, isSigned).c_str());
|
||||
}
|
||||
void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) {
|
||||
DumpExpr(Node);
|
||||
fprintf(F, " %f", Node->getValueAsDouble());
|
||||
}
|
||||
|
||||
void StmtDumper::VisitStringLiteral(StringLiteral *Str) {
|
||||
DumpExpr(Str);
|
||||
// FIXME: this doesn't print wstrings right.
|
||||
fprintf(F, " %s\"", Str->isWide() ? "L" : "");
|
||||
|
||||
for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) {
|
||||
switch (char C = Str->getStrData()[i]) {
|
||||
default:
|
||||
if (isprint(C))
|
||||
fputc(C, F);
|
||||
else
|
||||
fprintf(F, "\\%03o", C);
|
||||
break;
|
||||
// Handle some common ones to make dumps prettier.
|
||||
case '\\': fprintf(F, "\\\\"); break;
|
||||
case '"': fprintf(F, "\\\""); break;
|
||||
case '\n': fprintf(F, "\\n"); break;
|
||||
case '\t': fprintf(F, "\\t"); break;
|
||||
case '\a': fprintf(F, "\\a"); break;
|
||||
case '\b': fprintf(F, "\\b"); break;
|
||||
}
|
||||
}
|
||||
fprintf(F, "\"");
|
||||
}
|
||||
|
||||
void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) {
|
||||
DumpExpr(Node);
|
||||
fprintf(F, " %s '%s'", Node->isPostfix() ? "postfix" : "prefix",
|
||||
UnaryOperator::getOpcodeStr(Node->getOpcode()));
|
||||
}
|
||||
void StmtDumper::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
fprintf(F, " %s ", Node->isSizeOf() ? "sizeof" : "alignof");
|
||||
DumpType(Node->getArgumentType());
|
||||
}
|
||||
|
||||
void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".",
|
||||
Node->getMemberDecl()->getName(), (void*)Node->getMemberDecl());
|
||||
}
|
||||
void StmtDumper::VisitOCUVectorElementExpr(OCUVectorElementExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
fprintf(F, " %s", Node->getAccessor().getName());
|
||||
}
|
||||
void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) {
|
||||
DumpExpr(Node);
|
||||
fprintf(F, " '%s'", BinaryOperator::getOpcodeStr(Node->getOpcode()));
|
||||
}
|
||||
void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
|
||||
DumpExpr(Node);
|
||||
fprintf(F, " '%s' ComputeTy=",
|
||||
BinaryOperator::getOpcodeStr(Node->getOpcode()));
|
||||
DumpType(Node->getComputationType());
|
||||
}
|
||||
|
||||
// GNU extensions.
|
||||
|
||||
void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
fprintf(F, " %s %p", Node->getLabel()->getName(), (void*)Node->getLabel());
|
||||
}
|
||||
|
||||
void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
fprintf(F, " ");
|
||||
DumpType(Node->getArgType1());
|
||||
fprintf(F, " ");
|
||||
DumpType(Node->getArgType2());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// C++ Expressions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void StmtDumper::VisitCXXCastExpr(CXXCastExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
fprintf(F, " %s", CXXCastExpr::getOpcodeStr(Node->getOpcode()));
|
||||
}
|
||||
|
||||
void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
fprintf(F, " %s", Node->getValue() ? "true" : "false");
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Obj-C Expressions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
|
||||
fprintf(F, " ");
|
||||
DumpType(Node->getEncodedType());
|
||||
}
|
||||
|
||||
void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
|
||||
fprintf(F, " ");
|
||||
Selector &selector = Node->getSelector();
|
||||
fprintf(F, "%s", selector.getName().c_str());
|
||||
}
|
||||
|
||||
void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
|
||||
fprintf(F, " ");
|
||||
fprintf(F, "%s", Node->getProtocol()->getName());
|
||||
}
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Stmt method implementations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// dump - This does a local dump of the specified AST fragment. It dumps the
|
||||
/// specified node and a few nodes underneath it, but not the whole subtree.
|
||||
/// This is useful in a debugger.
|
||||
void Stmt::dump(SourceManager &SM) const {
|
||||
StmtDumper P(&SM, stderr, 4);
|
||||
P.DumpSubTree(const_cast<Stmt*>(this));
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/// dump - This does a local dump of the specified AST fragment. It dumps the
|
||||
/// specified node and a few nodes underneath it, but not the whole subtree.
|
||||
/// This is useful in a debugger.
|
||||
void Stmt::dump() const {
|
||||
StmtDumper P(0, stderr, 4);
|
||||
P.DumpSubTree(const_cast<Stmt*>(this));
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
|
||||
void Stmt::dumpAll(SourceManager &SM) const {
|
||||
StmtDumper P(&SM, stderr, ~0U);
|
||||
P.DumpSubTree(const_cast<Stmt*>(this));
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
|
||||
void Stmt::dumpAll() const {
|
||||
StmtDumper P(0, stderr, ~0U);
|
||||
P.DumpSubTree(const_cast<Stmt*>(this));
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
//===--- StmtIterator.cpp - Iterators for Statements ------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines internal methods for StmtIterator.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/StmtIterator.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
static inline VariableArrayType* FindVA(Type* t) {
|
||||
while (ArrayType* vt = dyn_cast<ArrayType>(t)) {
|
||||
if (VariableArrayType* vat = dyn_cast<VariableArrayType>(vt))
|
||||
if (vat->getSizeExpr())
|
||||
return vat;
|
||||
|
||||
t = vt->getElementType().getTypePtr();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void StmtIteratorBase::NextVA() {
|
||||
assert (getVAPtr());
|
||||
|
||||
VariableArrayType* p = getVAPtr();
|
||||
p = FindVA(p->getElementType().getTypePtr());
|
||||
setVAPtr(p);
|
||||
|
||||
if (!p && decl) {
|
||||
if (VarDecl* VD = dyn_cast<VarDecl>(decl))
|
||||
if (VD->Init)
|
||||
return;
|
||||
|
||||
NextDecl();
|
||||
}
|
||||
else {
|
||||
RawVAPtr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void StmtIteratorBase::NextDecl(bool ImmediateAdvance) {
|
||||
assert (inDecl());
|
||||
assert (getVAPtr() == NULL);
|
||||
assert (decl);
|
||||
|
||||
if (ImmediateAdvance) {
|
||||
decl = decl->getNextDeclarator();
|
||||
|
||||
if (!decl) {
|
||||
RawVAPtr = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for ( ; decl ; decl = decl->getNextDeclarator()) {
|
||||
if (VarDecl* VD = dyn_cast<VarDecl>(decl)) {
|
||||
if (VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) {
|
||||
setVAPtr(VAPtr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (VD->getInit())
|
||||
return;
|
||||
}
|
||||
else if (TypedefDecl* TD = dyn_cast<TypedefDecl>(decl)) {
|
||||
if (VariableArrayType* VAPtr =
|
||||
FindVA(TD->getUnderlyingType().getTypePtr())) {
|
||||
setVAPtr(VAPtr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (EnumConstantDecl* ECD = dyn_cast<EnumConstantDecl>(decl))
|
||||
if (ECD->getInitExpr())
|
||||
return;
|
||||
}
|
||||
|
||||
if (!decl) {
|
||||
RawVAPtr = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
StmtIteratorBase::StmtIteratorBase(ScopedDecl* d)
|
||||
: decl(d), RawVAPtr(DeclMode) {
|
||||
assert (decl);
|
||||
NextDecl(false);
|
||||
}
|
||||
|
||||
StmtIteratorBase::StmtIteratorBase(VariableArrayType* t)
|
||||
: decl(NULL), RawVAPtr(SizeOfTypeVAMode) {
|
||||
RawVAPtr |= reinterpret_cast<uintptr_t>(t);
|
||||
}
|
||||
|
||||
|
||||
Stmt*& StmtIteratorBase::GetDeclExpr() const {
|
||||
if (VariableArrayType* VAPtr = getVAPtr()) {
|
||||
assert (VAPtr->SizeExpr);
|
||||
return reinterpret_cast<Stmt*&>(VAPtr->SizeExpr);
|
||||
}
|
||||
|
||||
if (VarDecl* VD = dyn_cast<VarDecl>(decl)) {
|
||||
assert (VD->Init);
|
||||
return reinterpret_cast<Stmt*&>(VD->Init);
|
||||
}
|
||||
|
||||
EnumConstantDecl* ECD = cast<EnumConstantDecl>(decl);
|
||||
return reinterpret_cast<Stmt*&>(ECD->Init);
|
||||
}
|
||||
@@ -1,828 +0,0 @@
|
||||
//===--- StmtPrinter.cpp - Printing implementation for Stmt ASTs ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the Stmt::dumpPretty/Stmt::printPretty methods, which
|
||||
// pretty print the AST back out to C code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/PrettyPrinter.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include <iomanip>
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// StmtPrinter Visitor
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor<StmtPrinter> {
|
||||
std::ostream &OS;
|
||||
unsigned IndentLevel;
|
||||
clang::PrinterHelper* Helper;
|
||||
public:
|
||||
StmtPrinter(std::ostream &os, PrinterHelper* helper) :
|
||||
OS(os), IndentLevel(0), Helper(helper) {}
|
||||
|
||||
void PrintStmt(Stmt *S, int SubIndent = 1) {
|
||||
IndentLevel += SubIndent;
|
||||
if (S && isa<Expr>(S)) {
|
||||
// If this is an expr used in a stmt context, indent and newline it.
|
||||
Indent();
|
||||
Visit(S);
|
||||
OS << ";\n";
|
||||
} else if (S) {
|
||||
Visit(S);
|
||||
} else {
|
||||
Indent() << "<<<NULL STATEMENT>>>\n";
|
||||
}
|
||||
IndentLevel -= SubIndent;
|
||||
}
|
||||
|
||||
void PrintRawCompoundStmt(CompoundStmt *S);
|
||||
void PrintRawDecl(Decl *D);
|
||||
void PrintRawIfStmt(IfStmt *If);
|
||||
|
||||
void PrintExpr(Expr *E) {
|
||||
if (E)
|
||||
Visit(E);
|
||||
else
|
||||
OS << "<null expr>";
|
||||
}
|
||||
|
||||
std::ostream &Indent(int Delta = 0) const {
|
||||
for (int i = 0, e = IndentLevel+Delta; i < e; ++i)
|
||||
OS << " ";
|
||||
return OS;
|
||||
}
|
||||
|
||||
bool PrintOffsetOfDesignator(Expr *E);
|
||||
void VisitUnaryOffsetOf(UnaryOperator *Node);
|
||||
|
||||
void Visit(Stmt* S) {
|
||||
if (Helper && Helper->handledStmt(S,OS))
|
||||
return;
|
||||
else StmtVisitor<StmtPrinter>::Visit(S);
|
||||
}
|
||||
|
||||
void VisitStmt(Stmt *Node);
|
||||
#define STMT(N, CLASS, PARENT) \
|
||||
void Visit##CLASS(CLASS *Node);
|
||||
#include "clang/AST/StmtNodes.def"
|
||||
};
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Stmt printing methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void StmtPrinter::VisitStmt(Stmt *Node) {
|
||||
Indent() << "<<unknown stmt type>>\n";
|
||||
}
|
||||
|
||||
/// PrintRawCompoundStmt - Print a compound stmt without indenting the {, and
|
||||
/// with no newline after the }.
|
||||
void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) {
|
||||
OS << "{\n";
|
||||
for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end();
|
||||
I != E; ++I)
|
||||
PrintStmt(*I);
|
||||
|
||||
Indent() << "}";
|
||||
}
|
||||
|
||||
void StmtPrinter::PrintRawDecl(Decl *D) {
|
||||
// FIXME: Need to complete/beautify this... this code simply shows the
|
||||
// nodes are where they need to be.
|
||||
if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
|
||||
OS << "typedef " << localType->getUnderlyingType().getAsString();
|
||||
OS << " " << localType->getName();
|
||||
} else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
|
||||
// Emit storage class for vardecls.
|
||||
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
|
||||
switch (V->getStorageClass()) {
|
||||
default: assert(0 && "Unknown storage class!");
|
||||
case VarDecl::None: break;
|
||||
case VarDecl::Extern: OS << "extern "; break;
|
||||
case VarDecl::Static: OS << "static "; break;
|
||||
case VarDecl::Auto: OS << "auto "; break;
|
||||
case VarDecl::Register: OS << "register "; break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Name = VD->getName();
|
||||
VD->getType().getAsStringInternal(Name);
|
||||
OS << Name;
|
||||
|
||||
// If this is a vardecl with an initializer, emit it.
|
||||
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
|
||||
if (V->getInit()) {
|
||||
OS << " = ";
|
||||
PrintExpr(V->getInit());
|
||||
}
|
||||
}
|
||||
} else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
|
||||
// print a free standing tag decl (e.g. "struct x;").
|
||||
OS << TD->getKindName();
|
||||
OS << " ";
|
||||
if (const IdentifierInfo *II = TD->getIdentifier())
|
||||
OS << II->getName();
|
||||
else
|
||||
OS << "<anonymous>";
|
||||
// FIXME: print tag bodies.
|
||||
} else {
|
||||
assert(0 && "Unexpected decl");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void StmtPrinter::VisitNullStmt(NullStmt *Node) {
|
||||
Indent() << ";\n";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitDeclStmt(DeclStmt *Node) {
|
||||
for (ScopedDecl *D = Node->getDecl(); D; D = D->getNextDeclarator()) {
|
||||
Indent();
|
||||
PrintRawDecl(D);
|
||||
OS << ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) {
|
||||
Indent();
|
||||
PrintRawCompoundStmt(Node);
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCaseStmt(CaseStmt *Node) {
|
||||
Indent(-1) << "case ";
|
||||
PrintExpr(Node->getLHS());
|
||||
if (Node->getRHS()) {
|
||||
OS << " ... ";
|
||||
PrintExpr(Node->getRHS());
|
||||
}
|
||||
OS << ":\n";
|
||||
|
||||
PrintStmt(Node->getSubStmt(), 0);
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitDefaultStmt(DefaultStmt *Node) {
|
||||
Indent(-1) << "default:\n";
|
||||
PrintStmt(Node->getSubStmt(), 0);
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitLabelStmt(LabelStmt *Node) {
|
||||
Indent(-1) << Node->getName() << ":\n";
|
||||
PrintStmt(Node->getSubStmt(), 0);
|
||||
}
|
||||
|
||||
void StmtPrinter::PrintRawIfStmt(IfStmt *If) {
|
||||
OS << "if ";
|
||||
PrintExpr(If->getCond());
|
||||
|
||||
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) {
|
||||
OS << ' ';
|
||||
PrintRawCompoundStmt(CS);
|
||||
OS << (If->getElse() ? ' ' : '\n');
|
||||
} else {
|
||||
OS << '\n';
|
||||
PrintStmt(If->getThen());
|
||||
if (If->getElse()) Indent();
|
||||
}
|
||||
|
||||
if (Stmt *Else = If->getElse()) {
|
||||
OS << "else";
|
||||
|
||||
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Else)) {
|
||||
OS << ' ';
|
||||
PrintRawCompoundStmt(CS);
|
||||
OS << '\n';
|
||||
} else if (IfStmt *ElseIf = dyn_cast<IfStmt>(Else)) {
|
||||
OS << ' ';
|
||||
PrintRawIfStmt(ElseIf);
|
||||
} else {
|
||||
OS << '\n';
|
||||
PrintStmt(If->getElse());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitIfStmt(IfStmt *If) {
|
||||
Indent();
|
||||
PrintRawIfStmt(If);
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) {
|
||||
Indent() << "switch (";
|
||||
PrintExpr(Node->getCond());
|
||||
OS << ")";
|
||||
|
||||
// Pretty print compoundstmt bodies (very common).
|
||||
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
|
||||
OS << " ";
|
||||
PrintRawCompoundStmt(CS);
|
||||
OS << "\n";
|
||||
} else {
|
||||
OS << "\n";
|
||||
PrintStmt(Node->getBody());
|
||||
}
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitSwitchCase(SwitchCase*) {
|
||||
assert(0 && "SwitchCase is an abstract class");
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitWhileStmt(WhileStmt *Node) {
|
||||
Indent() << "while (";
|
||||
PrintExpr(Node->getCond());
|
||||
OS << ")\n";
|
||||
PrintStmt(Node->getBody());
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitDoStmt(DoStmt *Node) {
|
||||
Indent() << "do ";
|
||||
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
|
||||
PrintRawCompoundStmt(CS);
|
||||
OS << " ";
|
||||
} else {
|
||||
OS << "\n";
|
||||
PrintStmt(Node->getBody());
|
||||
Indent();
|
||||
}
|
||||
|
||||
OS << "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()) {
|
||||
OS << " ";
|
||||
PrintExpr(Node->getCond());
|
||||
}
|
||||
OS << ";";
|
||||
if (Node->getInc()) {
|
||||
OS << " ";
|
||||
PrintExpr(Node->getInc());
|
||||
}
|
||||
OS << ") ";
|
||||
|
||||
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
|
||||
PrintRawCompoundStmt(CS);
|
||||
OS << "\n";
|
||||
} else {
|
||||
OS << "\n";
|
||||
PrintStmt(Node->getBody());
|
||||
}
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) {
|
||||
Indent() << "for (";
|
||||
if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getElement()))
|
||||
PrintRawDecl(DS->getDecl());
|
||||
else
|
||||
PrintExpr(cast<Expr>(Node->getElement()));
|
||||
OS << " in ";
|
||||
PrintExpr(Node->getCollection());
|
||||
OS << ") ";
|
||||
|
||||
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
|
||||
PrintRawCompoundStmt(CS);
|
||||
OS << "\n";
|
||||
} else {
|
||||
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";
|
||||
}
|
||||
|
||||
|
||||
void StmtPrinter::VisitAsmStmt(AsmStmt *Node) {
|
||||
Indent() << "asm ";
|
||||
|
||||
if (Node->isVolatile())
|
||||
OS << "volatile ";
|
||||
|
||||
OS << "(";
|
||||
VisitStringLiteral(Node->getAsmString());
|
||||
|
||||
// Outputs
|
||||
if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 ||
|
||||
Node->getNumClobbers() != 0)
|
||||
OS << " : ";
|
||||
|
||||
for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) {
|
||||
if (i != 0)
|
||||
OS << ", ";
|
||||
|
||||
if (!Node->getOutputName(i).empty()) {
|
||||
OS << '[';
|
||||
OS << Node->getOutputName(i);
|
||||
OS << "] ";
|
||||
}
|
||||
|
||||
VisitStringLiteral(Node->getOutputConstraint(i));
|
||||
OS << " ";
|
||||
Visit(Node->getOutputExpr(i));
|
||||
}
|
||||
|
||||
// Inputs
|
||||
if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0)
|
||||
OS << " : ";
|
||||
|
||||
for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) {
|
||||
if (i != 0)
|
||||
OS << ", ";
|
||||
|
||||
if (!Node->getInputName(i).empty()) {
|
||||
OS << '[';
|
||||
OS << Node->getInputName(i);
|
||||
OS << "] ";
|
||||
}
|
||||
|
||||
VisitStringLiteral(Node->getInputConstraint(i));
|
||||
OS << " ";
|
||||
Visit(Node->getInputExpr(i));
|
||||
}
|
||||
|
||||
// Clobbers
|
||||
if (Node->getNumClobbers() != 0)
|
||||
OS << " : ";
|
||||
|
||||
for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) {
|
||||
if (i != 0)
|
||||
OS << ", ";
|
||||
|
||||
VisitStringLiteral(Node->getClobber(i));
|
||||
}
|
||||
|
||||
OS << ");\n";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
|
||||
Indent() << "@try";
|
||||
if (CompoundStmt *TS = dyn_cast<CompoundStmt>(Node->getTryBody())) {
|
||||
PrintRawCompoundStmt(TS);
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
for (ObjCAtCatchStmt *catchStmt =
|
||||
static_cast<ObjCAtCatchStmt *>(Node->getCatchStmts());
|
||||
catchStmt;
|
||||
catchStmt =
|
||||
static_cast<ObjCAtCatchStmt *>(catchStmt->getNextCatchStmt())) {
|
||||
Indent() << "@catch(";
|
||||
if (catchStmt->getCatchParamStmt()) {
|
||||
if (DeclStmt *DS = dyn_cast<DeclStmt>(catchStmt->getCatchParamStmt()))
|
||||
PrintRawDecl(DS->getDecl());
|
||||
}
|
||||
OS << ")";
|
||||
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(catchStmt->getCatchBody()))
|
||||
{
|
||||
PrintRawCompoundStmt(CS);
|
||||
OS << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (ObjCAtFinallyStmt *FS =static_cast<ObjCAtFinallyStmt *>(
|
||||
Node->getFinallyStmt())) {
|
||||
Indent() << "@finally";
|
||||
PrintRawCompoundStmt(dyn_cast<CompoundStmt>(FS->getFinallyBody()));
|
||||
OS << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Node) {
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitObjCAtCatchStmt (ObjCAtCatchStmt *Node) {
|
||||
Indent() << "@catch (...) { /* todo */ } \n";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitObjCAtThrowStmt (ObjCAtThrowStmt *Node) {
|
||||
Indent() << "@throw";
|
||||
if (Node->getThrowExpr()) {
|
||||
OS << " ";
|
||||
PrintExpr(Node->getThrowExpr());
|
||||
}
|
||||
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::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
|
||||
if (Node->getBase()) {
|
||||
PrintExpr(Node->getBase());
|
||||
OS << (Node->isArrow() ? "->" : ".");
|
||||
}
|
||||
OS << Node->getDecl()->getName();
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitPreDefinedExpr(PreDefinedExpr *Node) {
|
||||
switch (Node->getIdentType()) {
|
||||
default:
|
||||
assert(0 && "unknown case");
|
||||
case PreDefinedExpr::Func:
|
||||
OS << "__func__";
|
||||
break;
|
||||
case PreDefinedExpr::Function:
|
||||
OS << "__FUNCTION__";
|
||||
break;
|
||||
case PreDefinedExpr::PrettyFunction:
|
||||
OS << "__PRETTY_FUNCTION__";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
|
||||
// FIXME should print an L for wchar_t constants
|
||||
unsigned value = Node->getValue();
|
||||
switch (value) {
|
||||
case '\\':
|
||||
OS << "'\\\\'";
|
||||
break;
|
||||
case '\'':
|
||||
OS << "'\\''";
|
||||
break;
|
||||
case '\a':
|
||||
// TODO: K&R: the meaning of '\\a' is different in traditional C
|
||||
OS << "'\\a'";
|
||||
break;
|
||||
case '\b':
|
||||
OS << "'\\b'";
|
||||
break;
|
||||
// Nonstandard escape sequence.
|
||||
/*case '\e':
|
||||
OS << "'\\e'";
|
||||
break;*/
|
||||
case '\f':
|
||||
OS << "'\\f'";
|
||||
break;
|
||||
case '\n':
|
||||
OS << "'\\n'";
|
||||
break;
|
||||
case '\r':
|
||||
OS << "'\\r'";
|
||||
break;
|
||||
case '\t':
|
||||
OS << "'\\t'";
|
||||
break;
|
||||
case '\v':
|
||||
OS << "'\\v'";
|
||||
break;
|
||||
default:
|
||||
if (isprint(value) && value < 256) {
|
||||
OS << "'" << (char)value << "'";
|
||||
} else if (value < 256) {
|
||||
OS << "'\\x" << std::hex << value << std::dec << "'";
|
||||
} else {
|
||||
// FIXME what to really do here?
|
||||
OS << value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
|
||||
bool isSigned = Node->getType()->isSignedIntegerType();
|
||||
OS << Node->getValue().toString(10, isSigned);
|
||||
|
||||
// Emit suffixes. Integer literals are always a builtin integer type.
|
||||
switch (cast<BuiltinType>(Node->getType().getCanonicalType())->getKind()) {
|
||||
default: assert(0 && "Unexpected type for integer literal!");
|
||||
case BuiltinType::Int: break; // no suffix.
|
||||
case BuiltinType::UInt: OS << 'U'; break;
|
||||
case BuiltinType::Long: OS << 'L'; break;
|
||||
case BuiltinType::ULong: OS << "UL"; break;
|
||||
case BuiltinType::LongLong: OS << "LL"; break;
|
||||
case BuiltinType::ULongLong: OS << "ULL"; break;
|
||||
}
|
||||
}
|
||||
void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) {
|
||||
// FIXME: print value more precisely.
|
||||
OS << Node->getValueAsDouble();
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) {
|
||||
PrintExpr(Node->getSubExpr());
|
||||
OS << "i";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitStringLiteral(StringLiteral *Str) {
|
||||
if (Str->isWide()) OS << 'L';
|
||||
OS << '"';
|
||||
|
||||
// FIXME: this doesn't print wstrings right.
|
||||
for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) {
|
||||
switch (Str->getStrData()[i]) {
|
||||
default: OS << Str->getStrData()[i]; break;
|
||||
// Handle some common ones to make dumps prettier.
|
||||
case '\\': OS << "\\\\"; break;
|
||||
case '"': OS << "\\\""; break;
|
||||
case '\n': OS << "\\n"; break;
|
||||
case '\t': OS << "\\t"; break;
|
||||
case '\a': OS << "\\a"; break;
|
||||
case '\b': OS << "\\b"; break;
|
||||
}
|
||||
}
|
||||
OS << '"';
|
||||
}
|
||||
void StmtPrinter::VisitParenExpr(ParenExpr *Node) {
|
||||
OS << "(";
|
||||
PrintExpr(Node->getSubExpr());
|
||||
OS << ")";
|
||||
}
|
||||
void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) {
|
||||
if (!Node->isPostfix()) {
|
||||
OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
|
||||
|
||||
// Print a space if this is an "identifier operator" like sizeof or __real.
|
||||
switch (Node->getOpcode()) {
|
||||
default: break;
|
||||
case UnaryOperator::SizeOf:
|
||||
case UnaryOperator::AlignOf:
|
||||
case UnaryOperator::Real:
|
||||
case UnaryOperator::Imag:
|
||||
case UnaryOperator::Extension:
|
||||
OS << ' ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
PrintExpr(Node->getSubExpr());
|
||||
|
||||
if (Node->isPostfix())
|
||||
OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
|
||||
}
|
||||
|
||||
bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) {
|
||||
if (isa<CompoundLiteralExpr>(E)) {
|
||||
// Base case, print the type and comma.
|
||||
OS << E->getType().getAsString() << ", ";
|
||||
return true;
|
||||
} else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
|
||||
PrintOffsetOfDesignator(ASE->getLHS());
|
||||
OS << "[";
|
||||
PrintExpr(ASE->getRHS());
|
||||
OS << "]";
|
||||
return false;
|
||||
} else {
|
||||
MemberExpr *ME = cast<MemberExpr>(E);
|
||||
bool IsFirst = PrintOffsetOfDesignator(ME->getBase());
|
||||
OS << (IsFirst ? "" : ".") << ME->getMemberDecl()->getName();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) {
|
||||
OS << "__builtin_offsetof(";
|
||||
PrintOffsetOfDesignator(Node->getSubExpr());
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) {
|
||||
OS << (Node->isSizeOf() ? "sizeof(" : "__alignof(");
|
||||
OS << Node->getArgumentType().getAsString() << ")";
|
||||
}
|
||||
void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
|
||||
PrintExpr(Node->getLHS());
|
||||
OS << "[";
|
||||
PrintExpr(Node->getRHS());
|
||||
OS << "]";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCallExpr(CallExpr *Call) {
|
||||
PrintExpr(Call->getCallee());
|
||||
OS << "(";
|
||||
for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) {
|
||||
if (i) OS << ", ";
|
||||
PrintExpr(Call->getArg(i));
|
||||
}
|
||||
OS << ")";
|
||||
}
|
||||
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
|
||||
PrintExpr(Node->getBase());
|
||||
OS << (Node->isArrow() ? "->" : ".");
|
||||
|
||||
FieldDecl *Field = Node->getMemberDecl();
|
||||
assert(Field && "MemberExpr should alway reference a field!");
|
||||
OS << Field->getName();
|
||||
}
|
||||
void StmtPrinter::VisitOCUVectorElementExpr(OCUVectorElementExpr *Node) {
|
||||
PrintExpr(Node->getBase());
|
||||
OS << ".";
|
||||
OS << Node->getAccessor().getName();
|
||||
}
|
||||
void StmtPrinter::VisitCastExpr(CastExpr *Node) {
|
||||
OS << "(" << Node->getType().getAsString() << ")";
|
||||
PrintExpr(Node->getSubExpr());
|
||||
}
|
||||
void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) {
|
||||
OS << "(" << Node->getType().getAsString() << ")";
|
||||
PrintExpr(Node->getInitializer());
|
||||
}
|
||||
void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
|
||||
// No need to print anything, simply forward to the sub expression.
|
||||
PrintExpr(Node->getSubExpr());
|
||||
}
|
||||
void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) {
|
||||
PrintExpr(Node->getLHS());
|
||||
OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
|
||||
PrintExpr(Node->getRHS());
|
||||
}
|
||||
void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
|
||||
PrintExpr(Node->getLHS());
|
||||
OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
|
||||
PrintExpr(Node->getRHS());
|
||||
}
|
||||
void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) {
|
||||
PrintExpr(Node->getCond());
|
||||
|
||||
if (Node->getLHS()) {
|
||||
OS << " ? ";
|
||||
PrintExpr(Node->getLHS());
|
||||
OS << " : ";
|
||||
}
|
||||
else { // Handle GCC extention where LHS can be NULL.
|
||||
OS << " ?: ";
|
||||
}
|
||||
|
||||
PrintExpr(Node->getRHS());
|
||||
}
|
||||
|
||||
// GNU extensions.
|
||||
|
||||
void StmtPrinter::VisitAddrLabelExpr(AddrLabelExpr *Node) {
|
||||
OS << "&&" << Node->getLabel()->getName();
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitStmtExpr(StmtExpr *E) {
|
||||
OS << "(";
|
||||
PrintRawCompoundStmt(E->getSubStmt());
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
|
||||
OS << "__builtin_types_compatible_p(";
|
||||
OS << Node->getArgType1().getAsString() << ",";
|
||||
OS << Node->getArgType2().getAsString() << ")";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) {
|
||||
OS << "__builtin_choose_expr(";
|
||||
PrintExpr(Node->getCond());
|
||||
OS << ", ";
|
||||
PrintExpr(Node->getLHS());
|
||||
OS << ", ";
|
||||
PrintExpr(Node->getRHS());
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
|
||||
OS << "{ ";
|
||||
for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {
|
||||
if (i) OS << ", ";
|
||||
PrintExpr(Node->getInit(i));
|
||||
}
|
||||
OS << " }";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
|
||||
OS << "va_arg(";
|
||||
PrintExpr(Node->getSubExpr());
|
||||
OS << ", ";
|
||||
OS << Node->getType().getAsString();
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
// C++
|
||||
|
||||
void StmtPrinter::VisitCXXCastExpr(CXXCastExpr *Node) {
|
||||
OS << CXXCastExpr::getOpcodeStr(Node->getOpcode()) << '<';
|
||||
OS << Node->getDestType().getAsString() << ">(";
|
||||
PrintExpr(Node->getSubExpr());
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
|
||||
OS << (Node->getValue() ? "true" : "false");
|
||||
}
|
||||
|
||||
// Obj-C
|
||||
|
||||
void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
|
||||
OS << "@";
|
||||
VisitStringLiteral(Node->getString());
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
|
||||
OS << "@encode(" << Node->getEncodedType().getAsString() << ")";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
|
||||
OS << "@selector(" << Node->getSelector().getName() << ")";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
|
||||
OS << "@protocol(" << Node->getProtocol()->getName() << ")";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
|
||||
OS << "[";
|
||||
Expr *receiver = Mess->getReceiver();
|
||||
if (receiver) PrintExpr(receiver);
|
||||
else OS << Mess->getClassName()->getName();
|
||||
Selector &selector = Mess->getSelector();
|
||||
if (selector.isUnarySelector()) {
|
||||
OS << " " << selector.getIdentifierInfoForSlot(0)->getName();
|
||||
} else {
|
||||
for (unsigned i = 0, e = Mess->getNumArgs(); i != e; ++i) {
|
||||
if (selector.getIdentifierInfoForSlot(i))
|
||||
OS << selector.getIdentifierInfoForSlot(i)->getName() << ":";
|
||||
else
|
||||
OS << ":";
|
||||
PrintExpr(Mess->getArg(i));
|
||||
}
|
||||
}
|
||||
OS << "]";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Stmt method implementations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void Stmt::dumpPretty() const {
|
||||
printPretty(*llvm::cerr.stream());
|
||||
}
|
||||
|
||||
void Stmt::printPretty(std::ostream &OS, PrinterHelper* Helper) const {
|
||||
if (this == 0) {
|
||||
OS << "<NULL>";
|
||||
return;
|
||||
}
|
||||
|
||||
StmtPrinter P(OS, Helper);
|
||||
P.Visit(const_cast<Stmt*>(this));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// PrinterHelper
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Implement virtual destructor.
|
||||
PrinterHelper::~PrinterHelper() {}
|
||||
@@ -1,981 +0,0 @@
|
||||
//===--- StmtSerialization.cpp - Serialization of Statements --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the type-specific methods for serializing statements
|
||||
// and expressions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "llvm/Bitcode/Serialize.h"
|
||||
#include "llvm/Bitcode/Deserialize.h"
|
||||
|
||||
using namespace clang;
|
||||
using llvm::Serializer;
|
||||
using llvm::Deserializer;
|
||||
|
||||
void Stmt::Emit(Serializer& S) const {
|
||||
S.FlushRecord();
|
||||
S.EmitInt(getStmtClass());
|
||||
EmitImpl(S);
|
||||
S.FlushRecord();
|
||||
}
|
||||
|
||||
Stmt* Stmt::Create(Deserializer& D) {
|
||||
StmtClass SC = static_cast<StmtClass>(D.ReadInt());
|
||||
|
||||
switch (SC) {
|
||||
default:
|
||||
assert (false && "Not implemented.");
|
||||
return NULL;
|
||||
|
||||
case AddrLabelExprClass:
|
||||
return AddrLabelExpr::CreateImpl(D);
|
||||
|
||||
case ArraySubscriptExprClass:
|
||||
return ArraySubscriptExpr::CreateImpl(D);
|
||||
|
||||
case AsmStmtClass:
|
||||
return AsmStmt::CreateImpl(D);
|
||||
|
||||
case BinaryOperatorClass:
|
||||
return BinaryOperator::CreateImpl(D);
|
||||
|
||||
case BreakStmtClass:
|
||||
return BreakStmt::CreateImpl(D);
|
||||
|
||||
case CallExprClass:
|
||||
return CallExpr::CreateImpl(D);
|
||||
|
||||
case CaseStmtClass:
|
||||
return CaseStmt::CreateImpl(D);
|
||||
|
||||
case CastExprClass:
|
||||
return CastExpr::CreateImpl(D);
|
||||
|
||||
case CharacterLiteralClass:
|
||||
return CharacterLiteral::CreateImpl(D);
|
||||
|
||||
case CompoundAssignOperatorClass:
|
||||
return CompoundAssignOperator::CreateImpl(D);
|
||||
|
||||
case CompoundLiteralExprClass:
|
||||
return CompoundLiteralExpr::CreateImpl(D);
|
||||
|
||||
case CompoundStmtClass:
|
||||
return CompoundStmt::CreateImpl(D);
|
||||
|
||||
case ConditionalOperatorClass:
|
||||
return ConditionalOperator::CreateImpl(D);
|
||||
|
||||
case ContinueStmtClass:
|
||||
return ContinueStmt::CreateImpl(D);
|
||||
|
||||
case DeclRefExprClass:
|
||||
return DeclRefExpr::CreateImpl(D);
|
||||
|
||||
case DeclStmtClass:
|
||||
return DeclStmt::CreateImpl(D);
|
||||
|
||||
case DefaultStmtClass:
|
||||
return DefaultStmt::CreateImpl(D);
|
||||
|
||||
case DoStmtClass:
|
||||
return DoStmt::CreateImpl(D);
|
||||
|
||||
case FloatingLiteralClass:
|
||||
return FloatingLiteral::CreateImpl(D);
|
||||
|
||||
case ForStmtClass:
|
||||
return ForStmt::CreateImpl(D);
|
||||
|
||||
case GotoStmtClass:
|
||||
return GotoStmt::CreateImpl(D);
|
||||
|
||||
case IfStmtClass:
|
||||
return IfStmt::CreateImpl(D);
|
||||
|
||||
case ImaginaryLiteralClass:
|
||||
return ImaginaryLiteral::CreateImpl(D);
|
||||
|
||||
case ImplicitCastExprClass:
|
||||
return ImplicitCastExpr::CreateImpl(D);
|
||||
|
||||
case IndirectGotoStmtClass:
|
||||
return IndirectGotoStmt::CreateImpl(D);
|
||||
|
||||
case InitListExprClass:
|
||||
return InitListExpr::CreateImpl(D);
|
||||
|
||||
case IntegerLiteralClass:
|
||||
return IntegerLiteral::CreateImpl(D);
|
||||
|
||||
case LabelStmtClass:
|
||||
return LabelStmt::CreateImpl(D);
|
||||
|
||||
case MemberExprClass:
|
||||
return MemberExpr::CreateImpl(D);
|
||||
|
||||
case NullStmtClass:
|
||||
return NullStmt::CreateImpl(D);
|
||||
|
||||
case ParenExprClass:
|
||||
return ParenExpr::CreateImpl(D);
|
||||
|
||||
case PreDefinedExprClass:
|
||||
return PreDefinedExpr::CreateImpl(D);
|
||||
|
||||
case ReturnStmtClass:
|
||||
return ReturnStmt::CreateImpl(D);
|
||||
|
||||
case SizeOfAlignOfTypeExprClass:
|
||||
return SizeOfAlignOfTypeExpr::CreateImpl(D);
|
||||
|
||||
case StmtExprClass:
|
||||
return StmtExpr::CreateImpl(D);
|
||||
|
||||
case StringLiteralClass:
|
||||
return StringLiteral::CreateImpl(D);
|
||||
|
||||
case SwitchStmtClass:
|
||||
return SwitchStmt::CreateImpl(D);
|
||||
|
||||
case UnaryOperatorClass:
|
||||
return UnaryOperator::CreateImpl(D);
|
||||
|
||||
case WhileStmtClass:
|
||||
return WhileStmt::CreateImpl(D);
|
||||
|
||||
//==--------------------------------------==//
|
||||
// Objective C
|
||||
//==--------------------------------------==//
|
||||
|
||||
case ObjCAtCatchStmtClass:
|
||||
return ObjCAtCatchStmt::CreateImpl(D);
|
||||
|
||||
case ObjCAtFinallyStmtClass:
|
||||
return ObjCAtFinallyStmt::CreateImpl(D);
|
||||
|
||||
case ObjCAtThrowStmtClass:
|
||||
return ObjCAtThrowStmt::CreateImpl(D);
|
||||
|
||||
case ObjCAtTryStmtClass:
|
||||
return ObjCAtTryStmt::CreateImpl(D);
|
||||
|
||||
case ObjCEncodeExprClass:
|
||||
return ObjCEncodeExpr::CreateImpl(D);
|
||||
|
||||
case ObjCForCollectionStmtClass:
|
||||
return ObjCForCollectionStmt::CreateImpl(D);
|
||||
|
||||
case ObjCIvarRefExprClass:
|
||||
return ObjCIvarRefExpr::CreateImpl(D);
|
||||
|
||||
case ObjCSelectorExprClass:
|
||||
return ObjCSelectorExpr::CreateImpl(D);
|
||||
|
||||
case ObjCStringLiteralClass:
|
||||
return ObjCStringLiteral::CreateImpl(D);
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// C Serialization
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void AddrLabelExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.Emit(AmpAmpLoc);
|
||||
S.Emit(LabelLoc);
|
||||
S.EmitPtr(Label);
|
||||
}
|
||||
|
||||
AddrLabelExpr* AddrLabelExpr::CreateImpl(Deserializer& D) {
|
||||
QualType t = QualType::ReadVal(D);
|
||||
SourceLocation AALoc = SourceLocation::ReadVal(D);
|
||||
SourceLocation LLoc = SourceLocation::ReadVal(D);
|
||||
AddrLabelExpr* expr = new AddrLabelExpr(AALoc,LLoc,NULL,t);
|
||||
D.ReadPtr(expr->Label); // Pointer may be backpatched.
|
||||
return expr;
|
||||
}
|
||||
|
||||
void ArraySubscriptExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.Emit(RBracketLoc);
|
||||
S.BatchEmitOwnedPtrs(getLHS(),getRHS());
|
||||
}
|
||||
|
||||
ArraySubscriptExpr* ArraySubscriptExpr::CreateImpl(Deserializer& D) {
|
||||
QualType t = QualType::ReadVal(D);
|
||||
SourceLocation L = SourceLocation::ReadVal(D);
|
||||
Expr *LHS, *RHS;
|
||||
D.BatchReadOwnedPtrs(LHS,RHS);
|
||||
return new ArraySubscriptExpr(LHS,RHS,t,L);
|
||||
}
|
||||
|
||||
void AsmStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(AsmLoc);
|
||||
|
||||
getAsmString()->EmitImpl(S);
|
||||
S.Emit(RParenLoc);
|
||||
|
||||
S.EmitBool(IsVolatile);
|
||||
S.EmitInt(NumOutputs);
|
||||
S.EmitInt(NumInputs);
|
||||
|
||||
unsigned size = NumOutputs + NumInputs;
|
||||
|
||||
for (unsigned i = 0; i < size; ++i)
|
||||
S.EmitCStr(Names[i].c_str());
|
||||
|
||||
for (unsigned i = 0; i < size; ++i)
|
||||
Constraints[i]->EmitImpl(S);
|
||||
|
||||
for (unsigned i = 0; i < size; ++i)
|
||||
S.EmitOwnedPtr(Exprs[i]);
|
||||
|
||||
S.EmitInt(Clobbers.size());
|
||||
for (unsigned i = 0, e = Clobbers.size(); i != e; ++i)
|
||||
Clobbers[i]->EmitImpl(S);
|
||||
}
|
||||
|
||||
AsmStmt* AsmStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation ALoc = SourceLocation::ReadVal(D);
|
||||
StringLiteral *AsmStr = StringLiteral::CreateImpl(D);
|
||||
SourceLocation PLoc = SourceLocation::ReadVal(D);
|
||||
|
||||
bool IsVolatile = D.ReadBool();
|
||||
AsmStmt *Stmt = new AsmStmt(ALoc, IsVolatile, 0, 0, 0, 0, 0,
|
||||
AsmStr,
|
||||
0, 0, PLoc);
|
||||
|
||||
Stmt->NumOutputs = D.ReadInt();
|
||||
Stmt->NumInputs = D.ReadInt();
|
||||
|
||||
unsigned size = Stmt->NumOutputs + Stmt->NumInputs;
|
||||
|
||||
Stmt->Names.reserve(size);
|
||||
for (unsigned i = 0; i < size; ++i) {
|
||||
std::vector<char> data;
|
||||
D.ReadCStr(data, false);
|
||||
|
||||
Stmt->Names.push_back(std::string(&data[0], data.size()));
|
||||
}
|
||||
|
||||
Stmt->Constraints.reserve(size);
|
||||
for (unsigned i = 0; i < size; ++i)
|
||||
Stmt->Constraints.push_back(StringLiteral::CreateImpl(D));
|
||||
|
||||
Stmt->Exprs.reserve(size);
|
||||
for (unsigned i = 0; i < size; ++i)
|
||||
Stmt->Exprs.push_back(D.ReadOwnedPtr<Expr>());
|
||||
|
||||
unsigned NumClobbers = D.ReadInt();
|
||||
Stmt->Clobbers.reserve(NumClobbers);
|
||||
for (unsigned i = 0; i < NumClobbers; ++i)
|
||||
Stmt->Clobbers.push_back(StringLiteral::CreateImpl(D));
|
||||
|
||||
return Stmt;
|
||||
}
|
||||
|
||||
void BinaryOperator::EmitImpl(Serializer& S) const {
|
||||
S.EmitInt(Opc);
|
||||
S.Emit(OpLoc);;
|
||||
S.Emit(getType());
|
||||
S.BatchEmitOwnedPtrs(getLHS(),getRHS());
|
||||
}
|
||||
|
||||
BinaryOperator* BinaryOperator::CreateImpl(Deserializer& D) {
|
||||
Opcode Opc = static_cast<Opcode>(D.ReadInt());
|
||||
SourceLocation OpLoc = SourceLocation::ReadVal(D);
|
||||
QualType Result = QualType::ReadVal(D);
|
||||
Expr *LHS, *RHS;
|
||||
D.BatchReadOwnedPtrs(LHS,RHS);
|
||||
|
||||
return new BinaryOperator(LHS,RHS,Opc,Result,OpLoc);
|
||||
}
|
||||
|
||||
void BreakStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(BreakLoc);
|
||||
}
|
||||
|
||||
BreakStmt* BreakStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation Loc = SourceLocation::ReadVal(D);
|
||||
return new BreakStmt(Loc);
|
||||
}
|
||||
|
||||
void CallExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.Emit(RParenLoc);
|
||||
S.EmitInt(NumArgs);
|
||||
S.BatchEmitOwnedPtrs(NumArgs+1,SubExprs);
|
||||
}
|
||||
|
||||
CallExpr* CallExpr::CreateImpl(Deserializer& D) {
|
||||
QualType t = QualType::ReadVal(D);
|
||||
SourceLocation L = SourceLocation::ReadVal(D);
|
||||
unsigned NumArgs = D.ReadInt();
|
||||
Expr** SubExprs = new Expr*[NumArgs+1];
|
||||
D.BatchReadOwnedPtrs(NumArgs+1,SubExprs);
|
||||
|
||||
return new CallExpr(SubExprs,NumArgs,t,L);
|
||||
}
|
||||
|
||||
void CaseStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(CaseLoc);
|
||||
S.EmitPtr(getNextSwitchCase());
|
||||
S.BatchEmitOwnedPtrs((unsigned) END_EXPR,&SubExprs[0]);
|
||||
}
|
||||
|
||||
CaseStmt* CaseStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation CaseLoc = SourceLocation::ReadVal(D);
|
||||
CaseStmt* stmt = new CaseStmt(NULL,NULL,NULL,CaseLoc);
|
||||
D.ReadPtr(stmt->NextSwitchCase);
|
||||
D.BatchReadOwnedPtrs((unsigned) END_EXPR,&stmt->SubExprs[0]);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
void CastExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.Emit(Loc);
|
||||
S.EmitOwnedPtr(Op);
|
||||
}
|
||||
|
||||
CastExpr* CastExpr::CreateImpl(Deserializer& D) {
|
||||
QualType t = QualType::ReadVal(D);
|
||||
SourceLocation Loc = SourceLocation::ReadVal(D);
|
||||
Expr* Op = D.ReadOwnedPtr<Expr>();
|
||||
return new CastExpr(t,Op,Loc);
|
||||
}
|
||||
|
||||
|
||||
void CharacterLiteral::EmitImpl(Serializer& S) const {
|
||||
S.Emit(Value);
|
||||
S.Emit(Loc);
|
||||
S.Emit(getType());
|
||||
}
|
||||
|
||||
CharacterLiteral* CharacterLiteral::CreateImpl(Deserializer& D) {
|
||||
unsigned value = D.ReadInt();
|
||||
SourceLocation Loc = SourceLocation::ReadVal(D);
|
||||
QualType T = QualType::ReadVal(D);
|
||||
return new CharacterLiteral(value,T,Loc);
|
||||
}
|
||||
|
||||
void CompoundAssignOperator::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.Emit(ComputationType);
|
||||
S.Emit(getOperatorLoc());
|
||||
S.EmitInt(getOpcode());
|
||||
S.BatchEmitOwnedPtrs(getLHS(),getRHS());
|
||||
}
|
||||
|
||||
CompoundAssignOperator*
|
||||
CompoundAssignOperator::CreateImpl(Deserializer& D) {
|
||||
QualType t = QualType::ReadVal(D);
|
||||
QualType c = QualType::ReadVal(D);
|
||||
SourceLocation L = SourceLocation::ReadVal(D);
|
||||
Opcode Opc = static_cast<Opcode>(D.ReadInt());
|
||||
Expr* LHS, *RHS;
|
||||
D.BatchReadOwnedPtrs(LHS,RHS);
|
||||
|
||||
return new CompoundAssignOperator(LHS,RHS,Opc,t,c,L);
|
||||
}
|
||||
|
||||
void CompoundLiteralExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.Emit(getLParenLoc());
|
||||
S.EmitBool(isFileScope());
|
||||
S.EmitOwnedPtr(Init);
|
||||
}
|
||||
|
||||
CompoundLiteralExpr* CompoundLiteralExpr::CreateImpl(Deserializer& D) {
|
||||
QualType Q = QualType::ReadVal(D);
|
||||
SourceLocation L = SourceLocation::ReadVal(D);
|
||||
bool fileScope = D.ReadBool();
|
||||
Expr* Init = D.ReadOwnedPtr<Expr>();
|
||||
return new CompoundLiteralExpr(L, Q, Init, fileScope);
|
||||
}
|
||||
|
||||
void CompoundStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(LBracLoc);
|
||||
S.Emit(RBracLoc);
|
||||
S.Emit(Body.size());
|
||||
|
||||
for (const_body_iterator I=body_begin(), E=body_end(); I!=E; ++I)
|
||||
S.EmitOwnedPtr(*I);
|
||||
}
|
||||
|
||||
CompoundStmt* CompoundStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation LB = SourceLocation::ReadVal(D);
|
||||
SourceLocation RB = SourceLocation::ReadVal(D);
|
||||
unsigned size = D.ReadInt();
|
||||
|
||||
CompoundStmt* stmt = new CompoundStmt(NULL,0,LB,RB);
|
||||
|
||||
stmt->Body.reserve(size);
|
||||
|
||||
for (unsigned i = 0; i < size; ++i)
|
||||
stmt->Body.push_back(D.ReadOwnedPtr<Stmt>());
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
void ConditionalOperator::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.BatchEmitOwnedPtrs((unsigned) END_EXPR, SubExprs);
|
||||
}
|
||||
|
||||
ConditionalOperator* ConditionalOperator::CreateImpl(Deserializer& D) {
|
||||
QualType t = QualType::ReadVal(D);
|
||||
ConditionalOperator* c = new ConditionalOperator(NULL,NULL,NULL,t);
|
||||
D.BatchReadOwnedPtrs((unsigned) END_EXPR, c->SubExprs);
|
||||
return c;
|
||||
}
|
||||
|
||||
void ContinueStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(ContinueLoc);
|
||||
}
|
||||
|
||||
ContinueStmt* ContinueStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation Loc = SourceLocation::ReadVal(D);
|
||||
return new ContinueStmt(Loc);
|
||||
}
|
||||
|
||||
void DeclStmt::EmitImpl(Serializer& S) const {
|
||||
// FIXME: special handling for struct decls.
|
||||
S.EmitOwnedPtr(getDecl());
|
||||
}
|
||||
|
||||
void DeclRefExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(Loc);
|
||||
S.Emit(getType());
|
||||
|
||||
// Some DeclRefExprs can actually hold the owning reference to a FunctionDecl.
|
||||
// This occurs when an implicitly defined function is called, and
|
||||
// the decl does not appear in the source file. We thus check if the
|
||||
// decl pointer has been registered, and if not, emit an owned pointer.
|
||||
|
||||
// FIXME: While this will work for serialization, it won't work for
|
||||
// memory management. The only reason this works for serialization is
|
||||
// because we are tracking all serialized pointers. Either DeclRefExpr
|
||||
// needs an explicit bit indicating that it owns the the object,
|
||||
// or we need a different ownership model.
|
||||
|
||||
const Decl* d = getDecl();
|
||||
|
||||
if (!S.isRegistered(d)) {
|
||||
assert (isa<FunctionDecl>(d)
|
||||
&& "DeclRefExpr can only own FunctionDecls for implicitly def. funcs.");
|
||||
|
||||
S.EmitBool(true);
|
||||
S.EmitOwnedPtr(d);
|
||||
}
|
||||
else {
|
||||
S.EmitBool(false);
|
||||
S.EmitPtr(d);
|
||||
}
|
||||
}
|
||||
|
||||
DeclRefExpr* DeclRefExpr::CreateImpl(Deserializer& D) {
|
||||
SourceLocation Loc = SourceLocation::ReadVal(D);
|
||||
QualType T = QualType::ReadVal(D);
|
||||
bool OwnsDecl = D.ReadBool();
|
||||
ValueDecl* decl;
|
||||
|
||||
if (!OwnsDecl)
|
||||
D.ReadPtr(decl,false); // No backpatching.
|
||||
else
|
||||
decl = cast<ValueDecl>(D.ReadOwnedPtr<Decl>());
|
||||
|
||||
return new DeclRefExpr(decl,T,Loc);
|
||||
}
|
||||
|
||||
|
||||
DeclStmt* DeclStmt::CreateImpl(Deserializer& D) {
|
||||
ScopedDecl* decl = cast<ScopedDecl>(D.ReadOwnedPtr<Decl>());
|
||||
return new DeclStmt(decl);
|
||||
}
|
||||
|
||||
void DefaultStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(DefaultLoc);
|
||||
S.EmitOwnedPtr(getSubStmt());
|
||||
S.EmitPtr(getNextSwitchCase());
|
||||
}
|
||||
|
||||
DefaultStmt* DefaultStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation Loc = SourceLocation::ReadVal(D);
|
||||
Stmt* SubStmt = D.ReadOwnedPtr<Stmt>();
|
||||
|
||||
DefaultStmt* stmt = new DefaultStmt(Loc,SubStmt);
|
||||
stmt->setNextSwitchCase(D.ReadPtr<SwitchCase>());
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
void DoStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(DoLoc);
|
||||
S.EmitOwnedPtr(getCond());
|
||||
S.EmitOwnedPtr(getBody());
|
||||
}
|
||||
|
||||
DoStmt* DoStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation DoLoc = SourceLocation::ReadVal(D);
|
||||
Expr* Cond = D.ReadOwnedPtr<Expr>();
|
||||
Stmt* Body = D.ReadOwnedPtr<Stmt>();
|
||||
return new DoStmt(Body,Cond,DoLoc);
|
||||
}
|
||||
|
||||
void FloatingLiteral::EmitImpl(Serializer& S) const {
|
||||
S.Emit(Loc);
|
||||
S.Emit(getType());
|
||||
S.EmitBool(isExact());
|
||||
S.Emit(Value);
|
||||
}
|
||||
|
||||
FloatingLiteral* FloatingLiteral::CreateImpl(Deserializer& D) {
|
||||
SourceLocation Loc = SourceLocation::ReadVal(D);
|
||||
QualType t = QualType::ReadVal(D);
|
||||
bool isExact = D.ReadBool();
|
||||
llvm::APFloat Val = llvm::APFloat::ReadVal(D);
|
||||
FloatingLiteral* expr = new FloatingLiteral(Val,&isExact,t,Loc);
|
||||
return expr;
|
||||
}
|
||||
|
||||
void ForStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(ForLoc);
|
||||
S.EmitOwnedPtr(getInit());
|
||||
S.EmitOwnedPtr(getCond());
|
||||
S.EmitOwnedPtr(getInc());
|
||||
S.EmitOwnedPtr(getBody());
|
||||
}
|
||||
|
||||
ForStmt* ForStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation ForLoc = SourceLocation::ReadVal(D);
|
||||
Stmt* Init = D.ReadOwnedPtr<Stmt>();
|
||||
Expr* Cond = D.ReadOwnedPtr<Expr>();
|
||||
Expr* Inc = D.ReadOwnedPtr<Expr>();
|
||||
Stmt* Body = D.ReadOwnedPtr<Stmt>();
|
||||
return new ForStmt(Init,Cond,Inc,Body,ForLoc);
|
||||
}
|
||||
|
||||
void GotoStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(GotoLoc);
|
||||
S.Emit(LabelLoc);
|
||||
S.EmitPtr(Label);
|
||||
}
|
||||
|
||||
GotoStmt* GotoStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation GotoLoc = SourceLocation::ReadVal(D);
|
||||
SourceLocation LabelLoc = SourceLocation::ReadVal(D);
|
||||
GotoStmt* stmt = new GotoStmt(NULL,GotoLoc,LabelLoc);
|
||||
D.ReadPtr(stmt->Label); // This pointer may be backpatched later.
|
||||
return stmt;
|
||||
}
|
||||
|
||||
void IfStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(IfLoc);
|
||||
S.EmitOwnedPtr(getCond());
|
||||
S.EmitOwnedPtr(getThen());
|
||||
S.EmitOwnedPtr(getElse());
|
||||
}
|
||||
|
||||
IfStmt* IfStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation L = SourceLocation::ReadVal(D);
|
||||
Expr* Cond = D.ReadOwnedPtr<Expr>();
|
||||
Stmt* Then = D.ReadOwnedPtr<Stmt>();
|
||||
Stmt* Else = D.ReadOwnedPtr<Stmt>();
|
||||
return new IfStmt(L,Cond,Then,Else);
|
||||
}
|
||||
|
||||
void ImaginaryLiteral::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.EmitOwnedPtr(Val);
|
||||
}
|
||||
|
||||
ImaginaryLiteral* ImaginaryLiteral::CreateImpl(Deserializer& D) {
|
||||
QualType t = QualType::ReadVal(D);
|
||||
Expr* expr = D.ReadOwnedPtr<Expr>();
|
||||
assert (isa<FloatingLiteral>(expr) || isa<IntegerLiteral>(expr));
|
||||
return new ImaginaryLiteral(expr,t);
|
||||
}
|
||||
|
||||
void ImplicitCastExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.EmitOwnedPtr(Op);
|
||||
}
|
||||
|
||||
ImplicitCastExpr* ImplicitCastExpr::CreateImpl(Deserializer& D) {
|
||||
QualType t = QualType::ReadVal(D);
|
||||
Expr* Op = D.ReadOwnedPtr<Expr>();
|
||||
return new ImplicitCastExpr(t,Op);
|
||||
}
|
||||
|
||||
void IndirectGotoStmt::EmitImpl(Serializer& S) const {
|
||||
S.EmitOwnedPtr(Target);
|
||||
}
|
||||
|
||||
IndirectGotoStmt* IndirectGotoStmt::CreateImpl(Deserializer& D) {
|
||||
Expr* Target = D.ReadOwnedPtr<Expr>();
|
||||
return new IndirectGotoStmt(Target);
|
||||
}
|
||||
|
||||
void InitListExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(LBraceLoc);
|
||||
S.Emit(RBraceLoc);
|
||||
S.EmitInt(NumInits);
|
||||
S.BatchEmitOwnedPtrs(NumInits,InitExprs);
|
||||
}
|
||||
|
||||
InitListExpr* InitListExpr::CreateImpl(Deserializer& D) {
|
||||
InitListExpr* expr = new InitListExpr();
|
||||
expr->LBraceLoc = SourceLocation::ReadVal(D);
|
||||
expr->RBraceLoc = SourceLocation::ReadVal(D);
|
||||
expr->NumInits = D.ReadInt();
|
||||
assert(expr->NumInits);
|
||||
expr->InitExprs = new Expr*[expr->NumInits];
|
||||
D.BatchReadOwnedPtrs(expr->NumInits,expr->InitExprs);
|
||||
return expr;
|
||||
}
|
||||
|
||||
void IntegerLiteral::EmitImpl(Serializer& S) const {
|
||||
S.Emit(Loc);
|
||||
S.Emit(getType());
|
||||
S.Emit(getValue());
|
||||
}
|
||||
|
||||
IntegerLiteral* IntegerLiteral::CreateImpl(Deserializer& D) {
|
||||
SourceLocation Loc = SourceLocation::ReadVal(D);
|
||||
QualType T = QualType::ReadVal(D);
|
||||
|
||||
// Create a dummy APInt because it is more efficient to deserialize
|
||||
// it in place with the deserialized IntegerLiteral. (fewer copies)
|
||||
llvm::APInt temp;
|
||||
IntegerLiteral* expr = new IntegerLiteral(temp,T,Loc);
|
||||
D.Read(expr->Value);
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
void LabelStmt::EmitImpl(Serializer& S) const {
|
||||
S.EmitPtr(Label);
|
||||
S.Emit(IdentLoc);
|
||||
S.EmitOwnedPtr(SubStmt);
|
||||
}
|
||||
|
||||
LabelStmt* LabelStmt::CreateImpl(Deserializer& D) {
|
||||
IdentifierInfo* Label = D.ReadPtr<IdentifierInfo>();
|
||||
SourceLocation IdentLoc = SourceLocation::ReadVal(D);
|
||||
Stmt* SubStmt = D.ReadOwnedPtr<Stmt>();
|
||||
return new LabelStmt(IdentLoc,Label,SubStmt);
|
||||
}
|
||||
|
||||
void MemberExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(MemberLoc);
|
||||
S.EmitPtr(MemberDecl);
|
||||
S.EmitBool(IsArrow);
|
||||
S.EmitOwnedPtr(Base);
|
||||
}
|
||||
|
||||
MemberExpr* MemberExpr::CreateImpl(Deserializer& D) {
|
||||
SourceLocation L = SourceLocation::ReadVal(D);
|
||||
FieldDecl* MemberDecl = cast<FieldDecl>(D.ReadPtr<Decl>());
|
||||
bool IsArrow = D.ReadBool();
|
||||
Expr* base = D.ReadOwnedPtr<Expr>();
|
||||
|
||||
return new MemberExpr(base,IsArrow,MemberDecl,L);
|
||||
}
|
||||
|
||||
void NullStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(SemiLoc);
|
||||
}
|
||||
|
||||
NullStmt* NullStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation SemiLoc = SourceLocation::ReadVal(D);
|
||||
return new NullStmt(SemiLoc);
|
||||
}
|
||||
|
||||
void ParenExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(L);
|
||||
S.Emit(R);
|
||||
S.EmitOwnedPtr(Val);
|
||||
}
|
||||
|
||||
ParenExpr* ParenExpr::CreateImpl(Deserializer& D) {
|
||||
SourceLocation L = SourceLocation::ReadVal(D);
|
||||
SourceLocation R = SourceLocation::ReadVal(D);
|
||||
Expr* val = D.ReadOwnedPtr<Expr>();
|
||||
return new ParenExpr(L,R,val);
|
||||
}
|
||||
|
||||
void PreDefinedExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(Loc);
|
||||
S.EmitInt(getIdentType());
|
||||
S.Emit(getType());
|
||||
}
|
||||
|
||||
PreDefinedExpr* PreDefinedExpr::CreateImpl(Deserializer& D) {
|
||||
SourceLocation Loc = SourceLocation::ReadVal(D);
|
||||
IdentType it = static_cast<IdentType>(D.ReadInt());
|
||||
QualType Q = QualType::ReadVal(D);
|
||||
return new PreDefinedExpr(Loc,Q,it);
|
||||
}
|
||||
|
||||
void ReturnStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(RetLoc);
|
||||
S.EmitOwnedPtr(RetExpr);
|
||||
}
|
||||
|
||||
ReturnStmt* ReturnStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation RetLoc = SourceLocation::ReadVal(D);
|
||||
Expr* RetExpr = D.ReadOwnedPtr<Expr>();
|
||||
return new ReturnStmt(RetLoc,RetExpr);
|
||||
}
|
||||
|
||||
void SizeOfAlignOfTypeExpr::EmitImpl(Serializer& S) const {
|
||||
S.EmitBool(isSizeof);
|
||||
S.Emit(Ty);
|
||||
S.Emit(getType());
|
||||
S.Emit(OpLoc);
|
||||
S.Emit(RParenLoc);
|
||||
}
|
||||
|
||||
SizeOfAlignOfTypeExpr* SizeOfAlignOfTypeExpr::CreateImpl(Deserializer& D) {
|
||||
bool isSizeof = D.ReadBool();
|
||||
QualType Ty = QualType::ReadVal(D);
|
||||
QualType Res = QualType::ReadVal(D);
|
||||
SourceLocation OpLoc = SourceLocation::ReadVal(D);
|
||||
SourceLocation RParenLoc = SourceLocation::ReadVal(D);
|
||||
|
||||
return new SizeOfAlignOfTypeExpr(isSizeof,Ty,Res,OpLoc,RParenLoc);
|
||||
}
|
||||
|
||||
void StmtExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.Emit(LParenLoc);
|
||||
S.Emit(RParenLoc);
|
||||
S.EmitOwnedPtr(SubStmt);
|
||||
}
|
||||
|
||||
StmtExpr* StmtExpr::CreateImpl(Deserializer& D) {
|
||||
QualType t = QualType::ReadVal(D);
|
||||
SourceLocation L = SourceLocation::ReadVal(D);
|
||||
SourceLocation R = SourceLocation::ReadVal(D);
|
||||
CompoundStmt* SubStmt = cast<CompoundStmt>(D.ReadOwnedPtr<Stmt>());
|
||||
return new StmtExpr(SubStmt,t,L,R);
|
||||
}
|
||||
|
||||
void StringLiteral::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.Emit(firstTokLoc);
|
||||
S.Emit(lastTokLoc);
|
||||
S.EmitBool(isWide());
|
||||
S.Emit(getByteLength());
|
||||
|
||||
for (unsigned i = 0 ; i < ByteLength; ++i)
|
||||
S.EmitInt(StrData[i]);
|
||||
}
|
||||
|
||||
StringLiteral* StringLiteral::CreateImpl(Deserializer& D) {
|
||||
QualType t = QualType::ReadVal(D);
|
||||
SourceLocation firstTokLoc = SourceLocation::ReadVal(D);
|
||||
SourceLocation lastTokLoc = SourceLocation::ReadVal(D);
|
||||
bool isWide = D.ReadBool();
|
||||
unsigned ByteLength = D.ReadInt();
|
||||
|
||||
StringLiteral* sl = new StringLiteral(NULL,0,isWide,t,firstTokLoc,lastTokLoc);
|
||||
|
||||
char* StrData = new char[ByteLength];
|
||||
for (unsigned i = 0; i < ByteLength; ++i)
|
||||
StrData[i] = (char) D.ReadInt();
|
||||
|
||||
sl->ByteLength = ByteLength;
|
||||
sl->StrData = StrData;
|
||||
|
||||
return sl;
|
||||
}
|
||||
|
||||
void SwitchStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(SwitchLoc);
|
||||
S.EmitOwnedPtr(getCond());
|
||||
S.EmitOwnedPtr(getBody());
|
||||
S.EmitPtr(FirstCase);
|
||||
}
|
||||
|
||||
SwitchStmt* SwitchStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation Loc = SourceLocation::ReadVal(D);
|
||||
Stmt* Cond = D.ReadOwnedPtr<Stmt>();
|
||||
Stmt* Body = D.ReadOwnedPtr<Stmt>();
|
||||
SwitchCase* FirstCase = cast<SwitchCase>(D.ReadPtr<Stmt>());
|
||||
|
||||
SwitchStmt* stmt = new SwitchStmt(cast<Expr>(Cond));
|
||||
stmt->setBody(Body,Loc);
|
||||
stmt->FirstCase = FirstCase;
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
void UnaryOperator::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.Emit(Loc);
|
||||
S.EmitInt(Opc);
|
||||
S.EmitOwnedPtr(Val);
|
||||
}
|
||||
|
||||
UnaryOperator* UnaryOperator::CreateImpl(Deserializer& D) {
|
||||
QualType t = QualType::ReadVal(D);
|
||||
SourceLocation L = SourceLocation::ReadVal(D);
|
||||
Opcode Opc = static_cast<Opcode>(D.ReadInt());
|
||||
Expr* Val = D.ReadOwnedPtr<Expr>();
|
||||
return new UnaryOperator(Val,Opc,t,L);
|
||||
}
|
||||
|
||||
void WhileStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(WhileLoc);
|
||||
S.EmitOwnedPtr(getCond());
|
||||
S.EmitOwnedPtr(getBody());
|
||||
}
|
||||
|
||||
WhileStmt* WhileStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation WhileLoc = SourceLocation::ReadVal(D);
|
||||
Expr* Cond = D.ReadOwnedPtr<Expr>();
|
||||
Stmt* Body = D.ReadOwnedPtr<Stmt>();
|
||||
return new WhileStmt(Cond,Body,WhileLoc);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Objective C Serialization
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void ObjCAtCatchStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(AtCatchLoc);
|
||||
S.Emit(RParenLoc);
|
||||
S.EmitPtr(NextAtCatchStmt);
|
||||
S.BatchEmitOwnedPtrs((unsigned) END_EXPR,&SubExprs[0]);
|
||||
}
|
||||
|
||||
ObjCAtCatchStmt* ObjCAtCatchStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation AtCatchLoc = SourceLocation::ReadVal(D);
|
||||
SourceLocation RParenLoc = SourceLocation::ReadVal(D);
|
||||
|
||||
ObjCAtCatchStmt* stmt = new ObjCAtCatchStmt(AtCatchLoc,RParenLoc);
|
||||
|
||||
D.ReadPtr(stmt->NextAtCatchStmt); // Allows backpatching.
|
||||
D.BatchReadOwnedPtrs((unsigned) END_EXPR, &stmt->SubExprs[0]);
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
void ObjCAtFinallyStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(AtFinallyLoc);
|
||||
S.EmitOwnedPtr(AtFinallyStmt);
|
||||
}
|
||||
|
||||
ObjCAtFinallyStmt* ObjCAtFinallyStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation Loc = SourceLocation::ReadVal(D);
|
||||
Stmt* AtFinallyStmt = D.ReadOwnedPtr<Stmt>();
|
||||
return new ObjCAtFinallyStmt(Loc,AtFinallyStmt);
|
||||
}
|
||||
|
||||
void ObjCAtThrowStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(AtThrowLoc);
|
||||
S.EmitOwnedPtr(Throw);
|
||||
}
|
||||
|
||||
ObjCAtThrowStmt* ObjCAtThrowStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation L = SourceLocation::ReadVal(D);
|
||||
Stmt* Throw = D.ReadOwnedPtr<Stmt>();
|
||||
return new ObjCAtThrowStmt(L,Throw);
|
||||
}
|
||||
|
||||
void ObjCAtTryStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(AtTryLoc);
|
||||
S.BatchEmitOwnedPtrs((unsigned) END_EXPR, &SubStmts[0]);
|
||||
}
|
||||
|
||||
ObjCAtTryStmt* ObjCAtTryStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation L = SourceLocation::ReadVal(D);
|
||||
ObjCAtTryStmt* stmt = new ObjCAtTryStmt(L,NULL,NULL,NULL);
|
||||
D.BatchReadOwnedPtrs((unsigned) END_EXPR, &stmt->SubStmts[0]);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
void ObjCEncodeExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(AtLoc);
|
||||
S.Emit(RParenLoc);
|
||||
S.Emit(getType());
|
||||
S.Emit(EncType);
|
||||
}
|
||||
|
||||
ObjCEncodeExpr* ObjCEncodeExpr::CreateImpl(Deserializer& D) {
|
||||
SourceLocation AtLoc = SourceLocation::ReadVal(D);
|
||||
SourceLocation RParenLoc = SourceLocation::ReadVal(D);
|
||||
QualType T = QualType::ReadVal(D);
|
||||
QualType ET = QualType::ReadVal(D);
|
||||
return new ObjCEncodeExpr(T,ET,AtLoc,RParenLoc);
|
||||
}
|
||||
|
||||
void ObjCForCollectionStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(ForLoc);
|
||||
S.Emit(RParenLoc);
|
||||
S.BatchEmitOwnedPtrs(getElement(),getCollection(),getBody());
|
||||
}
|
||||
|
||||
ObjCForCollectionStmt* ObjCForCollectionStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation ForLoc = SourceLocation::ReadVal(D);
|
||||
SourceLocation RParenLoc = SourceLocation::ReadVal(D);
|
||||
Stmt* Element;
|
||||
Expr* Collection;
|
||||
Stmt* Body;
|
||||
D.BatchReadOwnedPtrs(Element,Collection,Body);
|
||||
return new ObjCForCollectionStmt(Element,Collection,Body,ForLoc, RParenLoc);
|
||||
}
|
||||
|
||||
void ObjCIvarRefExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(Loc);
|
||||
S.Emit(getType());
|
||||
S.EmitPtr(getDecl());
|
||||
}
|
||||
|
||||
ObjCIvarRefExpr* ObjCIvarRefExpr::CreateImpl(Deserializer& D) {
|
||||
SourceLocation Loc = SourceLocation::ReadVal(D);
|
||||
QualType T = QualType::ReadVal(D);
|
||||
ObjCIvarRefExpr* dr = new ObjCIvarRefExpr(NULL,T,Loc);
|
||||
D.ReadPtr(dr->D,false);
|
||||
return dr;
|
||||
}
|
||||
|
||||
void ObjCSelectorExpr::EmitImpl(Serializer& S) const {
|
||||
S.Emit(AtLoc);
|
||||
S.Emit(RParenLoc);
|
||||
S.Emit(getType());
|
||||
S.Emit(SelName);
|
||||
}
|
||||
|
||||
ObjCSelectorExpr* ObjCSelectorExpr::CreateImpl(Deserializer& D) {
|
||||
SourceLocation AtLoc = SourceLocation::ReadVal(D);
|
||||
SourceLocation RParenLoc = SourceLocation::ReadVal(D);
|
||||
QualType T = QualType::ReadVal(D);
|
||||
Selector SelName = Selector::ReadVal(D);
|
||||
|
||||
return new ObjCSelectorExpr(T,SelName,AtLoc,RParenLoc);
|
||||
}
|
||||
|
||||
void ObjCStringLiteral::EmitImpl(Serializer& S) const {
|
||||
S.Emit(AtLoc);
|
||||
S.Emit(getType());
|
||||
S.EmitOwnedPtr(String);
|
||||
}
|
||||
|
||||
ObjCStringLiteral* ObjCStringLiteral::CreateImpl(Deserializer& D) {
|
||||
SourceLocation L = SourceLocation::ReadVal(D);
|
||||
QualType T = QualType::ReadVal(D);
|
||||
StringLiteral* String = cast<StringLiteral>(D.ReadOwnedPtr<Stmt>());
|
||||
return new ObjCStringLiteral(String,T,L);
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
//===--- StmtViz.cpp - Graphviz visualization for Stmt ASTs -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements Stmt::viewAST, which generates a Graphviz DOT file
|
||||
// that depicts the AST and then calls Graphviz/dot+gv on it.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/StmtGraphTraits.h"
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include <sstream>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
void Stmt::viewAST() const {
|
||||
#ifndef NDEBUG
|
||||
llvm::ViewGraph(this,"AST");
|
||||
#else
|
||||
llvm::cerr << "Stmt::viewAST is only available in debug builds on "
|
||||
<< "systems with Graphviz or gv!\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
template<>
|
||||
struct DOTGraphTraits<const Stmt*> : public DefaultDOTGraphTraits {
|
||||
static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::ostringstream Out;
|
||||
|
||||
if (Node)
|
||||
Out << Node->getStmtClassName();
|
||||
else
|
||||
Out << "<NULL>";
|
||||
|
||||
std::string OutStr = Out.str();
|
||||
if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
|
||||
|
||||
// Process string output to make it nicer...
|
||||
for (unsigned i = 0; i != OutStr.length(); ++i)
|
||||
if (OutStr[i] == '\n') { // Left justify
|
||||
OutStr[i] = '\\';
|
||||
OutStr.insert(OutStr.begin()+i+1, 'l');
|
||||
}
|
||||
|
||||
return OutStr;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // end namespace llvm
|
||||
@@ -1,227 +0,0 @@
|
||||
//===--- TranslationUnit.cpp - Abstraction for Translation Units ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
// FIXME: This should eventually be moved out of the driver, or replaced
|
||||
// with its eventual successor.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/TranslationUnit.h"
|
||||
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/AST/AST.h"
|
||||
|
||||
#include "llvm/Bitcode/Serialize.h"
|
||||
#include "llvm/Bitcode/Deserialize.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
enum { BasicMetadataBlock = 1,
|
||||
ASTContextBlock = 2,
|
||||
DeclsBlock = 3 };
|
||||
|
||||
|
||||
bool clang::EmitASTBitcodeFile(const TranslationUnit& TU,
|
||||
const llvm::sys::Path& Filename) {
|
||||
|
||||
// Reserve 256K for bitstream buffer.
|
||||
std::vector<unsigned char> Buffer;
|
||||
Buffer.reserve(256*1024);
|
||||
|
||||
// Create bitstream.
|
||||
llvm::BitstreamWriter Stream(Buffer);
|
||||
|
||||
// Emit the preamble.
|
||||
Stream.Emit((unsigned)'B', 8);
|
||||
Stream.Emit((unsigned)'C', 8);
|
||||
Stream.Emit(0xC, 4);
|
||||
Stream.Emit(0xF, 4);
|
||||
Stream.Emit(0xE, 4);
|
||||
Stream.Emit(0x0, 4);
|
||||
|
||||
{
|
||||
// Create serializer. Placing it in its own scope assures any necessary
|
||||
// finalization of bits to the buffer in the serializer's dstor.
|
||||
llvm::Serializer Sezr(Stream);
|
||||
|
||||
// Emit the translation unit.
|
||||
TU.Emit(Sezr);
|
||||
}
|
||||
|
||||
// Write the bits to disk.
|
||||
if (FILE* fp = fopen(Filename.c_str(),"wb")) {
|
||||
fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp);
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TranslationUnit::Emit(llvm::Serializer& Sezr) const {
|
||||
|
||||
// ===---------------------------------------------------===/
|
||||
// Serialize the top-level decls.
|
||||
// ===---------------------------------------------------===/
|
||||
|
||||
Sezr.EnterBlock(DeclsBlock);
|
||||
|
||||
// Only serialize the head of a decl chain. The ASTConsumer interfaces
|
||||
// provides us with each top-level decl, including those nested in
|
||||
// a decl chain, so we may be passed decls that are already serialized.
|
||||
for (const_iterator I=begin(), E=end(); I!=E; ++I)
|
||||
if (!Sezr.isRegistered(*I))
|
||||
Sezr.EmitOwnedPtr(*I);
|
||||
|
||||
Sezr.ExitBlock();
|
||||
|
||||
// ===---------------------------------------------------===/
|
||||
// Serialize the "Translation Unit" metadata.
|
||||
// ===---------------------------------------------------===/
|
||||
|
||||
// Emit ASTContext.
|
||||
Sezr.EnterBlock(ASTContextBlock);
|
||||
Sezr.EmitOwnedPtr(Context);
|
||||
Sezr.ExitBlock();
|
||||
|
||||
Sezr.EnterBlock(BasicMetadataBlock);
|
||||
|
||||
// Block for SourceManager, LangOptions, and Target. Allows easy skipping
|
||||
// around to the block for the Selectors during deserialization.
|
||||
Sezr.EnterBlock();
|
||||
|
||||
// Emit the SourceManager.
|
||||
Sezr.Emit(Context->getSourceManager());
|
||||
|
||||
// Emit the LangOptions.
|
||||
Sezr.Emit(LangOpts);
|
||||
|
||||
// Emit the Target.
|
||||
Sezr.EmitPtr(&Context->Target);
|
||||
Sezr.EmitCStr(Context->Target.getTargetTriple());
|
||||
|
||||
Sezr.ExitBlock(); // exit "BasicMetadataBlock"
|
||||
|
||||
// Emit the Selectors.
|
||||
Sezr.Emit(Context->Selectors);
|
||||
|
||||
// Emit the Identifier Table.
|
||||
Sezr.Emit(Context->Idents);
|
||||
|
||||
Sezr.ExitBlock(); // exit "ASTContextBlock"
|
||||
}
|
||||
|
||||
TranslationUnit*
|
||||
clang::ReadASTBitcodeFile(const llvm::sys::Path& Filename, FileManager& FMgr) {
|
||||
|
||||
// Create the memory buffer that contains the contents of the file.
|
||||
llvm::OwningPtr<llvm::MemoryBuffer>
|
||||
MBuffer(llvm::MemoryBuffer::getFile(Filename.c_str(),
|
||||
strlen(Filename.c_str())));
|
||||
|
||||
if (!MBuffer) {
|
||||
// FIXME: Provide diagnostic.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check if the file is of the proper length.
|
||||
if (MBuffer->getBufferSize() & 0x3) {
|
||||
// FIXME: Provide diagnostic: "Length should be a multiple of 4 bytes."
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create the bitstream reader.
|
||||
unsigned char *BufPtr = (unsigned char *) MBuffer->getBufferStart();
|
||||
llvm::BitstreamReader Stream(BufPtr,BufPtr+MBuffer->getBufferSize());
|
||||
|
||||
if (Stream.Read(8) != 'B' ||
|
||||
Stream.Read(8) != 'C' ||
|
||||
Stream.Read(4) != 0xC ||
|
||||
Stream.Read(4) != 0xF ||
|
||||
Stream.Read(4) != 0xE ||
|
||||
Stream.Read(4) != 0x0) {
|
||||
// FIXME: Provide diagnostic.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create the deserializer.
|
||||
llvm::Deserializer Dezr(Stream);
|
||||
|
||||
return TranslationUnit::Create(Dezr,FMgr);
|
||||
}
|
||||
|
||||
TranslationUnit* TranslationUnit::Create(llvm::Deserializer& Dezr,
|
||||
FileManager& FMgr) {
|
||||
|
||||
// Create the translation unit object.
|
||||
TranslationUnit* TU = new TranslationUnit();
|
||||
|
||||
// ===---------------------------------------------------===/
|
||||
// Deserialize the "Translation Unit" metadata.
|
||||
// ===---------------------------------------------------===/
|
||||
|
||||
// Skip to the BasicMetaDataBlock. First jump to ASTContextBlock
|
||||
// (which will appear earlier) and record its location.
|
||||
|
||||
bool FoundBlock = Dezr.SkipToBlock(ASTContextBlock);
|
||||
assert (FoundBlock);
|
||||
|
||||
llvm::Deserializer::Location ASTContextBlockLoc =
|
||||
Dezr.getCurrentBlockLocation();
|
||||
|
||||
FoundBlock = Dezr.SkipToBlock(BasicMetadataBlock);
|
||||
assert (FoundBlock);
|
||||
|
||||
// Read the SourceManager.
|
||||
SourceManager::CreateAndRegister(Dezr,FMgr);
|
||||
|
||||
// Read the LangOptions.
|
||||
TU->LangOpts.Read(Dezr);
|
||||
|
||||
{ // Read the TargetInfo.
|
||||
llvm::SerializedPtrID PtrID = Dezr.ReadPtrID();
|
||||
char* triple = Dezr.ReadCStr(NULL,0,true);
|
||||
std::string Triple(triple);
|
||||
Dezr.RegisterPtr(PtrID,TargetInfo::CreateTargetInfo(&Triple,
|
||||
&Triple+1));
|
||||
delete [] triple;
|
||||
}
|
||||
|
||||
// For Selectors, we must read the identifier table first because the
|
||||
// SelectorTable depends on the identifiers being already deserialized.
|
||||
llvm::Deserializer::Location SelectorBlkLoc = Dezr.getCurrentBlockLocation();
|
||||
Dezr.SkipBlock();
|
||||
|
||||
// Read the identifier table.
|
||||
IdentifierTable::CreateAndRegister(Dezr);
|
||||
|
||||
// Now jump back and read the selectors.
|
||||
Dezr.JumpTo(SelectorBlkLoc);
|
||||
SelectorTable::CreateAndRegister(Dezr);
|
||||
|
||||
// Now jump back to ASTContextBlock and read the ASTContext.
|
||||
Dezr.JumpTo(ASTContextBlockLoc);
|
||||
TU->Context = Dezr.ReadOwnedPtr<ASTContext>();
|
||||
|
||||
// "Rewind" the stream. Find the block with the serialized top-level decls.
|
||||
Dezr.Rewind();
|
||||
FoundBlock = Dezr.SkipToBlock(DeclsBlock);
|
||||
assert (FoundBlock);
|
||||
llvm::Deserializer::Location DeclBlockLoc = Dezr.getCurrentBlockLocation();
|
||||
|
||||
while (!Dezr.FinishedBlock(DeclBlockLoc))
|
||||
TU->AddTopLevelDecl(Dezr.ReadOwnedPtr<Decl>());
|
||||
|
||||
return TU;
|
||||
}
|
||||
|
||||
@@ -1,850 +0,0 @@
|
||||
//===--- Type.cpp - Type representation and manipulation ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements type-related functionality.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include <sstream>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
Type::~Type() {}
|
||||
|
||||
/// isVoidType - Helper method to determine if this is the 'void' type.
|
||||
bool Type::isVoidType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() == BuiltinType::Void;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isObjectType() const {
|
||||
if (isa<FunctionType>(CanonicalType))
|
||||
return false;
|
||||
else if (CanonicalType->isIncompleteType())
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Type::isDerivedType() const {
|
||||
switch (CanonicalType->getTypeClass()) {
|
||||
case Pointer:
|
||||
case VariableArray:
|
||||
case ConstantArray:
|
||||
case FunctionProto:
|
||||
case FunctionNoProto:
|
||||
case Reference:
|
||||
return true;
|
||||
case Tagged: {
|
||||
const TagType *TT = cast<TagType>(CanonicalType);
|
||||
const Decl::Kind Kind = TT->getDecl()->getKind();
|
||||
return Kind == Decl::Struct || Kind == Decl::Union;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Type::isStructureType() const {
|
||||
if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType))
|
||||
if (RT->getDecl()->getKind() == Decl::Struct)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool Type::isUnionType() const {
|
||||
if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType))
|
||||
if (RT->getDecl()->getKind() == Decl::Union)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isComplexType() const {
|
||||
if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType))
|
||||
return CT->getElementType()->isFloatingType();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isComplexIntegerType() const {
|
||||
// Check for GCC complex integer extension.
|
||||
if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType))
|
||||
return CT->getElementType()->isIntegerType();
|
||||
return false;
|
||||
}
|
||||
|
||||
const ComplexType *Type::getAsComplexIntegerType() const {
|
||||
// Are we directly a complex type?
|
||||
if (const ComplexType *CTy = dyn_cast<ComplexType>(this)) {
|
||||
if (CTy->getElementType()->isIntegerType())
|
||||
return CTy;
|
||||
}
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
const ComplexType *CTy = dyn_cast<ComplexType>(CanonicalType);
|
||||
if (!CTy || !CTy->getElementType()->isIntegerType())
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for a complex type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
return getDesugaredType()->getAsComplexIntegerType();
|
||||
}
|
||||
|
||||
/// getDesugaredType - Return the specified type with any "sugar" removed from
|
||||
/// type type. This takes off typedefs, typeof's etc. If the outer level of
|
||||
/// the type is already concrete, it returns it unmodified. This is similar
|
||||
/// to getting the canonical type, but it doesn't remove *all* typedefs. For
|
||||
/// example, it return "T*" as "T*", (not as "int*"), because the pointer is
|
||||
/// concrete.
|
||||
const Type *Type::getDesugaredType() const {
|
||||
if (const TypedefType *TDT = dyn_cast<TypedefType>(this))
|
||||
return TDT->LookThroughTypedefs().getTypePtr();
|
||||
if (const TypeOfExpr *TOE = dyn_cast<TypeOfExpr>(this))
|
||||
return TOE->getUnderlyingExpr()->getType().getTypePtr();
|
||||
if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this))
|
||||
return TOT->getUnderlyingType().getTypePtr();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
const BuiltinType *Type::getAsBuiltinType() const {
|
||||
// If this is directly a builtin type, return it.
|
||||
if (const BuiltinType *BTy = dyn_cast<BuiltinType>(this))
|
||||
return BTy;
|
||||
|
||||
// If the canonical form of this type isn't a builtin type, reject it.
|
||||
if (!isa<BuiltinType>(CanonicalType))
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for a builtin type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
return getDesugaredType()->getAsBuiltinType();
|
||||
}
|
||||
|
||||
const FunctionType *Type::getAsFunctionType() const {
|
||||
// If this is directly a function type, return it.
|
||||
if (const FunctionType *FTy = dyn_cast<FunctionType>(this))
|
||||
return FTy;
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (!isa<FunctionType>(CanonicalType))
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for a function type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
return getDesugaredType()->getAsFunctionType();
|
||||
}
|
||||
|
||||
const PointerType *Type::getAsPointerType() const {
|
||||
// If this is directly a pointer type, return it.
|
||||
if (const PointerType *PTy = dyn_cast<PointerType>(this))
|
||||
return PTy;
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (!isa<PointerType>(CanonicalType))
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for a pointer type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
return getDesugaredType()->getAsPointerType();
|
||||
}
|
||||
|
||||
const ReferenceType *Type::getAsReferenceType() const {
|
||||
// If this is directly a reference type, return it.
|
||||
if (const ReferenceType *RTy = dyn_cast<ReferenceType>(this))
|
||||
return RTy;
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (!isa<ReferenceType>(CanonicalType))
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for a reference type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
return getDesugaredType()->getAsReferenceType();
|
||||
}
|
||||
|
||||
const ArrayType *Type::getAsArrayType() const {
|
||||
// If this is directly an array type, return it.
|
||||
if (const ArrayType *ATy = dyn_cast<ArrayType>(this))
|
||||
return ATy;
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (!isa<ArrayType>(CanonicalType))
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for an array type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
return getDesugaredType()->getAsArrayType();
|
||||
}
|
||||
|
||||
const ConstantArrayType *Type::getAsConstantArrayType() const {
|
||||
// If this is directly a constant array type, return it.
|
||||
if (const ConstantArrayType *ATy = dyn_cast<ConstantArrayType>(this))
|
||||
return ATy;
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (!isa<ConstantArrayType>(CanonicalType))
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for a constant array type, strip the typedef off
|
||||
// without losing all typedef information.
|
||||
return getDesugaredType()->getAsConstantArrayType();
|
||||
}
|
||||
|
||||
const VariableArrayType *Type::getAsVariableArrayType() const {
|
||||
// If this is directly a variable array type, return it.
|
||||
if (const VariableArrayType *ATy = dyn_cast<VariableArrayType>(this))
|
||||
return ATy;
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (!isa<VariableArrayType>(CanonicalType))
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for a variable array type, strip the typedef off
|
||||
// without losing all typedef information.
|
||||
return getDesugaredType()->getAsVariableArrayType();
|
||||
}
|
||||
|
||||
/// isVariablyModifiedType (C99 6.7.5.2p2) - Return true for variable array
|
||||
/// types that have a non-constant expression. This does not include "[]".
|
||||
bool Type::isVariablyModifiedType() const {
|
||||
if (const VariableArrayType *VAT = getAsVariableArrayType()) {
|
||||
if (VAT->getSizeExpr())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const VariableArrayType *Type::getAsVariablyModifiedType() const {
|
||||
if (const VariableArrayType *VAT = getAsVariableArrayType()) {
|
||||
if (VAT->getSizeExpr())
|
||||
return VAT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const RecordType *Type::getAsRecordType() const {
|
||||
// If this is directly a reference type, return it.
|
||||
if (const RecordType *RTy = dyn_cast<RecordType>(this))
|
||||
return RTy;
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (!isa<RecordType>(CanonicalType))
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for a record type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
return getDesugaredType()->getAsRecordType();
|
||||
}
|
||||
|
||||
const RecordType *Type::getAsStructureType() const {
|
||||
// If this is directly a structure type, return it.
|
||||
if (const RecordType *RT = dyn_cast<RecordType>(this)) {
|
||||
if (RT->getDecl()->getKind() == Decl::Struct)
|
||||
return RT;
|
||||
}
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) {
|
||||
if (RT->getDecl()->getKind() != Decl::Struct)
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for a structure type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
return getDesugaredType()->getAsStructureType();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const RecordType *Type::getAsUnionType() const {
|
||||
// If this is directly a union type, return it.
|
||||
if (const RecordType *RT = dyn_cast<RecordType>(this)) {
|
||||
if (RT->getDecl()->getKind() == Decl::Union)
|
||||
return RT;
|
||||
}
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) {
|
||||
if (RT->getDecl()->getKind() != Decl::Union)
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for a union type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
return getDesugaredType()->getAsUnionType();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ComplexType *Type::getAsComplexType() const {
|
||||
// Are we directly a complex type?
|
||||
if (const ComplexType *CTy = dyn_cast<ComplexType>(this))
|
||||
return CTy;
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (!isa<ComplexType>(CanonicalType))
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for a complex type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
return getDesugaredType()->getAsComplexType();
|
||||
}
|
||||
|
||||
const VectorType *Type::getAsVectorType() const {
|
||||
// Are we directly a vector type?
|
||||
if (const VectorType *VTy = dyn_cast<VectorType>(this))
|
||||
return VTy;
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (!isa<VectorType>(CanonicalType))
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for a vector type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
return getDesugaredType()->getAsVectorType();
|
||||
}
|
||||
|
||||
const OCUVectorType *Type::getAsOCUVectorType() const {
|
||||
// Are we directly an OpenCU vector type?
|
||||
if (const OCUVectorType *VTy = dyn_cast<OCUVectorType>(this))
|
||||
return VTy;
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (!isa<OCUVectorType>(CanonicalType))
|
||||
return 0;
|
||||
|
||||
// If this is a typedef for an ocuvector type, strip the typedef off without
|
||||
// losing all typedef information.
|
||||
return getDesugaredType()->getAsOCUVectorType();
|
||||
}
|
||||
|
||||
bool Type::isIntegerType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() >= BuiltinType::Bool &&
|
||||
BT->getKind() <= BuiltinType::LongLong;
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
|
||||
if (TT->getDecl()->getKind() == Decl::Enum)
|
||||
return true;
|
||||
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
|
||||
return VT->getElementType()->isIntegerType();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isIntegralType() 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::isEnumeralType() const {
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
|
||||
return TT->getDecl()->getKind() == Decl::Enum;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isBooleanType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() == BuiltinType::Bool;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isCharType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() == BuiltinType::Char_U ||
|
||||
BT->getKind() == BuiltinType::UChar ||
|
||||
BT->getKind() == BuiltinType::Char_S ||
|
||||
BT->getKind() == BuiltinType::SChar;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// isSignedIntegerType - Return true if this is an integer type that is
|
||||
/// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..],
|
||||
/// an enum decl which has a signed representation, or a vector of signed
|
||||
/// integer element type.
|
||||
bool Type::isSignedIntegerType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
|
||||
return BT->getKind() >= BuiltinType::Char_S &&
|
||||
BT->getKind() <= BuiltinType::LongLong;
|
||||
}
|
||||
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
|
||||
if (const EnumDecl *ED = dyn_cast<EnumDecl>(TT->getDecl()))
|
||||
return ED->getIntegerType()->isSignedIntegerType();
|
||||
|
||||
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
|
||||
return VT->getElementType()->isSignedIntegerType();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// isUnsignedIntegerType - Return true if this is an integer type that is
|
||||
/// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum
|
||||
/// decl which has an unsigned representation, or a vector of unsigned integer
|
||||
/// element type.
|
||||
bool Type::isUnsignedIntegerType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
|
||||
return BT->getKind() >= BuiltinType::Bool &&
|
||||
BT->getKind() <= BuiltinType::ULongLong;
|
||||
}
|
||||
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
|
||||
if (const EnumDecl *ED = dyn_cast<EnumDecl>(TT->getDecl()))
|
||||
return ED->getIntegerType()->isUnsignedIntegerType();
|
||||
|
||||
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
|
||||
return VT->getElementType()->isUnsignedIntegerType();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isFloatingType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() >= BuiltinType::Float &&
|
||||
BT->getKind() <= BuiltinType::LongDouble;
|
||||
if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType))
|
||||
return CT->getElementType()->isFloatingType();
|
||||
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
|
||||
return VT->getElementType()->isFloatingType();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isRealFloatingType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() >= BuiltinType::Float &&
|
||||
BT->getKind() <= BuiltinType::LongDouble;
|
||||
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
|
||||
return VT->getElementType()->isRealFloatingType();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isRealType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() >= BuiltinType::Bool &&
|
||||
BT->getKind() <= BuiltinType::LongDouble;
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
|
||||
return TT->getDecl()->getKind() == Decl::Enum;
|
||||
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
|
||||
return VT->getElementType()->isRealType();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isArithmeticType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() != BuiltinType::Void;
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
|
||||
if (const EnumDecl *ED = dyn_cast<EnumDecl>(TT->getDecl()))
|
||||
// GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2).
|
||||
// If a body isn't seen by the time we get here, return false.
|
||||
return ED->isDefinition();
|
||||
return isa<ComplexType>(CanonicalType) || isa<VectorType>(CanonicalType);
|
||||
}
|
||||
|
||||
bool Type::isScalarType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() != BuiltinType::Void;
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
|
||||
if (TT->getDecl()->getKind() == Decl::Enum)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return isa<PointerType>(CanonicalType) || isa<ComplexType>(CanonicalType) ||
|
||||
isa<VectorType>(CanonicalType) ||
|
||||
isa<ObjCQualifiedIdType>(CanonicalType);
|
||||
}
|
||||
|
||||
bool Type::isAggregateType() const {
|
||||
if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
|
||||
if (TT->getDecl()->getKind() == Decl::Struct)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return CanonicalType->getTypeClass() == ConstantArray ||
|
||||
CanonicalType->getTypeClass() == VariableArray;
|
||||
}
|
||||
|
||||
/// isConstantSizeType - Return true if this is not a variable sized type,
|
||||
/// according to the rules of C99 6.7.5p3. It is not legal to call this on
|
||||
/// incomplete types.
|
||||
bool Type::isConstantSizeType(ASTContext &Ctx) const {
|
||||
assert(!isIncompleteType() && "This doesn't make sense for incomplete types");
|
||||
// The VAT must have a size, as it is known to be complete.
|
||||
return !isa<VariableArrayType>(CanonicalType);
|
||||
}
|
||||
|
||||
/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1)
|
||||
/// - a type that can describe objects, but which lacks information needed to
|
||||
/// determine its size.
|
||||
bool Type::isIncompleteType() const {
|
||||
switch (CanonicalType->getTypeClass()) {
|
||||
default: return false;
|
||||
case Builtin:
|
||||
// Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never
|
||||
// be completed.
|
||||
return isVoidType();
|
||||
case Tagged:
|
||||
// A tagged type (struct/union/enum/class) is incomplete if the decl is a
|
||||
// forward declaration, but not a full definition (C99 6.2.5p22).
|
||||
return !cast<TagType>(CanonicalType)->getDecl()->isDefinition();
|
||||
case VariableArray:
|
||||
// An array of unknown size is an incomplete type (C99 6.2.5p22).
|
||||
return cast<VariableArrayType>(CanonicalType)->getSizeExpr() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Type::isPromotableIntegerType() const {
|
||||
const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType);
|
||||
if (!BT) return false;
|
||||
switch (BT->getKind()) {
|
||||
case BuiltinType::Bool:
|
||||
case BuiltinType::Char_S:
|
||||
case BuiltinType::Char_U:
|
||||
case BuiltinType::SChar:
|
||||
case BuiltinType::UChar:
|
||||
case BuiltinType::Short:
|
||||
case BuiltinType::UShort:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const char *BuiltinType::getName() const {
|
||||
switch (getKind()) {
|
||||
default: assert(0 && "Unknown builtin type!");
|
||||
case Void: return "void";
|
||||
case Bool: return "_Bool";
|
||||
case Char_S: return "char";
|
||||
case Char_U: return "char";
|
||||
case SChar: return "signed char";
|
||||
case Short: return "short";
|
||||
case Int: return "int";
|
||||
case Long: return "long";
|
||||
case LongLong: return "long long";
|
||||
case UChar: return "unsigned char";
|
||||
case UShort: return "unsigned short";
|
||||
case UInt: return "unsigned int";
|
||||
case ULong: return "unsigned long";
|
||||
case ULongLong: return "unsigned long long";
|
||||
case Float: return "float";
|
||||
case Double: return "double";
|
||||
case LongDouble: return "long double";
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
|
||||
arg_type_iterator ArgTys,
|
||||
unsigned NumArgs, bool isVariadic) {
|
||||
ID.AddPointer(Result.getAsOpaquePtr());
|
||||
for (unsigned i = 0; i != NumArgs; ++i)
|
||||
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
|
||||
ID.AddInteger(isVariadic);
|
||||
}
|
||||
|
||||
void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic());
|
||||
}
|
||||
|
||||
void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
ObjCProtocolDecl **protocols,
|
||||
unsigned NumProtocols) {
|
||||
for (unsigned i = 0; i != NumProtocols; i++)
|
||||
ID.AddPointer(protocols[i]);
|
||||
}
|
||||
|
||||
void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, &Protocols[0], getNumProtocols());
|
||||
}
|
||||
|
||||
void ObjCQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
ObjCProtocolDecl **protocols,
|
||||
unsigned NumProtocols) {
|
||||
for (unsigned i = 0; i != NumProtocols; i++)
|
||||
ID.AddPointer(protocols[i]);
|
||||
}
|
||||
|
||||
void ObjCQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, &Protocols[0], getNumProtocols());
|
||||
}
|
||||
|
||||
/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
|
||||
/// potentially looking through *all* consequtive typedefs. This returns the
|
||||
/// sum of the type qualifiers, so if you have:
|
||||
/// typedef const int A;
|
||||
/// typedef volatile A B;
|
||||
/// looking through the typedefs for B will give you "const volatile A".
|
||||
///
|
||||
QualType TypedefType::LookThroughTypedefs() const {
|
||||
// Usually, there is only a single level of typedefs, be fast in that case.
|
||||
QualType FirstType = getDecl()->getUnderlyingType();
|
||||
if (!isa<TypedefType>(FirstType))
|
||||
return FirstType;
|
||||
|
||||
// Otherwise, do the fully general loop.
|
||||
unsigned TypeQuals = 0;
|
||||
const TypedefType *TDT = this;
|
||||
while (1) {
|
||||
QualType CurType = TDT->getDecl()->getUnderlyingType();
|
||||
TypeQuals |= CurType.getQualifiers();
|
||||
|
||||
TDT = dyn_cast<TypedefType>(CurType);
|
||||
if (TDT == 0)
|
||||
return QualType(CurType.getTypePtr(), TypeQuals);
|
||||
}
|
||||
}
|
||||
|
||||
bool RecordType::classof(const Type *T) {
|
||||
if (const TagType *TT = dyn_cast<TagType>(T))
|
||||
return isa<RecordDecl>(TT->getDecl());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Type Printing
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void QualType::dump(const char *msg) const {
|
||||
std::string R = "identifier";
|
||||
getAsStringInternal(R);
|
||||
if (msg)
|
||||
fprintf(stderr, "%s: %s\n", msg, R.c_str());
|
||||
else
|
||||
fprintf(stderr, "%s\n", R.c_str());
|
||||
}
|
||||
|
||||
static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
|
||||
// Note: funkiness to ensure we get a space only between quals.
|
||||
bool NonePrinted = true;
|
||||
if (TypeQuals & QualType::Const)
|
||||
S += "const", NonePrinted = false;
|
||||
if (TypeQuals & QualType::Volatile)
|
||||
S += (NonePrinted+" volatile"), NonePrinted = false;
|
||||
if (TypeQuals & QualType::Restrict)
|
||||
S += (NonePrinted+" restrict"), NonePrinted = false;
|
||||
}
|
||||
|
||||
void QualType::getAsStringInternal(std::string &S) const {
|
||||
if (isNull()) {
|
||||
S += "NULL TYPE\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Print qualifiers as appropriate.
|
||||
unsigned TQ = getQualifiers();
|
||||
if (TQ) {
|
||||
std::string TQS;
|
||||
AppendTypeQualList(TQS, TQ);
|
||||
if (!S.empty())
|
||||
S = TQS + ' ' + S;
|
||||
else
|
||||
S = TQS;
|
||||
}
|
||||
|
||||
getTypePtr()->getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void BuiltinType::getAsStringInternal(std::string &S) const {
|
||||
if (S.empty()) {
|
||||
S = getName();
|
||||
} else {
|
||||
// Prefix the basic type, e.g. 'int X'.
|
||||
S = ' ' + S;
|
||||
S = getName() + S;
|
||||
}
|
||||
}
|
||||
|
||||
void ComplexType::getAsStringInternal(std::string &S) const {
|
||||
ElementType->getAsStringInternal(S);
|
||||
S = "_Complex " + S;
|
||||
}
|
||||
|
||||
void PointerType::getAsStringInternal(std::string &S) const {
|
||||
S = '*' + S;
|
||||
|
||||
// Handle things like 'int (*A)[4];' correctly.
|
||||
// FIXME: this should include vectors, but vectors use attributes I guess.
|
||||
if (isa<ArrayType>(PointeeType.getTypePtr()))
|
||||
S = '(' + S + ')';
|
||||
|
||||
PointeeType.getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void ReferenceType::getAsStringInternal(std::string &S) const {
|
||||
S = '&' + S;
|
||||
|
||||
// Handle things like 'int (&A)[4];' correctly.
|
||||
// FIXME: this should include vectors, but vectors use attributes I guess.
|
||||
if (isa<ArrayType>(ReferenceeType.getTypePtr()))
|
||||
S = '(' + S + ')';
|
||||
|
||||
ReferenceeType.getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void ConstantArrayType::getAsStringInternal(std::string &S) const {
|
||||
S += '[';
|
||||
S += llvm::utostr(getSize().getZExtValue());
|
||||
S += ']';
|
||||
|
||||
getElementType().getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void VariableArrayType::getAsStringInternal(std::string &S) const {
|
||||
S += '[';
|
||||
|
||||
if (getIndexTypeQualifier()) {
|
||||
AppendTypeQualList(S, getIndexTypeQualifier());
|
||||
S += ' ';
|
||||
}
|
||||
|
||||
if (getSizeModifier() == Static)
|
||||
S += "static";
|
||||
else if (getSizeModifier() == Star)
|
||||
S += '*';
|
||||
|
||||
if (getSizeExpr()) {
|
||||
std::ostringstream s;
|
||||
getSizeExpr()->printPretty(s);
|
||||
S += s.str();
|
||||
}
|
||||
S += ']';
|
||||
|
||||
getElementType().getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void VectorType::getAsStringInternal(std::string &S) const {
|
||||
S += " __attribute__((__vector_size__(";
|
||||
// FIXME: should multiply by element size somehow.
|
||||
S += llvm::utostr_32(NumElements*4); // convert back to bytes.
|
||||
S += ")))";
|
||||
ElementType.getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void OCUVectorType::getAsStringInternal(std::string &S) const {
|
||||
S += " __attribute__((ocu_vector_type(";
|
||||
S += llvm::utostr_32(NumElements);
|
||||
S += ")))";
|
||||
ElementType.getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void TypeOfExpr::getAsStringInternal(std::string &InnerString) const {
|
||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(e) X'.
|
||||
InnerString = ' ' + InnerString;
|
||||
std::ostringstream s;
|
||||
getUnderlyingExpr()->printPretty(s);
|
||||
InnerString = "typeof(" + s.str() + ")" + InnerString;
|
||||
}
|
||||
|
||||
void TypeOfType::getAsStringInternal(std::string &InnerString) const {
|
||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(t) X'.
|
||||
InnerString = ' ' + InnerString;
|
||||
std::string Tmp;
|
||||
getUnderlyingType().getAsStringInternal(Tmp);
|
||||
InnerString = "typeof(" + Tmp + ")" + InnerString;
|
||||
}
|
||||
|
||||
void FunctionTypeNoProto::getAsStringInternal(std::string &S) const {
|
||||
// If needed for precedence reasons, wrap the inner part in grouping parens.
|
||||
if (!S.empty())
|
||||
S = "(" + S + ")";
|
||||
|
||||
S += "()";
|
||||
getResultType().getAsStringInternal(S);
|
||||
}
|
||||
|
||||
void FunctionTypeProto::getAsStringInternal(std::string &S) const {
|
||||
// If needed for precedence reasons, wrap the inner part in grouping parens.
|
||||
if (!S.empty())
|
||||
S = "(" + S + ")";
|
||||
|
||||
S += "(";
|
||||
std::string Tmp;
|
||||
for (unsigned i = 0, e = getNumArgs(); i != e; ++i) {
|
||||
if (i) S += ", ";
|
||||
getArgType(i).getAsStringInternal(Tmp);
|
||||
S += Tmp;
|
||||
Tmp.clear();
|
||||
}
|
||||
|
||||
if (isVariadic()) {
|
||||
if (getNumArgs())
|
||||
S += ", ";
|
||||
S += "...";
|
||||
} else if (getNumArgs() == 0) {
|
||||
// Do not emit int() if we have a proto, emit 'int(void)'.
|
||||
S += "void";
|
||||
}
|
||||
|
||||
S += ")";
|
||||
getResultType().getAsStringInternal(S);
|
||||
}
|
||||
|
||||
|
||||
void TypedefType::getAsStringInternal(std::string &InnerString) const {
|
||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
||||
InnerString = ' ' + InnerString;
|
||||
InnerString = getDecl()->getIdentifier()->getName() + InnerString;
|
||||
}
|
||||
|
||||
void ObjCInterfaceType::getAsStringInternal(std::string &InnerString) const {
|
||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
||||
InnerString = ' ' + InnerString;
|
||||
InnerString = getDecl()->getIdentifier()->getName() + InnerString;
|
||||
}
|
||||
|
||||
void ObjCQualifiedInterfaceType::getAsStringInternal(
|
||||
std::string &InnerString) const {
|
||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
||||
InnerString = ' ' + InnerString;
|
||||
std::string ObjCQIString = getDecl()->getName();
|
||||
ObjCQIString += '<';
|
||||
int num = getNumProtocols();
|
||||
for (int i = 0; i < num; i++) {
|
||||
ObjCQIString += getProtocols(i)->getName();
|
||||
if (i < num-1)
|
||||
ObjCQIString += ',';
|
||||
}
|
||||
ObjCQIString += '>';
|
||||
InnerString = ObjCQIString + InnerString;
|
||||
}
|
||||
|
||||
void ObjCQualifiedIdType::getAsStringInternal(
|
||||
std::string &InnerString) const {
|
||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
||||
InnerString = ' ' + InnerString;
|
||||
std::string ObjCQIString = "id";
|
||||
ObjCQIString += '<';
|
||||
int num = getNumProtocols();
|
||||
for (int i = 0; i < num; i++) {
|
||||
ObjCQIString += getProtocols(i)->getName();
|
||||
if (i < num-1)
|
||||
ObjCQIString += ',';
|
||||
}
|
||||
ObjCQIString += '>';
|
||||
InnerString = ObjCQIString + InnerString;
|
||||
}
|
||||
|
||||
void TagType::getAsStringInternal(std::string &InnerString) const {
|
||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
||||
InnerString = ' ' + InnerString;
|
||||
|
||||
const char *Kind = getDecl()->getKindName();
|
||||
const char *ID;
|
||||
if (const IdentifierInfo *II = getDecl()->getIdentifier())
|
||||
ID = II->getName();
|
||||
else
|
||||
ID = "<anonymous>";
|
||||
|
||||
InnerString = std::string(Kind) + " " + ID + InnerString;
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
//===--- TypeSerialization.cpp - Serialization of Decls ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This files defines methods that implement bitcode serialization for Types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "llvm/Bitcode/Serialize.h"
|
||||
#include "llvm/Bitcode/Deserialize.h"
|
||||
|
||||
using namespace clang;
|
||||
using llvm::Serializer;
|
||||
using llvm::Deserializer;
|
||||
using llvm::SerializedPtrID;
|
||||
|
||||
|
||||
void QualType::Emit(Serializer& S) const {
|
||||
S.EmitPtr(getTypePtr());
|
||||
S.EmitInt(getQualifiers());
|
||||
}
|
||||
|
||||
QualType QualType::ReadVal(Deserializer& D) {
|
||||
QualType Q;
|
||||
D.ReadUIntPtr(Q.ThePtr,false);
|
||||
Q.ThePtr |= D.ReadInt();
|
||||
return Q;
|
||||
}
|
||||
|
||||
void QualType::ReadBackpatch(Deserializer& D) {
|
||||
D.ReadUIntPtr(ThePtr,true);
|
||||
ThePtr |= D.ReadInt();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Type Serialization: Dispatch code to handle specific types.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void Type::Emit(Serializer& S) const {
|
||||
S.EmitInt(getTypeClass());
|
||||
S.EmitPtr(this);
|
||||
|
||||
if (!isa<BuiltinType>(this))
|
||||
EmitImpl(S);
|
||||
}
|
||||
|
||||
void Type::EmitImpl(Serializer& S) const {
|
||||
assert (false && "Serializization for type not supported.");
|
||||
}
|
||||
|
||||
void Type::Create(ASTContext& Context, unsigned i, Deserializer& D) {
|
||||
Type::TypeClass K = static_cast<Type::TypeClass>(D.ReadInt());
|
||||
SerializedPtrID PtrID = D.ReadPtrID();
|
||||
|
||||
switch (K) {
|
||||
default:
|
||||
assert (false && "Deserialization for type not supported.");
|
||||
break;
|
||||
|
||||
case Type::Builtin:
|
||||
assert (i < Context.getTypes().size());
|
||||
assert (isa<BuiltinType>(Context.getTypes()[i]));
|
||||
D.RegisterPtr(PtrID,Context.getTypes()[i]);
|
||||
break;
|
||||
|
||||
case Type::Complex:
|
||||
D.RegisterPtr(PtrID,ComplexType::CreateImpl(Context,D));
|
||||
break;
|
||||
|
||||
case Type::ConstantArray:
|
||||
D.RegisterPtr(PtrID,ConstantArrayType::CreateImpl(Context,D));
|
||||
break;
|
||||
|
||||
case Type::FunctionNoProto:
|
||||
D.RegisterPtr(PtrID,FunctionTypeNoProto::CreateImpl(Context,D));
|
||||
break;
|
||||
|
||||
case Type::FunctionProto:
|
||||
D.RegisterPtr(PtrID,FunctionTypeProto::CreateImpl(Context,D));
|
||||
break;
|
||||
|
||||
case Type::Pointer:
|
||||
D.RegisterPtr(PtrID,PointerType::CreateImpl(Context,D));
|
||||
break;
|
||||
|
||||
case Type::Tagged:
|
||||
D.RegisterPtr(PtrID,TagType::CreateImpl(Context,D));
|
||||
break;
|
||||
|
||||
case Type::TypeName:
|
||||
D.RegisterPtr(PtrID,TypedefType::CreateImpl(Context,D));
|
||||
break;
|
||||
|
||||
case Type::VariableArray:
|
||||
D.RegisterPtr(PtrID,VariableArrayType::CreateImpl(Context,D));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ComplexType
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void ComplexType::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getElementType());
|
||||
}
|
||||
|
||||
Type* ComplexType::CreateImpl(ASTContext& Context, Deserializer& D) {
|
||||
return Context.getComplexType(QualType::ReadVal(D)).getTypePtr();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ConstantArray
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void ConstantArrayType::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getElementType());
|
||||
S.EmitInt(getSizeModifier());
|
||||
S.EmitInt(getIndexTypeQualifier());
|
||||
S.Emit(Size);
|
||||
}
|
||||
|
||||
Type* ConstantArrayType::CreateImpl(ASTContext& Context, Deserializer& D) {
|
||||
QualType ElTy = QualType::ReadVal(D);
|
||||
ArraySizeModifier am = static_cast<ArraySizeModifier>(D.ReadInt());
|
||||
unsigned ITQ = D.ReadInt();
|
||||
|
||||
llvm::APInt Size;
|
||||
D.Read(Size);
|
||||
|
||||
return Context.getConstantArrayType(ElTy,Size,am,ITQ).getTypePtr();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FunctionTypeNoProto
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void FunctionTypeNoProto::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getResultType());
|
||||
}
|
||||
|
||||
Type* FunctionTypeNoProto::CreateImpl(ASTContext& Context, Deserializer& D) {
|
||||
return Context.getFunctionTypeNoProto(QualType::ReadVal(D)).getTypePtr();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FunctionTypeProto
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void FunctionTypeProto::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getResultType());
|
||||
S.EmitBool(isVariadic());
|
||||
S.EmitInt(getNumArgs());
|
||||
|
||||
for (arg_type_iterator I=arg_type_begin(), E=arg_type_end(); I!=E; ++I)
|
||||
S.Emit(*I);
|
||||
}
|
||||
|
||||
Type* FunctionTypeProto::CreateImpl(ASTContext& Context, Deserializer& D) {
|
||||
QualType ResultType = QualType::ReadVal(D);
|
||||
bool isVariadic = D.ReadBool();
|
||||
unsigned NumArgs = D.ReadInt();
|
||||
|
||||
llvm::SmallVector<QualType,15> Args;
|
||||
|
||||
for (unsigned j = 0; j < NumArgs; ++j)
|
||||
Args.push_back(QualType::ReadVal(D));
|
||||
|
||||
return Context.getFunctionType(ResultType,&*Args.begin(),
|
||||
NumArgs,isVariadic).getTypePtr();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// PointerType
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void PointerType::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getPointeeType());
|
||||
}
|
||||
|
||||
Type* PointerType::CreateImpl(ASTContext& Context, Deserializer& D) {
|
||||
return Context.getPointerType(QualType::ReadVal(D)).getTypePtr();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TagType
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void TagType::EmitImpl(Serializer& S) const {
|
||||
S.EmitOwnedPtr(getDecl());
|
||||
}
|
||||
|
||||
Type* TagType::CreateImpl(ASTContext& Context, Deserializer& D) {
|
||||
std::vector<Type*>& Types =
|
||||
const_cast<std::vector<Type*>&>(Context.getTypes());
|
||||
|
||||
TagType* T = new TagType(NULL,QualType());
|
||||
Types.push_back(T);
|
||||
|
||||
// Deserialize the decl.
|
||||
T->decl = cast<TagDecl>(D.ReadOwnedPtr<Decl>());
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TypedefType
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void TypedefType::EmitImpl(Serializer& S) const {
|
||||
S.Emit(QualType((Type*)this,0).getCanonicalType());
|
||||
S.EmitPtr(Decl);
|
||||
}
|
||||
|
||||
Type* TypedefType::CreateImpl(ASTContext& Context, Deserializer& D) {
|
||||
std::vector<Type*>& Types =
|
||||
const_cast<std::vector<Type*>&>(Context.getTypes());
|
||||
|
||||
TypedefType* T = new TypedefType(Type::TypeName, NULL,QualType::ReadVal(D));
|
||||
Types.push_back(T);
|
||||
|
||||
D.ReadPtr(T->Decl); // May be backpatched.
|
||||
return T;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// VariableArrayType
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void VariableArrayType::EmitImpl(Serializer& S) const {
|
||||
S.Emit(getElementType());
|
||||
S.EmitInt(getSizeModifier());
|
||||
S.EmitInt(getIndexTypeQualifier());
|
||||
S.EmitOwnedPtr(SizeExpr);
|
||||
}
|
||||
|
||||
Type* VariableArrayType::CreateImpl(ASTContext& Context, Deserializer& D) {
|
||||
QualType ElTy = QualType::ReadVal(D);
|
||||
ArraySizeModifier am = static_cast<ArraySizeModifier>(D.ReadInt());
|
||||
unsigned ITQ = D.ReadInt();
|
||||
Expr* SizeExpr = D.ReadOwnedPtr<Expr>();
|
||||
|
||||
return Context.getVariableArrayType(ElTy,SizeExpr,am,ITQ).getTypePtr();
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
//==- DeadStores.cpp - Check for stores to dead variables --------*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This files defines a DeadStores, a flow-sensitive checker that looks for
|
||||
// stores to variables that are no longer live.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/LocalCheckers.h"
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
|
||||
class VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy {
|
||||
ASTContext &Ctx;
|
||||
Diagnostic &Diags;
|
||||
public:
|
||||
DeadStoreObs(ASTContext &ctx,Diagnostic &diags) : Ctx(ctx), Diags(diags){}
|
||||
virtual ~DeadStoreObs() {}
|
||||
|
||||
virtual void ObserveStmt(Stmt* S,
|
||||
const LiveVariables::AnalysisDataTy& AD,
|
||||
const LiveVariables::ValTy& Live) {
|
||||
|
||||
if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
|
||||
if (!B->isAssignmentOp()) return; // Skip non-assignments.
|
||||
|
||||
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
|
||||
if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
|
||||
if (VD->hasLocalStorage() && !Live(VD,AD)) {
|
||||
SourceRange R = B->getRHS()->getSourceRange();
|
||||
Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()),
|
||||
diag::warn_dead_store, 0, 0, &R, 1);
|
||||
}
|
||||
}
|
||||
else if(DeclStmt* DS = dyn_cast<DeclStmt>(S))
|
||||
// Iterate through the decls. Warn if any initializers are complex
|
||||
// expressions that are not live (never used).
|
||||
for (VarDecl* V = cast<VarDecl>(DS->getDecl()); V != NULL ;
|
||||
V = cast_or_null<VarDecl>(V->getNextDeclarator())) {
|
||||
if (V->hasLocalStorage())
|
||||
if (Expr* E = V->getInit()) {
|
||||
if (!Live(DS->getDecl(),AD)) {
|
||||
// Special case: check for initializations with constants.
|
||||
//
|
||||
// e.g. : int x = 0;
|
||||
//
|
||||
// If x is EVER assigned a new value later, don't issue
|
||||
// a warning. This is because such initialization can be
|
||||
// due to defensive programming.
|
||||
if (!E->isConstantExpr(Ctx,NULL)) {
|
||||
// Flag a warning.
|
||||
SourceRange R = E->getSourceRange();
|
||||
Diags.Report(Ctx.getFullLoc(V->getLocation()),
|
||||
diag::warn_dead_store, 0, 0, &R, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace clang {
|
||||
|
||||
void CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) {
|
||||
LiveVariables L(cfg);
|
||||
L.runOnCFG(cfg);
|
||||
DeadStoreObs A(Ctx, Diags);
|
||||
L.runOnAllBlocks(cfg,A);
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
@@ -1,87 +0,0 @@
|
||||
//=-- ExplodedGraph.cpp - Local, Path-Sens. "Exploded Graph" -*- C++ -*------=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the template classes ExplodedNode and ExplodedGraph,
|
||||
// which represent a path-sensitive, intra-procedural "exploded graph."
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
|
||||
#include <vector>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
|
||||
static inline std::vector<ExplodedNodeImpl*>& getVector(void* P) {
|
||||
return *reinterpret_cast<std::vector<ExplodedNodeImpl*>*>(P);
|
||||
}
|
||||
|
||||
void ExplodedNodeImpl::NodeGroup::addNode(ExplodedNodeImpl* N) {
|
||||
if (getKind() == Size1) {
|
||||
if (ExplodedNodeImpl* NOld = getNode()) {
|
||||
std::vector<ExplodedNodeImpl*>* V = new std::vector<ExplodedNodeImpl*>();
|
||||
V->push_back(NOld);
|
||||
V->push_back(N);
|
||||
P = reinterpret_cast<uintptr_t>(V) & SizeOther;
|
||||
}
|
||||
else
|
||||
P = reinterpret_cast<uintptr_t>(N);
|
||||
}
|
||||
else
|
||||
getVector(getPtr()).push_back(N);
|
||||
}
|
||||
|
||||
bool ExplodedNodeImpl::NodeGroup::empty() const {
|
||||
if (getKind() == Size1)
|
||||
return getNode() ? false : true;
|
||||
else
|
||||
return getVector(getPtr()).empty();
|
||||
}
|
||||
|
||||
unsigned ExplodedNodeImpl::NodeGroup::size() const {
|
||||
if (getKind() == Size1)
|
||||
return getNode() ? 1 : 0;
|
||||
else
|
||||
return getVector(getPtr()).size();
|
||||
}
|
||||
|
||||
ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::begin() const {
|
||||
if (getKind() == Size1)
|
||||
return (ExplodedNodeImpl**) &P;
|
||||
else
|
||||
return const_cast<ExplodedNodeImpl**>(&*(getVector(getPtr()).begin()));
|
||||
}
|
||||
|
||||
ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::end() const {
|
||||
if (getKind() == Size1)
|
||||
return (ExplodedNodeImpl**) (P ? &P+1 : &P);
|
||||
else
|
||||
return const_cast<ExplodedNodeImpl**>(&*(getVector(getPtr()).rbegin())+1);
|
||||
}
|
||||
|
||||
ExplodedNodeImpl::NodeGroup::~NodeGroup() {
|
||||
if (getKind() == SizeOther) delete &getVector(getPtr());
|
||||
}
|
||||
|
||||
|
||||
ExplodedGraphImpl::~ExplodedGraphImpl() {
|
||||
// Delete the FoldingSet's in Nodes. Note that the contents
|
||||
// of the FoldingSets are nodes allocated from the BumpPtrAllocator,
|
||||
// so all of those will get nuked when that object is destroyed.
|
||||
for (EdgeNodeSetMap::iterator I=Nodes.begin(), E=Nodes.end(); I!=E; ++I) {
|
||||
llvm::FoldingSet<ExplodedNodeImpl>* ENodes =
|
||||
reinterpret_cast<llvm::FoldingSet<ExplodedNodeImpl>*>(I->second);
|
||||
|
||||
for (llvm::FoldingSet<ExplodedNodeImpl>::iterator
|
||||
I=ENodes->begin(), E=ENodes->end(); I!=E; ++I)
|
||||
(*I).~ExplodedNodeImpl();
|
||||
|
||||
delete ENodes;
|
||||
}
|
||||
}
|
||||
@@ -1,449 +0,0 @@
|
||||
//===-- GRConstants.cpp - Simple, Path-Sens. Constant Prop. ------*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Constant Propagation via Graph Reachability
|
||||
//
|
||||
// This files defines a simple analysis that performs path-sensitive
|
||||
// constant propagation within a function. An example use of this analysis
|
||||
// is to perform simple checks for NULL dereferences.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/PathSensitive/GREngine.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
#include "clang/Analysis/Visitors/CFGStmtVisitor.h"
|
||||
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include <sstream>
|
||||
#endif
|
||||
|
||||
using namespace clang;
|
||||
using llvm::APInt;
|
||||
using llvm::APFloat;
|
||||
using llvm::dyn_cast;
|
||||
using llvm::cast;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DSPtr - A variant smart pointer that wraps either a ValueDecl* or a
|
||||
/// Stmt*. Use cast<> or dyn_cast<> to get actual pointer type
|
||||
//===----------------------------------------------------------------------===//
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN DSPtr {
|
||||
uintptr_t Raw;
|
||||
public:
|
||||
enum VariantKind { IsSubExp=0x0, IsValueDecl=0x1, IsBlkLvl=0x2, Flags=0x3 };
|
||||
inline void* getPtr() const { return reinterpret_cast<void*>(Raw & ~Flags); }
|
||||
inline VariantKind getKind() const { return (VariantKind) (Raw & Flags); }
|
||||
|
||||
DSPtr(ValueDecl* D) : Raw(reinterpret_cast<uintptr_t>(D) | IsValueDecl) {}
|
||||
DSPtr(Stmt* S, bool isBlkLvl)
|
||||
: Raw(reinterpret_cast<uintptr_t>(S) | (isBlkLvl ? IsBlkLvl : IsSubExp)) {}
|
||||
|
||||
bool isSubExpr() const { return getKind() == IsSubExp; }
|
||||
|
||||
inline void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ID.AddPointer(getPtr());
|
||||
ID.AddInteger((unsigned) getKind());
|
||||
}
|
||||
inline bool operator==(const DSPtr& X) const { return Raw == X.Raw; }
|
||||
inline bool operator!=(const DSPtr& X) const { return Raw != X.Raw; }
|
||||
inline bool operator<(const DSPtr& X) const {
|
||||
VariantKind k = getKind(), Xk = X.getKind();
|
||||
return k == Xk ? getPtr() < X.getPtr() : ((unsigned) k) < ((unsigned) Xk);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
// Machinery to get cast<> and dyn_cast<> working with DSPtr.
|
||||
namespace llvm {
|
||||
template<> inline bool isa<ValueDecl,DSPtr>(const DSPtr& V) {
|
||||
return V.getKind() == DSPtr::IsValueDecl;
|
||||
}
|
||||
template<> inline bool isa<Stmt,DSPtr>(const DSPtr& V) {
|
||||
return ((unsigned) V.getKind()) != DSPtr::IsValueDecl;
|
||||
}
|
||||
template<> struct VISIBILITY_HIDDEN cast_retty_impl<ValueDecl,DSPtr> {
|
||||
typedef const ValueDecl* ret_type;
|
||||
};
|
||||
template<> struct VISIBILITY_HIDDEN cast_retty_impl<Stmt,DSPtr> {
|
||||
typedef const Stmt* ret_type;
|
||||
};
|
||||
template<> struct VISIBILITY_HIDDEN simplify_type<DSPtr> {
|
||||
typedef void* SimpleType;
|
||||
static inline SimpleType getSimplifiedValue(const DSPtr &V) {
|
||||
return V.getPtr();
|
||||
}
|
||||
};
|
||||
} // end llvm namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DeclStmtMapTy - A ImmutableMap type from Decl*/Stmt* to integers.
|
||||
//
|
||||
// FIXME: We may eventually use APSInt, or a mixture of APSInt and
|
||||
// integer primitives to do this right; this will handle both
|
||||
// different bit-widths and allow us to detect integer overflows, etc.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
typedef llvm::ImmutableMap<DSPtr,uint64_t> DeclStmtMapTy;
|
||||
|
||||
namespace clang {
|
||||
template<>
|
||||
struct VISIBILITY_HIDDEN GRTrait<DeclStmtMapTy> {
|
||||
static inline void* toPtr(DeclStmtMapTy M) {
|
||||
return reinterpret_cast<void*>(M.getRoot());
|
||||
}
|
||||
static inline DeclStmtMapTy toState(void* P) {
|
||||
return DeclStmtMapTy(static_cast<DeclStmtMapTy::TreeTy*>(P));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// The Checker!
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN ExprVariantTy {
|
||||
const uint64_t val;
|
||||
const bool isConstant;
|
||||
public:
|
||||
ExprVariantTy() : val(0), isConstant(false) {}
|
||||
ExprVariantTy(uint64_t v) : val(v), isConstant(true) {}
|
||||
|
||||
operator bool() const { return isConstant; }
|
||||
uint64_t getVal() const { assert (isConstant); return val; }
|
||||
|
||||
ExprVariantTy operator+(const ExprVariantTy& X) const {
|
||||
if (!isConstant || !X.isConstant) return ExprVariantTy();
|
||||
else return ExprVariantTy(val+X.val);
|
||||
}
|
||||
|
||||
ExprVariantTy operator-(const ExprVariantTy& X) const {
|
||||
if (!isConstant || !X.isConstant) return ExprVariantTy();
|
||||
else return ExprVariantTy(val-X.val);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// The Checker!
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN GRConstants : public CFGStmtVisitor<GRConstants> {
|
||||
|
||||
public:
|
||||
typedef DeclStmtMapTy StateTy;
|
||||
typedef GRNodeBuilder<GRConstants> NodeBuilder;
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
|
||||
protected:
|
||||
// Liveness - live-variables information the ValueDecl* and Expr* (block-level)
|
||||
// in the CFG. Used to prune out dead state.
|
||||
LiveVariables* Liveness;
|
||||
|
||||
// Builder - The current GRNodeBuilder which is used when building the nodes
|
||||
// for a given statement.
|
||||
NodeBuilder* Builder;
|
||||
|
||||
DeclStmtMapTy::Factory StateMgr;
|
||||
|
||||
// cfg - the current CFG.
|
||||
CFG* cfg;
|
||||
|
||||
typedef llvm::SmallVector<NodeTy*,8> NodeSetTy;
|
||||
NodeSetTy NodeSetA;
|
||||
NodeSetTy NodeSetB;
|
||||
NodeSetTy* Nodes;
|
||||
NodeSetTy* OldNodes;
|
||||
StateTy CurrentState;
|
||||
NodeTy* InitialPred;
|
||||
|
||||
public:
|
||||
GRConstants() : Liveness(NULL), Builder(NULL), cfg(NULL),
|
||||
Nodes(&NodeSetA), OldNodes(&NodeSetB),
|
||||
CurrentState(StateMgr.GetEmptyMap()), InitialPred(NULL) {}
|
||||
|
||||
~GRConstants() { delete Liveness; }
|
||||
|
||||
CFG& getCFG() { assert (cfg); return *cfg; }
|
||||
|
||||
void Initialize(CFG& c) {
|
||||
cfg = &c;
|
||||
Liveness = new LiveVariables(c);
|
||||
Liveness->runOnCFG(c);
|
||||
}
|
||||
|
||||
StateTy getInitialState() {
|
||||
return StateMgr.GetEmptyMap();
|
||||
}
|
||||
|
||||
void ProcessStmt(Stmt* S, NodeBuilder& builder);
|
||||
void SwitchNodeSets();
|
||||
void DoStmt(Stmt* S);
|
||||
|
||||
StateTy RemoveDescendantMappings(Stmt* S, StateTy M, unsigned Levels=2);
|
||||
StateTy RemoveSubExprMappings(StateTy M);
|
||||
|
||||
void AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl = false);
|
||||
void AddBinding(ValueDecl* D, ExprVariantTy V);
|
||||
|
||||
ExprVariantTy GetBinding(Expr* E);
|
||||
|
||||
void BlockStmt_VisitStmt(Stmt* S) { DoStmt(S); }
|
||||
|
||||
void VisitAssign(BinaryOperator* O);
|
||||
void VisitBinAdd(BinaryOperator* O);
|
||||
void VisitBinSub(BinaryOperator* O);
|
||||
void VisitBinAssign(BinaryOperator* D);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
static inline Expr* IgnoreParen(Expr* E) {
|
||||
while (ParenExpr* P = dyn_cast<ParenExpr>(E))
|
||||
E = P->getSubExpr();
|
||||
|
||||
return E;
|
||||
}
|
||||
|
||||
void GRConstants::ProcessStmt(Stmt* S, NodeBuilder& builder) {
|
||||
Builder = &builder;
|
||||
Nodes->clear();
|
||||
OldNodes->clear();
|
||||
InitialPred = Builder->getLastNode();
|
||||
assert (InitialPred);
|
||||
OldNodes->push_back(InitialPred);
|
||||
CurrentState = RemoveSubExprMappings(InitialPred->getState());
|
||||
BlockStmt_Visit(S);
|
||||
Builder = NULL;
|
||||
}
|
||||
|
||||
ExprVariantTy GRConstants::GetBinding(Expr* E) {
|
||||
DSPtr P(NULL);
|
||||
E = IgnoreParen(E);
|
||||
|
||||
switch (E->getStmtClass()) {
|
||||
case Stmt::DeclRefExprClass:
|
||||
P = DSPtr(cast<DeclRefExpr>(E)->getDecl());
|
||||
break;
|
||||
|
||||
case Stmt::IntegerLiteralClass:
|
||||
return cast<IntegerLiteral>(E)->getValue().getZExtValue();
|
||||
|
||||
default:
|
||||
P = DSPtr(E, getCFG().isBlkExpr(E));
|
||||
break;
|
||||
}
|
||||
|
||||
StateTy::iterator I = CurrentState.find(P);
|
||||
|
||||
if (I == CurrentState.end())
|
||||
return ExprVariantTy();
|
||||
|
||||
return (*I).second;
|
||||
}
|
||||
|
||||
void GRConstants::AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl) {
|
||||
if (V)
|
||||
CurrentState = StateMgr.Add(CurrentState, DSPtr(E,isBlkLvl), V.getVal());
|
||||
}
|
||||
|
||||
void GRConstants::AddBinding(ValueDecl* D, ExprVariantTy V) {
|
||||
if (V)
|
||||
CurrentState = StateMgr.Add(CurrentState, DSPtr(D), V.getVal());
|
||||
else
|
||||
CurrentState = StateMgr.Remove(CurrentState, DSPtr(D));
|
||||
}
|
||||
|
||||
void GRConstants::SwitchNodeSets() {
|
||||
NodeSetTy* Tmp = OldNodes;
|
||||
OldNodes = Nodes;
|
||||
Nodes = Tmp;
|
||||
Nodes->clear();
|
||||
}
|
||||
|
||||
GRConstants::StateTy
|
||||
GRConstants::RemoveSubExprMappings(StateTy M) {
|
||||
#if 0
|
||||
return M;
|
||||
#else
|
||||
for (StateTy::iterator I = M.begin(), E = M.end();
|
||||
I!=E && I.getKey().getKind() == DSPtr::IsSubExp; ++I) {
|
||||
// Note: we can assign a new map to M since the iterators are
|
||||
// iterating over the tree of the original map (aren't immutable maps
|
||||
// nice?).
|
||||
M = StateMgr.Remove(M, I.getKey());
|
||||
}
|
||||
|
||||
return M;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
GRConstants::StateTy
|
||||
GRConstants::RemoveDescendantMappings(Stmt* S, GRConstants::StateTy State,
|
||||
unsigned Levels) {
|
||||
#if 1
|
||||
return State;
|
||||
#else
|
||||
typedef Stmt::child_iterator iterator;
|
||||
|
||||
for (iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
|
||||
if (Stmt* C = *I) {
|
||||
if (Levels == 1) {
|
||||
// Observe that this will only remove mappings to non-block level
|
||||
// expressions. This is valid even if *CI is a block-level expression,
|
||||
// since it simply won't be in the map in the first place.
|
||||
// Note: This should also work if 'C' is a block-level expression,
|
||||
// although ideally we would want to skip processing C's children.
|
||||
State = StateMgr.Remove(State, DSPtr(C,false));
|
||||
}
|
||||
else {
|
||||
if (ParenExpr* P = dyn_cast<ParenExpr>(C))
|
||||
State = RemoveDescendantMappings(P, State, Levels);
|
||||
else
|
||||
State = RemoveDescendantMappings(C, State, Levels-1);
|
||||
}
|
||||
}
|
||||
|
||||
return State;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GRConstants::DoStmt(Stmt* S) {
|
||||
for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
|
||||
if (*I) DoStmt(*I);
|
||||
|
||||
for (NodeSetTy::iterator I=OldNodes->begin(), E=OldNodes->end(); I!=E; ++I) {
|
||||
NodeTy* Pred = *I;
|
||||
|
||||
if (Pred != InitialPred)
|
||||
CurrentState = Pred->getState();
|
||||
|
||||
StateTy OldState = CurrentState;
|
||||
|
||||
if (Pred != InitialPred)
|
||||
CurrentState = RemoveDescendantMappings(S, CurrentState);
|
||||
|
||||
Visit(S);
|
||||
|
||||
if (CurrentState != OldState) {
|
||||
NodeTy* N = Builder->generateNode(S, CurrentState, Pred);
|
||||
if (N) Nodes->push_back(N);
|
||||
}
|
||||
else Nodes->push_back(Pred);
|
||||
}
|
||||
|
||||
SwitchNodeSets();
|
||||
}
|
||||
|
||||
void GRConstants::VisitBinAdd(BinaryOperator* B) {
|
||||
AddBinding(B, GetBinding(B->getLHS()) + GetBinding(B->getRHS()));
|
||||
}
|
||||
|
||||
void GRConstants::VisitBinSub(BinaryOperator* B) {
|
||||
AddBinding(B, GetBinding(B->getLHS()) - GetBinding(B->getRHS()));
|
||||
}
|
||||
|
||||
|
||||
void GRConstants::VisitBinAssign(BinaryOperator* B) {
|
||||
if (DeclRefExpr* D = dyn_cast<DeclRefExpr>(IgnoreParen(B->getLHS())))
|
||||
AddBinding(D->getDecl(), GetBinding(B->getRHS()));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Driver.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef NDEBUG
|
||||
namespace llvm {
|
||||
template<>
|
||||
struct VISIBILITY_HIDDEN DOTGraphTraits<GRConstants::NodeTy*> :
|
||||
public DefaultDOTGraphTraits {
|
||||
|
||||
static std::string getNodeLabel(const GRConstants::NodeTy* N, void*) {
|
||||
std::ostringstream Out;
|
||||
|
||||
Out << "Vertex: " << (void*) N << '\n';
|
||||
ProgramPoint Loc = N->getLocation();
|
||||
|
||||
switch (Loc.getKind()) {
|
||||
case ProgramPoint::BlockEntranceKind:
|
||||
Out << "Block Entrance: B"
|
||||
<< cast<BlockEntrance>(Loc).getBlock()->getBlockID();
|
||||
break;
|
||||
|
||||
case ProgramPoint::BlockExitKind:
|
||||
assert (false);
|
||||
break;
|
||||
|
||||
case ProgramPoint::PostStmtKind: {
|
||||
const PostStmt& L = cast<PostStmt>(Loc);
|
||||
Out << "Stmt: " << (void*) L.getStmt() << '\n';
|
||||
L.getStmt()->printPretty(Out);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
const BlockEdge& E = cast<BlockEdge>(Loc);
|
||||
Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B"
|
||||
<< E.getDst()->getBlockID() << ')';
|
||||
}
|
||||
}
|
||||
|
||||
Out << "\n{";
|
||||
|
||||
GRConstants::StateTy M = N->getState();
|
||||
bool isFirst = true;
|
||||
|
||||
for (GRConstants::StateTy::iterator I=M.begin(), E=M.end(); I!=E; ++I) {
|
||||
if (!isFirst)
|
||||
Out << '\n';
|
||||
else
|
||||
isFirst = false;
|
||||
|
||||
if (ValueDecl* V = dyn_cast<ValueDecl>(I.getKey())) {
|
||||
Out << "Decl: " << (void*) V << ", " << V->getName();
|
||||
}
|
||||
else {
|
||||
Stmt* E = cast<Stmt>(I.getKey());
|
||||
Out << "Stmt: " << (void*) E;
|
||||
}
|
||||
|
||||
Out << " => " << I.getData();
|
||||
}
|
||||
|
||||
Out << " }";
|
||||
|
||||
return Out.str();
|
||||
}
|
||||
};
|
||||
} // end llvm namespace
|
||||
#endif
|
||||
|
||||
namespace clang {
|
||||
void RunGRConstants(CFG& cfg) {
|
||||
GREngine<GRConstants> Engine(cfg);
|
||||
Engine.ExecuteWorkList();
|
||||
#ifndef NDEBUG
|
||||
llvm::ViewGraph(*Engine.getGraph().roots_begin(),"GRConstants");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
//==- GREngine.cpp - Path-Sensitive Dataflow Engine ----------------*- C++ -*-//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a generic engine for intraprocedural, path-sensitive,
|
||||
// dataflow analysis via graph reachability engine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/PathSensitive/GREngine.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include <vector>
|
||||
|
||||
using llvm::cast;
|
||||
using llvm::isa;
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN DFS : public GRWorkList {
|
||||
llvm::SmallVector<GRWorkListUnit,20> Stack;
|
||||
public:
|
||||
virtual bool hasWork() const {
|
||||
return !Stack.empty();
|
||||
}
|
||||
|
||||
virtual void Enqueue(const GRWorkListUnit& U) {
|
||||
Stack.push_back(U);
|
||||
}
|
||||
|
||||
virtual GRWorkListUnit Dequeue() {
|
||||
assert (!Stack.empty());
|
||||
const GRWorkListUnit& U = Stack.back();
|
||||
Stack.pop_back(); // This technically "invalidates" U, but we are fine.
|
||||
return U;
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
// Place the dstor for GRWorkList here because it contains virtual member
|
||||
// functions, and we the code for the dstor generated in one compilation unit.
|
||||
GRWorkList::~GRWorkList() {}
|
||||
|
||||
GRWorkList* GRWorkList::MakeDFS() { return new DFS(); }
|
||||
|
||||
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
|
||||
bool GREngineImpl::ExecuteWorkList(unsigned Steps) {
|
||||
|
||||
if (G->num_roots() == 0) { // Initialize the analysis by constructing
|
||||
// the root if none exists.
|
||||
|
||||
CFGBlock* Entry = &cfg.getEntry();
|
||||
|
||||
assert (Entry->empty() &&
|
||||
"Entry block must be empty.");
|
||||
|
||||
assert (Entry->succ_size() == 1 &&
|
||||
"Entry block must have 1 successor.");
|
||||
|
||||
// Get the solitary successor.
|
||||
CFGBlock* Succ = *(Entry->succ_begin());
|
||||
|
||||
// Construct an edge representing the
|
||||
// starting location in the function.
|
||||
BlockEdge StartLoc(cfg, Entry, Succ);
|
||||
|
||||
// Generate the root.
|
||||
GenerateNode(StartLoc, getInitialState());
|
||||
}
|
||||
|
||||
while (Steps && WList->hasWork()) {
|
||||
--Steps;
|
||||
const GRWorkListUnit& WU = WList->Dequeue();
|
||||
ExplodedNodeImpl* Node = WU.getNode();
|
||||
|
||||
// Dispatch on the location type.
|
||||
switch (Node->getLocation().getKind()) {
|
||||
default:
|
||||
assert (isa<BlockEdge>(Node->getLocation()));
|
||||
HandleBlockEdge(cast<BlockEdge>(Node->getLocation()), Node);
|
||||
break;
|
||||
|
||||
case ProgramPoint::BlockEntranceKind:
|
||||
HandleBlockEntrance(cast<BlockEntrance>(Node->getLocation()), Node);
|
||||
break;
|
||||
|
||||
case ProgramPoint::BlockExitKind:
|
||||
assert (false && "BlockExit location never occur in forward analysis.");
|
||||
break;
|
||||
|
||||
case ProgramPoint::PostStmtKind:
|
||||
HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
|
||||
WU.getIndex(), Node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return WList->hasWork();
|
||||
}
|
||||
|
||||
void GREngineImpl::HandleBlockEdge(const BlockEdge& L, ExplodedNodeImpl* Pred) {
|
||||
|
||||
CFGBlock* Blk = L.getDst();
|
||||
|
||||
// Check if we are entering the EXIT block.
|
||||
if (Blk == &cfg.getExit()) {
|
||||
|
||||
assert (cfg.getExit().size() == 0 && "EXIT block cannot contain Stmts.");
|
||||
|
||||
// Process the final state transition.
|
||||
void* State = ProcessEOP(Blk, Pred->State);
|
||||
|
||||
bool IsNew;
|
||||
ExplodedNodeImpl* Node = G->getNodeImpl(BlockEntrance(Blk), State, &IsNew);
|
||||
Node->addPredecessor(Pred);
|
||||
|
||||
// If the node was freshly created, mark it as an "End-Of-Path" node.
|
||||
if (IsNew) G->addEndOfPath(Node);
|
||||
|
||||
// This path is done. Don't enqueue any more nodes.
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: we will dispatch to a function that
|
||||
// manipulates the state at the entrance to a block.
|
||||
|
||||
GenerateNode(BlockEntrance(Blk), Pred->State, Pred);
|
||||
}
|
||||
|
||||
void GREngineImpl::HandleBlockEntrance(const BlockEntrance& L,
|
||||
ExplodedNodeImpl* Pred) {
|
||||
|
||||
if (Stmt* S = L.getFirstStmt()) {
|
||||
GRNodeBuilderImpl Builder(L.getBlock(), 0, Pred, this);
|
||||
ProcessStmt(S, Builder);
|
||||
}
|
||||
else
|
||||
HandleBlockExit(L.getBlock(), Pred);
|
||||
}
|
||||
|
||||
|
||||
void GREngineImpl::HandleBlockExit(CFGBlock * B, ExplodedNodeImpl* Pred) {
|
||||
|
||||
if (Stmt* Terminator = B->getTerminator())
|
||||
ProcessTerminator(Terminator, B, Pred);
|
||||
else {
|
||||
assert (B->succ_size() == 1 &&
|
||||
"Blocks with no terminator should have at most 1 successor.");
|
||||
|
||||
GenerateNode(BlockEdge(cfg,B,*(B->succ_begin())), Pred->State, Pred);
|
||||
}
|
||||
}
|
||||
|
||||
void GREngineImpl::HandlePostStmt(const PostStmt& L, CFGBlock* B,
|
||||
unsigned StmtIdx, ExplodedNodeImpl* Pred) {
|
||||
|
||||
assert (!B->empty());
|
||||
|
||||
if (StmtIdx == B->size())
|
||||
HandleBlockExit(B, Pred);
|
||||
else {
|
||||
GRNodeBuilderImpl Builder(B, StmtIdx, Pred, this);
|
||||
ProcessStmt((*B)[StmtIdx], Builder);
|
||||
}
|
||||
}
|
||||
|
||||
typedef llvm::DenseMap<Stmt*,Stmt*> ParentMapTy;
|
||||
/// PopulateParentMap - Recurse the AST starting at 'Parent' and add the
|
||||
/// mappings between child and parent to ParentMap.
|
||||
static void PopulateParentMap(Stmt* Parent, ParentMapTy& M) {
|
||||
for (Stmt::child_iterator I=Parent->child_begin(),
|
||||
E=Parent->child_end(); I!=E; ++I) {
|
||||
|
||||
assert (M.find(*I) == M.end());
|
||||
M[*I] = Parent;
|
||||
PopulateParentMap(*I, M);
|
||||
}
|
||||
}
|
||||
|
||||
/// GenerateNode - Utility method to generate nodes, hook up successors,
|
||||
/// and add nodes to the worklist.
|
||||
void GREngineImpl::GenerateNode(const ProgramPoint& Loc, void* State,
|
||||
ExplodedNodeImpl* Pred) {
|
||||
|
||||
bool IsNew;
|
||||
ExplodedNodeImpl* Node = G->getNodeImpl(Loc, State, &IsNew);
|
||||
|
||||
if (Pred)
|
||||
Node->addPredecessor(Pred); // Link 'Node' with its predecessor.
|
||||
else {
|
||||
assert (IsNew);
|
||||
G->addRoot(Node); // 'Node' has no predecessor. Make it a root.
|
||||
}
|
||||
|
||||
// Only add 'Node' to the worklist if it was freshly generated.
|
||||
if (IsNew) WList->Enqueue(GRWorkListUnit(Node));
|
||||
}
|
||||
|
||||
GRNodeBuilderImpl::GRNodeBuilderImpl(CFGBlock* b, unsigned idx,
|
||||
ExplodedNodeImpl* N, GREngineImpl* e)
|
||||
: Eng(*e), B(*b), Idx(idx), LastNode(N), Populated(false) {
|
||||
Deferred.insert(N);
|
||||
}
|
||||
|
||||
GRNodeBuilderImpl::~GRNodeBuilderImpl() {
|
||||
for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
|
||||
if (!(*I)->isInfeasible())
|
||||
GenerateAutoTransition(*I);
|
||||
}
|
||||
|
||||
void GRNodeBuilderImpl::GenerateAutoTransition(ExplodedNodeImpl* N) {
|
||||
assert (!N->isInfeasible());
|
||||
|
||||
PostStmt Loc(getStmt());
|
||||
|
||||
if (Loc == N->getLocation()) {
|
||||
// Note: 'N' should be a fresh node because otherwise it shouldn't be
|
||||
// a member of Deferred.
|
||||
Eng.WList->Enqueue(N, B, Idx+1);
|
||||
return;
|
||||
}
|
||||
|
||||
bool IsNew;
|
||||
ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(Loc, N->State, &IsNew);
|
||||
Succ->addPredecessor(N);
|
||||
|
||||
if (IsNew)
|
||||
Eng.WList->Enqueue(Succ, B, Idx+1);
|
||||
}
|
||||
|
||||
ExplodedNodeImpl* GRNodeBuilderImpl::generateNodeImpl(Stmt* S, void* State,
|
||||
ExplodedNodeImpl* Pred) {
|
||||
|
||||
bool IsNew;
|
||||
ExplodedNodeImpl* N = Eng.G->getNodeImpl(PostStmt(S), State, &IsNew);
|
||||
N->addPredecessor(Pred);
|
||||
Deferred.erase(Pred);
|
||||
|
||||
HasGeneratedNode = true;
|
||||
|
||||
if (IsNew) {
|
||||
Deferred.insert(N);
|
||||
LastNode = N;
|
||||
return N;
|
||||
}
|
||||
|
||||
LastNode = NULL;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
//=- LiveVariables.cpp - Live Variable Analysis for Source CFGs -*- C++ --*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
// details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements Live Variables analysis for source-level CFGs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Dataflow initialization logic.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN RegisterDecls
|
||||
: public CFGRecStmtDeclVisitor<RegisterDecls> {
|
||||
|
||||
LiveVariables::AnalysisDataTy& AD;
|
||||
public:
|
||||
RegisterDecls(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}
|
||||
void VisitVarDecl(VarDecl* VD) { AD.Register(VD); }
|
||||
CFG& getCFG() { return AD.getCFG(); }
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
void LiveVariables::InitializeValues(const CFG& cfg) {
|
||||
RegisterDecls R(getAnalysisData());
|
||||
cfg.VisitBlockStmts(R);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
|
||||
static const bool Alive = true;
|
||||
static const bool Dead = false;
|
||||
|
||||
class VISIBILITY_HIDDEN TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{
|
||||
LiveVariables::AnalysisDataTy& AD;
|
||||
LiveVariables::ValTy LiveState;
|
||||
public:
|
||||
TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}
|
||||
|
||||
LiveVariables::ValTy& getVal() { return LiveState; }
|
||||
CFG& getCFG() { return AD.getCFG(); }
|
||||
|
||||
void VisitDeclRefExpr(DeclRefExpr* DR);
|
||||
void VisitBinaryOperator(BinaryOperator* B);
|
||||
void VisitAssign(BinaryOperator* B);
|
||||
void VisitDeclStmt(DeclStmt* DS);
|
||||
void VisitUnaryOperator(UnaryOperator* U);
|
||||
void Visit(Stmt *S);
|
||||
|
||||
DeclRefExpr* FindDeclRef(Stmt *S);
|
||||
};
|
||||
|
||||
void TransferFuncs::Visit(Stmt *S) {
|
||||
if (AD.Observer)
|
||||
AD.Observer->ObserveStmt(S,AD,LiveState);
|
||||
|
||||
static_cast<CFGStmtVisitor<TransferFuncs>*>(this)->Visit(S);
|
||||
}
|
||||
|
||||
void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
|
||||
if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl()))
|
||||
LiveState(V,AD) = Alive;
|
||||
}
|
||||
|
||||
void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
|
||||
if (B->isAssignmentOp()) VisitAssign(B);
|
||||
else VisitStmt(B);
|
||||
}
|
||||
|
||||
void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
|
||||
Stmt *S = U->getSubExpr();
|
||||
|
||||
switch (U->getOpcode()) {
|
||||
case UnaryOperator::SizeOf: return;
|
||||
case UnaryOperator::PostInc:
|
||||
case UnaryOperator::PostDec:
|
||||
case UnaryOperator::PreInc:
|
||||
case UnaryOperator::PreDec:
|
||||
case UnaryOperator::AddrOf:
|
||||
// Walk through the subexpressions, blasting through ParenExprs
|
||||
// until we either find a DeclRefExpr or some non-DeclRefExpr
|
||||
// expression.
|
||||
if (DeclRefExpr* DR = FindDeclRef(S)) {
|
||||
// Treat the --/++/& operator as a kill.
|
||||
LiveState(DR->getDecl(),AD) = Dead;
|
||||
if (AD.Observer) { AD.Observer->ObserverKill(DR); }
|
||||
return VisitDeclRefExpr(DR);
|
||||
}
|
||||
|
||||
// Fall-through.
|
||||
|
||||
default:
|
||||
return Visit(S);
|
||||
}
|
||||
}
|
||||
|
||||
DeclRefExpr* TransferFuncs::FindDeclRef(Stmt *S) {
|
||||
for (;;)
|
||||
if (ParenExpr* P = dyn_cast<ParenExpr>(S)) {
|
||||
S = P->getSubExpr(); continue;
|
||||
}
|
||||
else if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(S))
|
||||
return DR;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void TransferFuncs::VisitAssign(BinaryOperator* B) {
|
||||
Stmt* LHS = B->getLHS();
|
||||
|
||||
// Assigning to a variable?
|
||||
if (DeclRefExpr* DR = FindDeclRef(LHS)) {
|
||||
LiveState(DR->getDecl(),AD) = Dead;
|
||||
if (AD.Observer) { AD.Observer->ObserverKill(DR); }
|
||||
|
||||
// Handle things like +=, etc., which also generate "uses"
|
||||
// of a variable. Do this just by visiting the subexpression.
|
||||
if (B->getOpcode() != BinaryOperator::Assign)
|
||||
VisitDeclRefExpr(DR);
|
||||
}
|
||||
else // Not assigning to a variable. Process LHS as usual.
|
||||
Visit(LHS);
|
||||
|
||||
Visit(B->getRHS());
|
||||
}
|
||||
|
||||
void TransferFuncs::VisitDeclStmt(DeclStmt* DS) {
|
||||
// Declarations effectively "kill" a variable since they cannot
|
||||
// possibly be live before they are declared.
|
||||
for (ScopedDecl* D = DS->getDecl(); D != NULL; D = D->getNextDeclarator())
|
||||
LiveState(D,AD) = Dead;
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Merge operator: if something is live on any successor block, it is live
|
||||
// in the current block (a set union).
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
typedef DeclBitVector_Types::Union Merge;
|
||||
typedef DataflowSolver<LiveVariables,TransferFuncs,Merge> Solver;
|
||||
} // end anonymous namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// External interface to run Liveness analysis.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void LiveVariables::runOnCFG(CFG& cfg) {
|
||||
Solver S(*this);
|
||||
S.runOnCFG(cfg);
|
||||
}
|
||||
|
||||
void LiveVariables::runOnAllBlocks(const CFG& cfg,
|
||||
LiveVariables::ObserverTy& Obs) {
|
||||
Solver S(*this);
|
||||
ObserverTy* OldObserver = getAnalysisData().Observer;
|
||||
getAnalysisData().Observer = &Obs;
|
||||
S.runOnAllBlocks(cfg);
|
||||
getAnalysisData().Observer = OldObserver;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// liveness queries
|
||||
//
|
||||
|
||||
bool LiveVariables::isLive(const CFGBlock* B, const VarDecl* D) const {
|
||||
return getBlockData(B)(D,getAnalysisData());
|
||||
}
|
||||
|
||||
bool LiveVariables::isLive(const ValTy& Live, const VarDecl* D) const {
|
||||
return Live(D,getAnalysisData());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// printing liveness state for debugging
|
||||
//
|
||||
|
||||
void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const {
|
||||
const AnalysisDataTy& AD = getAnalysisData();
|
||||
|
||||
for (AnalysisDataTy::decl_iterator I = AD.begin_decl(),
|
||||
E = AD.end_decl(); I!=E; ++I)
|
||||
if (V.getDeclBit(I->second)) {
|
||||
SourceLocation PhysLoc = SM.getPhysicalLoc(I->first->getLocation());
|
||||
|
||||
fprintf(stderr, " %s <%s:%u:%u>\n",
|
||||
I->first->getIdentifier()->getName(),
|
||||
SM.getSourceName(PhysLoc),
|
||||
SM.getLineNumber(PhysLoc),
|
||||
SM.getColumnNumber(PhysLoc));
|
||||
}
|
||||
}
|
||||
|
||||
void LiveVariables::dumpBlockLiveness(SourceManager& M) const {
|
||||
for (BlockDataMapTy::iterator I = getBlockDataMap().begin(),
|
||||
E = getBlockDataMap().end(); I!=E; ++I) {
|
||||
fprintf(stderr, "\n[ B%d (live variables at block exit) ]\n",
|
||||
I->first->getBlockID());
|
||||
|
||||
dumpLiveness(I->second,M);
|
||||
}
|
||||
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
##===- clang/Analysis/Makefile -----------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# This implements analyses built on top of source-level CFGs.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../..
|
||||
LIBRARYNAME := clangAnalysis
|
||||
BUILD_ARCHIVE = 1
|
||||
CXXFLAGS = -fno-rtti
|
||||
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
//= ProgramPoint.cpp - Program Points for Path-Sensitive Analysis --*- C++ -*-//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements methods for subclasses of ProgramPoint.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
BlockEdge::BlockEdge(CFG& cfg, const CFGBlock* B1, const CFGBlock* B2) {
|
||||
if (B1->succ_size() == 1) {
|
||||
assert (*(B1->succ_begin()) == B2);
|
||||
Data = reinterpret_cast<uintptr_t>(B1) | BlockEdgeSrcKind;
|
||||
}
|
||||
else if (B2->pred_size() == 1) {
|
||||
assert (*(B2->pred_begin()) == B1);
|
||||
Data = reinterpret_cast<uintptr_t>(B2) | BlockEdgeDstKind;
|
||||
}
|
||||
else
|
||||
Data = reinterpret_cast<uintptr_t>(cfg.getBlockEdgeImpl(B1,B2))
|
||||
| BlockEdgeAuxKind;
|
||||
}
|
||||
|
||||
CFGBlock* BlockEdge::getSrc() const {
|
||||
switch (getKind()) {
|
||||
default:
|
||||
assert (false && "Invalid BlockEdgeKind.");
|
||||
return NULL;
|
||||
|
||||
case BlockEdgeSrcKind:
|
||||
return reinterpret_cast<CFGBlock*>(getRawPtr());
|
||||
|
||||
case BlockEdgeDstKind:
|
||||
return *(reinterpret_cast<CFGBlock*>(getRawPtr())->pred_begin());
|
||||
|
||||
case BlockEdgeAuxKind:
|
||||
return reinterpret_cast<BPair*>(getRawPtr())->first;
|
||||
}
|
||||
}
|
||||
|
||||
CFGBlock* BlockEdge::getDst() const {
|
||||
switch (getKind()) {
|
||||
default:
|
||||
assert (false && "Invalid BlockEdgeKind.");
|
||||
return NULL;
|
||||
|
||||
case BlockEdgeSrcKind:
|
||||
return *(reinterpret_cast<CFGBlock*>(getRawPtr())->succ_begin());
|
||||
|
||||
case BlockEdgeDstKind:
|
||||
return reinterpret_cast<CFGBlock*>(getRawPtr());
|
||||
|
||||
case BlockEdgeAuxKind:
|
||||
return reinterpret_cast<BPair*>(getRawPtr())->second;
|
||||
}
|
||||
}
|
||||
@@ -1,277 +0,0 @@
|
||||
//==- UninitializedValues.cpp - Find Unintialized Values --------*- C++ --*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements Uninitialized Values analysis for source-level CFGs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/Analyses/UninitializedValues.h"
|
||||
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
|
||||
#include "clang/Analysis/LocalCheckers.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Dataflow initialization logic.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
|
||||
class VISIBILITY_HIDDEN RegisterDecls
|
||||
: public CFGRecStmtDeclVisitor<RegisterDecls> {
|
||||
|
||||
UninitializedValues::AnalysisDataTy& AD;
|
||||
public:
|
||||
RegisterDecls(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {}
|
||||
|
||||
void VisitBlockVarDecl(BlockVarDecl* VD) { AD.Register(VD); }
|
||||
CFG& getCFG() { return AD.getCFG(); }
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
void UninitializedValues::InitializeValues(const CFG& cfg) {
|
||||
RegisterDecls R(getAnalysisData());
|
||||
cfg.VisitBlockStmts(R);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN TransferFuncs
|
||||
: public CFGStmtVisitor<TransferFuncs,bool> {
|
||||
|
||||
UninitializedValues::ValTy V;
|
||||
UninitializedValues::AnalysisDataTy& AD;
|
||||
public:
|
||||
TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {
|
||||
V.resetValues(AD);
|
||||
}
|
||||
|
||||
UninitializedValues::ValTy& getVal() { return V; }
|
||||
CFG& getCFG() { return AD.getCFG(); }
|
||||
|
||||
bool VisitDeclRefExpr(DeclRefExpr* DR);
|
||||
bool VisitBinaryOperator(BinaryOperator* B);
|
||||
bool VisitUnaryOperator(UnaryOperator* U);
|
||||
bool VisitStmt(Stmt* S);
|
||||
bool VisitCallExpr(CallExpr* C);
|
||||
bool VisitDeclStmt(DeclStmt* D);
|
||||
bool VisitConditionalOperator(ConditionalOperator* C);
|
||||
|
||||
bool Visit(Stmt *S);
|
||||
bool BlockStmt_VisitExpr(Expr* E);
|
||||
|
||||
BlockVarDecl* FindBlockVarDecl(Stmt* S);
|
||||
};
|
||||
|
||||
static const bool Initialized = true;
|
||||
static const bool Uninitialized = false;
|
||||
|
||||
bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
|
||||
if (BlockVarDecl* VD = dyn_cast<BlockVarDecl>(DR->getDecl())) {
|
||||
if (AD.Observer) AD.Observer->ObserveDeclRefExpr(V,AD,DR,VD);
|
||||
|
||||
// Pseudo-hack to prevent cascade of warnings. If an accessed variable
|
||||
// is uninitialized, then we are already going to flag a warning for
|
||||
// this variable, which a "source" of uninitialized values.
|
||||
// We can otherwise do a full "taint" of uninitialized values. The
|
||||
// client has both options by toggling AD.FullUninitTaint.
|
||||
|
||||
return AD.FullUninitTaint ? V(VD,AD) : Initialized;
|
||||
}
|
||||
else return Initialized;
|
||||
}
|
||||
|
||||
BlockVarDecl* TransferFuncs::FindBlockVarDecl(Stmt *S) {
|
||||
for (;;)
|
||||
if (ParenExpr* P = dyn_cast<ParenExpr>(S)) {
|
||||
S = P->getSubExpr(); continue;
|
||||
}
|
||||
else if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(S)) {
|
||||
if (BlockVarDecl* VD = dyn_cast<BlockVarDecl>(DR->getDecl()))
|
||||
return VD;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
|
||||
if (BlockVarDecl* VD = FindBlockVarDecl(B->getLHS()))
|
||||
if (B->isAssignmentOp()) {
|
||||
if (B->getOpcode() == BinaryOperator::Assign)
|
||||
return V(VD,AD) = Visit(B->getRHS());
|
||||
else // Handle +=, -=, *=, etc. We do want '&', not '&&'.
|
||||
return V(VD,AD) = Visit(B->getLHS()) & Visit(B->getRHS());
|
||||
}
|
||||
|
||||
return VisitStmt(B);
|
||||
}
|
||||
|
||||
bool TransferFuncs::VisitDeclStmt(DeclStmt* S) {
|
||||
for (ScopedDecl* D = S->getDecl(); D != NULL; D = D->getNextDeclarator())
|
||||
if (BlockVarDecl* VD = dyn_cast<BlockVarDecl>(D)) {
|
||||
if (Stmt* I = VD->getInit())
|
||||
V(VD,AD) = AD.FullUninitTaint ? V(cast<Expr>(I),AD) : Initialized;
|
||||
else {
|
||||
// Special case for declarations of array types. For things like:
|
||||
//
|
||||
// char x[10];
|
||||
//
|
||||
// we should treat "x" as being initialized, because the variable
|
||||
// "x" really refers to the memory block. Clearly x[1] is
|
||||
// uninitialized, but expressions like "(char *) x" really do refer to
|
||||
// an initialized value. This simple dataflow analysis does not reason
|
||||
// about the contents of arrays, although it could be potentially
|
||||
// extended to do so if the array were of constant size.
|
||||
if (VD->getType()->isArrayType())
|
||||
V(VD,AD) = Initialized;
|
||||
else
|
||||
V(VD,AD) = Uninitialized;
|
||||
}
|
||||
}
|
||||
|
||||
return Uninitialized; // Value is never consumed.
|
||||
}
|
||||
|
||||
bool TransferFuncs::VisitCallExpr(CallExpr* C) {
|
||||
VisitChildren(C);
|
||||
return Initialized;
|
||||
}
|
||||
|
||||
bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
|
||||
switch (U->getOpcode()) {
|
||||
case UnaryOperator::AddrOf:
|
||||
if (BlockVarDecl* VD = FindBlockVarDecl(U->getSubExpr()))
|
||||
return V(VD,AD) = Initialized;
|
||||
|
||||
break;
|
||||
|
||||
case UnaryOperator::SizeOf:
|
||||
return Initialized;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Visit(U->getSubExpr());
|
||||
}
|
||||
|
||||
bool TransferFuncs::VisitConditionalOperator(ConditionalOperator* C) {
|
||||
Visit(C->getCond());
|
||||
|
||||
bool rhsResult = Visit(C->getRHS());
|
||||
// Handle the GNU extension for missing LHS.
|
||||
if (Expr *lhs = C->getLHS())
|
||||
return Visit(lhs) & rhsResult; // Yes: we want &, not &&.
|
||||
else
|
||||
return rhsResult;
|
||||
}
|
||||
|
||||
bool TransferFuncs::VisitStmt(Stmt* S) {
|
||||
bool x = Initialized;
|
||||
|
||||
// We don't stop at the first subexpression that is Uninitialized because
|
||||
// evaluating some subexpressions may result in propogating "Uninitialized"
|
||||
// or "Initialized" to variables referenced in the other subexpressions.
|
||||
for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
|
||||
if (*I && Visit(*I) == Uninitialized) x = Uninitialized;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
bool TransferFuncs::Visit(Stmt *S) {
|
||||
if (AD.isTracked(static_cast<Expr*>(S))) return V(static_cast<Expr*>(S),AD);
|
||||
else return static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(S);
|
||||
}
|
||||
|
||||
bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) {
|
||||
assert (AD.isTracked(E));
|
||||
return V(E,AD) =
|
||||
static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(E);
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Merge operator.
|
||||
//
|
||||
// In our transfer functions we take the approach that any
|
||||
// combination of unintialized values, e.g. Unitialized + ___ = Unitialized.
|
||||
//
|
||||
// Merges take the opposite approach.
|
||||
//
|
||||
// In the merge of dataflow values we prefer unsoundness, and
|
||||
// prefer false negatives to false positives. At merges, if a value for a
|
||||
// tracked Decl is EVER initialized in any of the predecessors we treat it as
|
||||
// initialized at the confluence point.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
typedef ExprDeclBitVector_Types::Union Merge;
|
||||
typedef DataflowSolver<UninitializedValues,TransferFuncs,Merge> Solver;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Unitialized values checker. Scan an AST and flag variable uses
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {}
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN UninitializedValuesChecker
|
||||
: public UninitializedValues::ObserverTy {
|
||||
|
||||
ASTContext &Ctx;
|
||||
Diagnostic &Diags;
|
||||
llvm::SmallPtrSet<BlockVarDecl*,10> AlreadyWarned;
|
||||
|
||||
public:
|
||||
UninitializedValuesChecker(ASTContext &ctx, Diagnostic &diags)
|
||||
: Ctx(ctx), Diags(diags) {}
|
||||
|
||||
virtual void ObserveDeclRefExpr(UninitializedValues::ValTy& V,
|
||||
UninitializedValues::AnalysisDataTy& AD,
|
||||
DeclRefExpr* DR, BlockVarDecl* VD) {
|
||||
|
||||
assert ( AD.isTracked(VD) && "Unknown VarDecl.");
|
||||
|
||||
if (V(VD,AD) == Uninitialized)
|
||||
if (AlreadyWarned.insert(VD))
|
||||
Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()),
|
||||
diag::warn_uninit_val);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace clang {
|
||||
void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags,
|
||||
bool FullUninitTaint) {
|
||||
|
||||
// Compute the unitialized values information.
|
||||
UninitializedValues U(cfg);
|
||||
U.getAnalysisData().FullUninitTaint = FullUninitTaint;
|
||||
Solver S(U);
|
||||
S.runOnCFG(cfg);
|
||||
|
||||
// Scan for DeclRefExprs that use uninitialized values.
|
||||
UninitializedValuesChecker Observer(Ctx,Diags);
|
||||
U.getAnalysisData().Observer = &Observer;
|
||||
S.runOnAllBlocks(cfg);
|
||||
}
|
||||
} // end namespace clang
|
||||
@@ -1,225 +0,0 @@
|
||||
//===--- Diagnostic.cpp - C Language Family Diagnostic Handling -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Builtin Diagnostic information
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Flag values for diagnostics.
|
||||
enum {
|
||||
// Diagnostic classes.
|
||||
NOTE = 0x01,
|
||||
WARNING = 0x02,
|
||||
EXTENSION = 0x03,
|
||||
ERROR = 0x04,
|
||||
class_mask = 0x07
|
||||
};
|
||||
|
||||
/// DiagnosticFlags - A set of flags, or'd together, that describe the
|
||||
/// diagnostic.
|
||||
static unsigned char DiagnosticFlags[] = {
|
||||
#define DIAG(ENUM,FLAGS,DESC) FLAGS,
|
||||
#include "clang/Basic/DiagnosticKinds.def"
|
||||
0
|
||||
};
|
||||
|
||||
/// getDiagClass - Return the class field of the diagnostic.
|
||||
///
|
||||
static unsigned getBuiltinDiagClass(unsigned DiagID) {
|
||||
assert(DiagID < diag::NUM_BUILTIN_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
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Custom Diagnostic information
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
class CustomDiagInfo {
|
||||
typedef std::pair<Diagnostic::Level, std::string> DiagDesc;
|
||||
std::vector<DiagDesc> DiagInfo;
|
||||
std::map<DiagDesc, unsigned> DiagIDs;
|
||||
public:
|
||||
|
||||
/// getDescription - Return the description of the specified custom
|
||||
/// diagnostic.
|
||||
const char *getDescription(unsigned DiagID) const {
|
||||
assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() &&
|
||||
"Invalid diagnosic ID");
|
||||
return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].second.c_str();
|
||||
}
|
||||
|
||||
/// getLevel - Return the level of the specified custom diagnostic.
|
||||
Diagnostic::Level getLevel(unsigned DiagID) const {
|
||||
assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() &&
|
||||
"Invalid diagnosic ID");
|
||||
return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].first;
|
||||
}
|
||||
|
||||
unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message) {
|
||||
DiagDesc D(L, Message);
|
||||
// Check to see if it already exists.
|
||||
std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
|
||||
if (I != DiagIDs.end() && I->first == D)
|
||||
return I->second;
|
||||
|
||||
// If not, assign a new ID.
|
||||
unsigned ID = DiagInfo.size()+diag::NUM_BUILTIN_DIAGNOSTICS;
|
||||
DiagIDs.insert(std::make_pair(D, ID));
|
||||
DiagInfo.push_back(D);
|
||||
return ID;
|
||||
}
|
||||
};
|
||||
|
||||
} // end diag namespace
|
||||
} // end clang namespace
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Common Diagnostic implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
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;
|
||||
CustomDiagInfo = 0;
|
||||
}
|
||||
|
||||
Diagnostic::~Diagnostic() {
|
||||
delete CustomDiagInfo;
|
||||
}
|
||||
|
||||
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
|
||||
/// and level. If this is the first request for this diagnosic, it is
|
||||
/// registered and created, otherwise the existing ID is returned.
|
||||
unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) {
|
||||
if (CustomDiagInfo == 0)
|
||||
CustomDiagInfo = new diag::CustomDiagInfo();
|
||||
return CustomDiagInfo->getOrCreateDiagID(L, Message);
|
||||
}
|
||||
|
||||
|
||||
/// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic
|
||||
/// level of the specified diagnostic ID is a Note, Warning, or Extension.
|
||||
/// Note that this only works on builtin diagnostics, not custom ones.
|
||||
bool Diagnostic::isBuiltinNoteWarningOrExtension(unsigned DiagID) {
|
||||
return DiagID < diag::NUM_BUILTIN_DIAGNOSTICS &&
|
||||
getBuiltinDiagClass(DiagID) < ERROR;
|
||||
}
|
||||
|
||||
|
||||
/// getDescription - Given a diagnostic ID, return a description of the
|
||||
/// issue.
|
||||
const char *Diagnostic::getDescription(unsigned DiagID) {
|
||||
if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS)
|
||||
return DiagnosticText[DiagID];
|
||||
else
|
||||
return CustomDiagInfo->getDescription(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 {
|
||||
// Handle custom diagnostics, which cannot be mapped.
|
||||
if (DiagID >= diag::NUM_BUILTIN_DIAGNOSTICS)
|
||||
return CustomDiagInfo->getLevel(DiagID);
|
||||
|
||||
unsigned DiagClass = getBuiltinDiagClass(DiagID);
|
||||
|
||||
// Specific non-error diagnostics may be mapped to various levels from ignored
|
||||
// to error.
|
||||
if (DiagClass < ERROR) {
|
||||
switch (getDiagnosticMapping((diag::kind)DiagID)) {
|
||||
case diag::MAP_DEFAULT: break;
|
||||
case diag::MAP_IGNORE: return Ignored;
|
||||
case diag::MAP_WARNING: DiagClass = WARNING; break;
|
||||
case diag::MAP_ERROR: DiagClass = ERROR; break;
|
||||
}
|
||||
}
|
||||
|
||||
// Map diagnostic classes based on command line argument settings.
|
||||
if (DiagClass == EXTENSION) {
|
||||
if (ErrorOnExtensions)
|
||||
DiagClass = ERROR;
|
||||
else if (WarnOnExtensions)
|
||||
DiagClass = WARNING;
|
||||
else
|
||||
return Ignored;
|
||||
}
|
||||
|
||||
// If warnings are to be treated as errors, indicate this as such.
|
||||
if (DiagClass == WARNING && WarningsAsErrors)
|
||||
DiagClass = ERROR;
|
||||
|
||||
switch (DiagClass) {
|
||||
default: assert(0 && "Unknown diagnostic class!");
|
||||
case NOTE: return Diagnostic::Note;
|
||||
case WARNING: return Diagnostic::Warning;
|
||||
case ERROR: return Diagnostic::Error;
|
||||
}
|
||||
}
|
||||
|
||||
/// Report - Issue the message to the client. If the client wants us to stop
|
||||
/// compilation, return true, otherwise return false. DiagID is a member of
|
||||
/// the diag::kind enum.
|
||||
void Diagnostic::Report(FullSourceLoc 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(*this, DiagLevel, Pos, (diag::kind)DiagID,
|
||||
Strs, NumStrs, Ranges, NumRanges);
|
||||
++NumDiagnostics;
|
||||
}
|
||||
|
||||
DiagnosticClient::~DiagnosticClient() {}
|
||||
@@ -1,177 +0,0 @@
|
||||
///===--- FileManager.cpp - File System Probing and Caching ----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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 "llvm/Bitcode/Serialize.h"
|
||||
#include "llvm/Bitcode/Deserialize.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
using namespace clang;
|
||||
|
||||
// FIXME: Enhance libsystem to support inode and other fields.
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define S_ISDIR(s) (_S_IFDIR & s)
|
||||
#endif
|
||||
|
||||
/// NON_EXISTENT_DIR - A special value distinct from null that is used to
|
||||
/// represent a dir name that doesn't exist on the disk.
|
||||
#define NON_EXISTENT_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_EXISTENT_DIR
|
||||
? 0 : NamedDirEnt.getValue();
|
||||
|
||||
++NumDirCacheMisses;
|
||||
|
||||
// By default, initialize it to invalid.
|
||||
NamedDirEnt.setValue(NON_EXISTENT_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_EXISTENT_FILE - A special value distinct from null that is used to
|
||||
/// represent a filename that doesn't exist on the disk.
|
||||
#define NON_EXISTENT_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_EXISTENT_FILE
|
||||
? 0 : NamedFileEnt.getValue();
|
||||
|
||||
++NumFileCacheMisses;
|
||||
|
||||
// By default, initialize it to invalid.
|
||||
NamedFileEnt.setValue(NON_EXISTENT_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;
|
||||
//llvm::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.
|
||||
//llvm::cerr << ": Not existing\n";
|
||||
return 0;
|
||||
}
|
||||
//llvm::cerr << ": exists\n";
|
||||
|
||||
// It exists. See if we have already opened a file with the same inode.
|
||||
// This occurs when one dir is symlinked to another, for example.
|
||||
FileEntry &UFE =
|
||||
const_cast<FileEntry&>(*UniqueFiles.insert(FileEntry(StatBuf.st_dev,
|
||||
StatBuf.st_ino)).first);
|
||||
|
||||
|
||||
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 {
|
||||
llvm::cerr << "\n*** File Manager Stats:\n";
|
||||
llvm::cerr << UniqueFiles.size() << " files found, "
|
||||
<< UniqueDirs.size() << " dirs found.\n";
|
||||
llvm::cerr << NumDirLookups << " dir lookups, "
|
||||
<< NumDirCacheMisses << " dir cache misses.\n";
|
||||
llvm::cerr << NumFileLookups << " file lookups, "
|
||||
<< NumFileCacheMisses << " file cache misses.\n";
|
||||
|
||||
//llvm::cerr << PagesMapped << BytesOfPagesMapped << FSLookups;
|
||||
}
|
||||
@@ -1,557 +0,0 @@
|
||||
//===--- IdentifierTable.cpp - Hash table for identifier lookup -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Bitcode/Serialize.h"
|
||||
#include "llvm/Bitcode/Deserialize.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// IdentifierInfo Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
IdentifierInfo::IdentifierInfo() {
|
||||
TokenID = tok::identifier;
|
||||
ObjCID = tok::objc_not_keyword;
|
||||
BuiltinID = 0;
|
||||
HasMacro = false;
|
||||
IsExtension = false;
|
||||
IsPoisoned = false;
|
||||
IsOtherTargetMacro = false;
|
||||
IsCPPOperatorKeyword = false;
|
||||
IsNonPortableBuiltin = false;
|
||||
FETokenInfo = 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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);
|
||||
}
|
||||
|
||||
// This cstor is intended to be used only for serialization.
|
||||
IdentifierTable::IdentifierTable() : HashTable(8192) {}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Language Keyword Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// AddKeyword - This method is used to associate a token ID with specific
|
||||
/// identifiers because they are language keywords. This causes the lexer to
|
||||
/// automatically map matching identifiers to specialized token codes.
|
||||
///
|
||||
/// The C90/C99/CPP/CPP0x flags are set to 0 if the token should be
|
||||
/// enabled in the specified langauge, set to 1 if it is an extension
|
||||
/// in the specified language, and set to 2 if disabled in the
|
||||
/// specified language.
|
||||
static void AddKeyword(const char *Keyword, unsigned KWLen,
|
||||
tok::TokenKind TokenCode,
|
||||
int C90, int C99, int CXX, int CXX0x, int BoolSupport,
|
||||
const LangOptions &LangOpts, IdentifierTable &Table) {
|
||||
int Flags = 0;
|
||||
if (BoolSupport != 0) {
|
||||
Flags = LangOpts.Boolean ? BoolSupport : 2;
|
||||
} else if (LangOpts.CPlusPlus) {
|
||||
Flags = LangOpts.CPlusPlus0x ? CXX0x : CXX;
|
||||
} else if (LangOpts.C99) {
|
||||
Flags = C99;
|
||||
} else {
|
||||
Flags = 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());
|
||||
}
|
||||
|
||||
/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative
|
||||
/// representations.
|
||||
static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen,
|
||||
tok::TokenKind TokenCode,
|
||||
IdentifierTable &Table) {
|
||||
IdentifierInfo &Info = Table.get(Keyword, Keyword + KWLen);
|
||||
Info.setTokenID(TokenCode);
|
||||
Info.setIsCPlusPlusOperatorKeyword();
|
||||
}
|
||||
|
||||
/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or
|
||||
/// "property".
|
||||
static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID,
|
||||
const char *Name, unsigned NameLen,
|
||||
IdentifierTable &Table) {
|
||||
Table.get(Name, Name+NameLen).setObjCKeywordID(ObjCID);
|
||||
}
|
||||
|
||||
/// AddKeywords - Add all keywords to the symbol table.
|
||||
///
|
||||
void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
|
||||
enum {
|
||||
C90Shift = 0,
|
||||
EXTC90 = 1 << C90Shift,
|
||||
NOTC90 = 2 << C90Shift,
|
||||
C99Shift = 2,
|
||||
EXTC99 = 1 << C99Shift,
|
||||
NOTC99 = 2 << C99Shift,
|
||||
CPPShift = 4,
|
||||
EXTCPP = 1 << CPPShift,
|
||||
NOTCPP = 2 << CPPShift,
|
||||
CPP0xShift = 6,
|
||||
EXTCPP0x = 1 << CPP0xShift,
|
||||
NOTCPP0x = 2 << CPP0xShift,
|
||||
BoolShift = 8,
|
||||
BOOLSUPPORT = 1 << BoolShift,
|
||||
Mask = 3
|
||||
};
|
||||
|
||||
// Add keywords and tokens for the current language.
|
||||
#define KEYWORD(NAME, FLAGS) \
|
||||
AddKeyword(#NAME, strlen(#NAME), tok::kw_ ## NAME, \
|
||||
((FLAGS) >> C90Shift) & Mask, \
|
||||
((FLAGS) >> C99Shift) & Mask, \
|
||||
((FLAGS) >> CPPShift) & Mask, \
|
||||
((FLAGS) >> CPP0xShift) & Mask, \
|
||||
((FLAGS) >> BoolShift) & Mask, LangOpts, *this);
|
||||
#define ALIAS(NAME, TOK) \
|
||||
AddAlias(NAME, strlen(NAME), #TOK, strlen(#TOK), LangOpts, *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"
|
||||
}
|
||||
|
||||
tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
|
||||
// We use a perfect hash function here involving the length of the keyword,
|
||||
// the first and third character. For preprocessor ID's there are no
|
||||
// collisions (if there were, the switch below would complain about duplicate
|
||||
// case values). Note that this depends on 'if' being null terminated.
|
||||
|
||||
#define HASH(LEN, FIRST, THIRD) \
|
||||
(LEN << 5) + (((FIRST-'a') + (THIRD-'a')) & 31)
|
||||
#define CASE(LEN, FIRST, THIRD, NAME) \
|
||||
case HASH(LEN, FIRST, THIRD): \
|
||||
return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME
|
||||
|
||||
unsigned Len = getLength();
|
||||
if (Len < 2) return tok::pp_not_keyword;
|
||||
const char *Name = getName();
|
||||
switch (HASH(Len, Name[0], Name[2])) {
|
||||
default: return tok::pp_not_keyword;
|
||||
CASE( 2, 'i', '\0', if);
|
||||
CASE( 4, 'e', 'i', elif);
|
||||
CASE( 4, 'e', 's', else);
|
||||
CASE( 4, 'l', 'n', line);
|
||||
CASE( 4, 's', 'c', sccs);
|
||||
CASE( 5, 'e', 'd', endif);
|
||||
CASE( 5, 'e', 'r', error);
|
||||
CASE( 5, 'i', 'e', ident);
|
||||
CASE( 5, 'i', 'd', ifdef);
|
||||
CASE( 5, 'u', 'd', undef);
|
||||
|
||||
CASE( 6, 'a', 's', assert);
|
||||
CASE( 6, 'd', 'f', define);
|
||||
CASE( 6, 'i', 'n', ifndef);
|
||||
CASE( 6, 'i', 'p', import);
|
||||
CASE( 6, 'p', 'a', pragma);
|
||||
|
||||
CASE( 7, 'd', 'f', defined);
|
||||
CASE( 7, 'i', 'c', include);
|
||||
CASE( 7, 'w', 'r', warning);
|
||||
|
||||
CASE( 8, 'u', 'a', unassert);
|
||||
CASE(12, 'i', 'c', include_next);
|
||||
CASE(13, 'd', 'f', define_target);
|
||||
CASE(19, 'd', 'f', define_other_target);
|
||||
#undef CASE
|
||||
#undef HASH
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SelectorTable Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
unsigned llvm::DenseMapInfo<clang::Selector>::getHashValue(clang::Selector S) {
|
||||
return DenseMapInfo<void*>::getHashValue(S.getAsOpaquePtr());
|
||||
}
|
||||
|
||||
|
||||
/// MultiKeywordSelector - One of these variable length records is kept for each
|
||||
/// selector containing more than one keyword. We use a folding set
|
||||
/// to unique aggregate names (keyword selectors in ObjC parlance). Access to
|
||||
/// this class is provided strictly through Selector.
|
||||
namespace clang {
|
||||
class MultiKeywordSelector : public llvm::FoldingSetNode {
|
||||
friend SelectorTable* SelectorTable::CreateAndRegister(llvm::Deserializer&);
|
||||
MultiKeywordSelector(unsigned nKeys) : NumArgs(nKeys) {}
|
||||
public:
|
||||
unsigned NumArgs;
|
||||
|
||||
// Constructor for keyword selectors.
|
||||
MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) {
|
||||
assert((nKeys > 1) && "not a multi-keyword selector");
|
||||
NumArgs = nKeys;
|
||||
|
||||
// Fill in the trailing keyword array.
|
||||
IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(this+1);
|
||||
for (unsigned i = 0; i != nKeys; ++i)
|
||||
KeyInfo[i] = IIV[i];
|
||||
}
|
||||
|
||||
// getName - Derive the full selector name and return it.
|
||||
std::string getName() const;
|
||||
|
||||
unsigned getNumArgs() const { return NumArgs; }
|
||||
|
||||
typedef IdentifierInfo *const *keyword_iterator;
|
||||
keyword_iterator keyword_begin() const {
|
||||
return reinterpret_cast<keyword_iterator>(this+1);
|
||||
}
|
||||
keyword_iterator keyword_end() const {
|
||||
return keyword_begin()+NumArgs;
|
||||
}
|
||||
IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const {
|
||||
assert(i < NumArgs && "getIdentifierInfoForSlot(): illegal index");
|
||||
return keyword_begin()[i];
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
keyword_iterator ArgTys, unsigned NumArgs) {
|
||||
ID.AddInteger(NumArgs);
|
||||
for (unsigned i = 0; i != NumArgs; ++i)
|
||||
ID.AddPointer(ArgTys[i]);
|
||||
}
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, keyword_begin(), NumArgs);
|
||||
}
|
||||
};
|
||||
} // end namespace clang.
|
||||
|
||||
unsigned Selector::getNumArgs() const {
|
||||
unsigned IIF = getIdentifierInfoFlag();
|
||||
if (IIF == ZeroArg)
|
||||
return 0;
|
||||
if (IIF == OneArg)
|
||||
return 1;
|
||||
// We point to a MultiKeywordSelector (pointer doesn't contain any flags).
|
||||
MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
|
||||
return SI->getNumArgs();
|
||||
}
|
||||
|
||||
IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const {
|
||||
if (IdentifierInfo *II = getAsIdentifierInfo()) {
|
||||
assert(argIndex == 0 && "illegal keyword index");
|
||||
return II;
|
||||
}
|
||||
// We point to a MultiKeywordSelector (pointer doesn't contain any flags).
|
||||
MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
|
||||
return SI->getIdentifierInfoForSlot(argIndex);
|
||||
}
|
||||
|
||||
std::string MultiKeywordSelector::getName() const {
|
||||
std::string Result;
|
||||
unsigned Length = 0;
|
||||
for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) {
|
||||
if (*I)
|
||||
Length += (*I)->getLength();
|
||||
++Length; // :
|
||||
}
|
||||
|
||||
Result.reserve(Length);
|
||||
|
||||
for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) {
|
||||
if (*I)
|
||||
Result.insert(Result.end(), (*I)->getName(),
|
||||
(*I)->getName()+(*I)->getLength());
|
||||
Result.push_back(':');
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string Selector::getName() const {
|
||||
if (IdentifierInfo *II = getAsIdentifierInfo()) {
|
||||
if (getNumArgs() == 0)
|
||||
return II->getName();
|
||||
|
||||
std::string Res = II->getName();
|
||||
Res += ":";
|
||||
return Res;
|
||||
}
|
||||
|
||||
// We have a multiple keyword selector (no embedded flags).
|
||||
return reinterpret_cast<MultiKeywordSelector *>(InfoPtr)->getName();
|
||||
}
|
||||
|
||||
|
||||
Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) {
|
||||
if (nKeys < 2)
|
||||
return Selector(IIV[0], nKeys);
|
||||
|
||||
llvm::FoldingSet<MultiKeywordSelector> *SelTab;
|
||||
|
||||
SelTab = static_cast<llvm::FoldingSet<MultiKeywordSelector> *>(Impl);
|
||||
|
||||
// Unique selector, to guarantee there is one per name.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
MultiKeywordSelector::Profile(ID, IIV, nKeys);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (MultiKeywordSelector *SI = SelTab->FindNodeOrInsertPos(ID, InsertPos))
|
||||
return Selector(SI);
|
||||
|
||||
// MultiKeywordSelector objects are not allocated with new because they have a
|
||||
// variable size array (for parameter types) at the end of them.
|
||||
MultiKeywordSelector *SI =
|
||||
(MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) +
|
||||
nKeys*sizeof(IdentifierInfo *));
|
||||
new (SI) MultiKeywordSelector(nKeys, IIV);
|
||||
SelTab->InsertNode(SI, InsertPos);
|
||||
return Selector(SI);
|
||||
}
|
||||
|
||||
SelectorTable::SelectorTable() {
|
||||
Impl = new llvm::FoldingSet<MultiKeywordSelector>;
|
||||
}
|
||||
|
||||
SelectorTable::~SelectorTable() {
|
||||
delete static_cast<llvm::FoldingSet<MultiKeywordSelector> *>(Impl);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Serialization for IdentifierInfo and IdentifierTable.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void IdentifierInfo::Emit(llvm::Serializer& S) const {
|
||||
S.EmitInt(getTokenID());
|
||||
S.EmitInt(getBuiltinID());
|
||||
S.EmitInt(getObjCKeywordID());
|
||||
S.EmitBool(hasMacroDefinition());
|
||||
S.EmitBool(isExtensionToken());
|
||||
S.EmitBool(isPoisoned());
|
||||
S.EmitBool(isOtherTargetMacro());
|
||||
S.EmitBool(isCPlusPlusOperatorKeyword());
|
||||
S.EmitBool(isNonPortableBuiltin());
|
||||
// FIXME: FETokenInfo
|
||||
}
|
||||
|
||||
void IdentifierInfo::Read(llvm::Deserializer& D) {
|
||||
setTokenID((tok::TokenKind) D.ReadInt());
|
||||
setBuiltinID(D.ReadInt());
|
||||
setObjCKeywordID((tok::ObjCKeywordKind) D.ReadInt());
|
||||
setHasMacroDefinition(D.ReadBool());
|
||||
setIsExtensionToken(D.ReadBool());
|
||||
setIsPoisoned(D.ReadBool());
|
||||
setIsOtherTargetMacro(D.ReadBool());
|
||||
setIsCPlusPlusOperatorKeyword(D.ReadBool());
|
||||
setNonPortableBuiltin(D.ReadBool());
|
||||
// FIXME: FETokenInfo
|
||||
}
|
||||
|
||||
void IdentifierTable::Emit(llvm::Serializer& S) const {
|
||||
S.EnterBlock();
|
||||
|
||||
S.EmitPtr(this);
|
||||
|
||||
for (iterator I=begin(), E=end(); I != E; ++I) {
|
||||
const char* Key = I->getKeyData();
|
||||
const IdentifierInfo* Info = &I->getValue();
|
||||
|
||||
bool KeyRegistered = S.isRegistered(Key);
|
||||
bool InfoRegistered = S.isRegistered(Info);
|
||||
|
||||
if (KeyRegistered || InfoRegistered) {
|
||||
// These acrobatics are so that we don't incur the cost of registering
|
||||
// a pointer with the backpatcher during deserialization if nobody
|
||||
// references the object.
|
||||
S.EmitPtr(InfoRegistered ? Info : NULL);
|
||||
S.EmitPtr(KeyRegistered ? Key : NULL);
|
||||
S.EmitCStr(Key);
|
||||
S.Emit(*Info);
|
||||
}
|
||||
}
|
||||
|
||||
S.ExitBlock();
|
||||
}
|
||||
|
||||
IdentifierTable* IdentifierTable::CreateAndRegister(llvm::Deserializer& D) {
|
||||
llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation();
|
||||
|
||||
std::vector<char> buff;
|
||||
buff.reserve(200);
|
||||
|
||||
IdentifierTable* t = new IdentifierTable();
|
||||
D.RegisterPtr(t);
|
||||
|
||||
while (!D.FinishedBlock(BLoc)) {
|
||||
llvm::SerializedPtrID InfoPtrID = D.ReadPtrID();
|
||||
llvm::SerializedPtrID KeyPtrID = D.ReadPtrID();
|
||||
|
||||
D.ReadCStr(buff);
|
||||
|
||||
llvm::StringMapEntry<IdentifierInfo>& Entry =
|
||||
t->HashTable.GetOrCreateValue(&buff[0],&buff[0]+buff.size());
|
||||
|
||||
D.Read(Entry.getValue());
|
||||
|
||||
if (InfoPtrID)
|
||||
D.RegisterRef(InfoPtrID,Entry.getValue());
|
||||
|
||||
if (KeyPtrID)
|
||||
D.RegisterPtr(KeyPtrID,Entry.getKeyData());
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Serialization for Selector and SelectorTable.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void Selector::Emit(llvm::Serializer& S) const {
|
||||
S.EmitInt(getIdentifierInfoFlag());
|
||||
S.EmitPtr(reinterpret_cast<void*>(InfoPtr & ~ArgFlags));
|
||||
}
|
||||
|
||||
Selector Selector::ReadVal(llvm::Deserializer& D) {
|
||||
unsigned flag = D.ReadInt();
|
||||
|
||||
uintptr_t ptr;
|
||||
D.ReadUIntPtr(ptr,false); // No backpatching.
|
||||
|
||||
return Selector(ptr | flag);
|
||||
}
|
||||
|
||||
void SelectorTable::Emit(llvm::Serializer& S) const {
|
||||
typedef llvm::FoldingSet<MultiKeywordSelector>::iterator iterator;
|
||||
llvm::FoldingSet<MultiKeywordSelector> *SelTab;
|
||||
SelTab = static_cast<llvm::FoldingSet<MultiKeywordSelector> *>(Impl);
|
||||
|
||||
S.EnterBlock();
|
||||
|
||||
S.EmitPtr(this);
|
||||
|
||||
for (iterator I=SelTab->begin(), E=SelTab->end(); I != E; ++I) {
|
||||
if (!S.isRegistered(&*I))
|
||||
continue;
|
||||
|
||||
S.FlushRecord(); // Start a new record.
|
||||
|
||||
S.EmitPtr(&*I);
|
||||
S.EmitInt(I->getNumArgs());
|
||||
|
||||
for (MultiKeywordSelector::keyword_iterator KI = I->keyword_begin(),
|
||||
KE = I->keyword_end(); KI != KE; ++KI)
|
||||
S.EmitPtr(*KI);
|
||||
}
|
||||
|
||||
S.ExitBlock();
|
||||
}
|
||||
|
||||
SelectorTable* SelectorTable::CreateAndRegister(llvm::Deserializer& D) {
|
||||
llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation();
|
||||
|
||||
SelectorTable* t = new SelectorTable();
|
||||
D.RegisterPtr(t);
|
||||
|
||||
llvm::FoldingSet<MultiKeywordSelector>& SelTab =
|
||||
*static_cast<llvm::FoldingSet<MultiKeywordSelector>*>(t->Impl);
|
||||
|
||||
while (!D.FinishedBlock(BLoc)) {
|
||||
|
||||
llvm::SerializedPtrID PtrID = D.ReadPtrID();
|
||||
unsigned nKeys = D.ReadInt();
|
||||
|
||||
MultiKeywordSelector *SI =
|
||||
(MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) +
|
||||
nKeys*sizeof(IdentifierInfo *));
|
||||
|
||||
new (SI) MultiKeywordSelector(nKeys);
|
||||
|
||||
D.RegisterPtr(PtrID,SI);
|
||||
|
||||
IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(SI+1);
|
||||
|
||||
for (unsigned i = 0; i != nKeys; ++i)
|
||||
D.ReadPtr(KeyInfo[i],false);
|
||||
|
||||
SelTab.GetOrInsertNode(SI);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
//===--- LangOptions.cpp - Language feature info --------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the methods for LangOptions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "llvm/Bitcode/Serialize.h"
|
||||
#include "llvm/Bitcode/Deserialize.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
void LangOptions::Emit(llvm::Serializer& S) const {
|
||||
S.EmitBool((bool) Trigraphs);
|
||||
S.EmitBool((bool) BCPLComment);
|
||||
S.EmitBool((bool) DollarIdents);
|
||||
S.EmitBool((bool) Digraphs);
|
||||
S.EmitBool((bool) HexFloats);
|
||||
S.EmitBool((bool) C99);
|
||||
S.EmitBool((bool) Microsoft);
|
||||
S.EmitBool((bool) CPlusPlus);
|
||||
S.EmitBool((bool) CPlusPlus0x);
|
||||
S.EmitBool((bool) NoExtensions);
|
||||
S.EmitBool((bool) CXXOperatorNames);
|
||||
S.EmitBool((bool) ObjC1);
|
||||
S.EmitBool((bool) ObjC2);
|
||||
S.EmitBool((bool) PascalStrings);
|
||||
S.EmitBool((bool) Boolean);
|
||||
S.EmitBool((bool) WritableStrings);
|
||||
S.EmitBool((bool) LaxVectorConversions);
|
||||
}
|
||||
|
||||
void LangOptions::Read(llvm::Deserializer& D) {
|
||||
Trigraphs = D.ReadBool() ? 1 : 0;
|
||||
BCPLComment = D.ReadBool() ? 1 : 0;
|
||||
DollarIdents = D.ReadBool() ? 1 : 0;
|
||||
Digraphs = D.ReadBool() ? 1 : 0;
|
||||
HexFloats = D.ReadBool() ? 1 : 0;
|
||||
C99 = D.ReadBool() ? 1 : 0;
|
||||
Microsoft = D.ReadBool() ? 1 : 0;
|
||||
CPlusPlus = D.ReadBool() ? 1 : 0;
|
||||
CPlusPlus0x = D.ReadBool() ? 1 : 0;
|
||||
NoExtensions = D.ReadBool() ? 1 : 0;
|
||||
CXXOperatorNames = D.ReadBool() ? 1 : 0;
|
||||
ObjC1 = D.ReadBool() ? 1 : 0;
|
||||
ObjC2 = D.ReadBool() ? 1 : 0;
|
||||
PascalStrings = D.ReadBool() ? 1 : 0;
|
||||
Boolean = D.ReadBool() ? 1 : 0;
|
||||
WritableStrings = D.ReadBool() ? 1 : 0;
|
||||
LaxVectorConversions = D.ReadBool() ? 1 : 0;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
##===- clang/Basic/Makefile --------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# This implements the Basic library for the C-Language front-end.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../..
|
||||
LIBRARYNAME := clangBasic
|
||||
BUILD_ARCHIVE = 1
|
||||
CXXFLAGS = -fno-rtti
|
||||
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
//==--- SourceLocation.cpp - Compact identifier for Source Files -*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines serialization methods for the SourceLocation class.
|
||||
// This file defines accessor methods for the FullSourceLoc class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/Bitcode/Serialize.h"
|
||||
#include "llvm/Bitcode/Deserialize.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
void SourceLocation::Emit(llvm::Serializer& S) const {
|
||||
S.EmitInt(getRawEncoding());
|
||||
}
|
||||
|
||||
SourceLocation SourceLocation::ReadVal(llvm::Deserializer& D) {
|
||||
return SourceLocation::getFromRawEncoding(D.ReadInt());
|
||||
}
|
||||
|
||||
void SourceRange::Emit(llvm::Serializer& S) const {
|
||||
B.Emit(S);
|
||||
E.Emit(S);
|
||||
}
|
||||
|
||||
SourceRange SourceRange::ReadVal(llvm::Deserializer& D) {
|
||||
SourceLocation A = SourceLocation::ReadVal(D);
|
||||
SourceLocation B = SourceLocation::ReadVal(D);
|
||||
return SourceRange(A,B);
|
||||
}
|
||||
|
||||
FullSourceLoc FullSourceLoc::getLogicalLoc() {
|
||||
assert (isValid());
|
||||
return FullSourceLoc(SrcMgr->getLogicalLoc(Loc),*SrcMgr);
|
||||
}
|
||||
|
||||
FullSourceLoc FullSourceLoc::getIncludeLoc() {
|
||||
assert (isValid());
|
||||
return FullSourceLoc(SrcMgr->getIncludeLoc(Loc),*SrcMgr);
|
||||
}
|
||||
|
||||
unsigned FullSourceLoc::getLineNumber() {
|
||||
assert (isValid());
|
||||
return SrcMgr->getLineNumber(Loc);
|
||||
}
|
||||
|
||||
unsigned FullSourceLoc::getColumnNumber() {
|
||||
assert (isValid());
|
||||
return SrcMgr->getColumnNumber(Loc);
|
||||
}
|
||||
|
||||
const char* FullSourceLoc::getSourceName() const {
|
||||
assert (isValid());
|
||||
return SrcMgr->getSourceName(Loc);
|
||||
}
|
||||
|
||||
const FileEntry* FullSourceLoc::getFileEntryForLoc() const {
|
||||
assert (isValid());
|
||||
return SrcMgr->getFileEntryForLoc(Loc);
|
||||
}
|
||||
|
||||
const char * FullSourceLoc::getCharacterData() const {
|
||||
assert (isValid());
|
||||
return SrcMgr->getCharacterData(Loc);
|
||||
}
|
||||
|
||||
const llvm::MemoryBuffer* FullSourceLoc::getBuffer() const {
|
||||
assert (isValid());
|
||||
return SrcMgr->getBuffer(Loc.getFileID());
|
||||
}
|
||||
@@ -1,575 +0,0 @@
|
||||
//===--- SourceManager.cpp - Track and cache source files -----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the SourceManager interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include "llvm/Bitcode/Serialize.h"
|
||||
#include "llvm/Bitcode/Deserialize.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include <algorithm>
|
||||
#include <fcntl.h>
|
||||
using namespace clang;
|
||||
using namespace SrcMgr;
|
||||
using llvm::MemoryBuffer;
|
||||
|
||||
ContentCache::~ContentCache() {
|
||||
delete Buffer;
|
||||
delete [] SourceLineCache;
|
||||
}
|
||||
|
||||
// FIXME: REMOVE THESE
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#if !defined(_MSC_VER) && !defined(__MINGW32__)
|
||||
#include <sys/uio.h>
|
||||
#include <sys/fcntl.h>
|
||||
#else
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <cerrno>
|
||||
|
||||
static const MemoryBuffer *ReadFileFast(const FileEntry *FileEnt) {
|
||||
#if 0
|
||||
// FIXME: Reintroduce this and zap this function once the common llvm stuff
|
||||
// is fast for the small case.
|
||||
return MemoryBuffer::getFile(FileEnt->getName(), strlen(FileEnt->getName()),
|
||||
FileEnt->getSize());
|
||||
#endif
|
||||
|
||||
// If the file is larger than some threshold, use 'read', otherwise use mmap.
|
||||
if (FileEnt->getSize() >= 4096*4)
|
||||
return MemoryBuffer::getFile(FileEnt->getName(), strlen(FileEnt->getName()),
|
||||
0, FileEnt->getSize());
|
||||
|
||||
MemoryBuffer *SB = MemoryBuffer::getNewUninitMemBuffer(FileEnt->getSize(),
|
||||
FileEnt->getName());
|
||||
char *BufPtr = const_cast<char*>(SB->getBufferStart());
|
||||
|
||||
#if defined(LLVM_ON_WIN32)
|
||||
int FD = ::open(FileEnt->getName(), O_RDONLY|O_BINARY);
|
||||
#else
|
||||
int FD = ::open(FileEnt->getName(), O_RDONLY);
|
||||
#endif
|
||||
if (FD == -1) {
|
||||
delete SB;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned BytesLeft = FileEnt->getSize();
|
||||
while (BytesLeft) {
|
||||
ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
|
||||
if (NumRead != -1) {
|
||||
BytesLeft -= NumRead;
|
||||
BufPtr += NumRead;
|
||||
} else if (errno == EINTR) {
|
||||
// try again
|
||||
} else {
|
||||
// error reading.
|
||||
close(FD);
|
||||
delete SB;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
close(FD);
|
||||
|
||||
return SB;
|
||||
}
|
||||
|
||||
|
||||
/// getFileInfo - Create or return a cached FileInfo for the specified file.
|
||||
///
|
||||
const ContentCache* SourceManager::getContentCache(const FileEntry *FileEnt) {
|
||||
|
||||
assert(FileEnt && "Didn't specify a file entry to use?");
|
||||
// Do we already have information about this file?
|
||||
std::set<ContentCache>::iterator I =
|
||||
FileInfos.lower_bound(ContentCache(FileEnt));
|
||||
|
||||
if (I != FileInfos.end() && I->Entry == FileEnt)
|
||||
return &*I;
|
||||
|
||||
// Nope, get information.
|
||||
const MemoryBuffer *File = ReadFileFast(FileEnt);
|
||||
if (File == 0)
|
||||
return 0;
|
||||
|
||||
ContentCache& Entry = const_cast<ContentCache&>(*FileInfos.insert(I,FileEnt));
|
||||
|
||||
Entry.Buffer = File;
|
||||
Entry.SourceLineCache = 0;
|
||||
Entry.NumLines = 0;
|
||||
return &Entry;
|
||||
}
|
||||
|
||||
|
||||
/// createMemBufferContentCache - Create a new ContentCache for the specified
|
||||
/// memory buffer. This does no caching.
|
||||
const ContentCache*
|
||||
SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) {
|
||||
// Add a new ContentCache to the MemBufferInfos list and return it. We
|
||||
// must default construct the object first that the instance actually
|
||||
// stored within MemBufferInfos actually owns the Buffer, and not any
|
||||
// temporary we would use in the call to "push_back".
|
||||
MemBufferInfos.push_back(ContentCache());
|
||||
ContentCache& Entry = const_cast<ContentCache&>(MemBufferInfos.back());
|
||||
Entry.Buffer = Buffer;
|
||||
return &Entry;
|
||||
}
|
||||
|
||||
|
||||
/// createFileID - Create a new fileID for the specified ContentCache and
|
||||
/// include position. This works regardless of whether the ContentCache
|
||||
/// corresponds to a file or some other input source.
|
||||
unsigned SourceManager::createFileID(const ContentCache *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->Buffer->getBufferSize();
|
||||
if (FileSize+1 < (1 << SourceLocation::FilePosBits)) {
|
||||
FileIDs.push_back(FileIDInfo::get(IncludePos, 0, File));
|
||||
assert(FileIDs.size() < (1 << SourceLocation::FileIDBits) &&
|
||||
"Ran out of file ID's!");
|
||||
return FileIDs.size();
|
||||
}
|
||||
|
||||
// Create one FileID for each chunk of the file.
|
||||
unsigned Result = FileIDs.size()+1;
|
||||
|
||||
unsigned ChunkNo = 0;
|
||||
while (1) {
|
||||
FileIDs.push_back(FileIDInfo::get(IncludePos, ChunkNo++, File));
|
||||
|
||||
if (FileSize+1 < (1 << SourceLocation::FilePosBits)) break;
|
||||
FileSize -= (1 << SourceLocation::FilePosBits);
|
||||
}
|
||||
|
||||
assert(FileIDs.size() < (1 << SourceLocation::FileIDBits) &&
|
||||
"Ran out of file ID's!");
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// getInstantiationLoc - Return a new SourceLocation that encodes the fact
|
||||
/// that a token from physloc PhysLoc should actually be referenced from
|
||||
/// InstantiationLoc.
|
||||
SourceLocation SourceManager::getInstantiationLoc(SourceLocation PhysLoc,
|
||||
SourceLocation InstantLoc) {
|
||||
// The specified source location may be a mapped location, due to a macro
|
||||
// instantiation or #line directive. Strip off this information to find out
|
||||
// where the characters are actually located.
|
||||
PhysLoc = getPhysicalLoc(PhysLoc);
|
||||
|
||||
// Resolve InstantLoc down to a real logical location.
|
||||
InstantLoc = getLogicalLoc(InstantLoc);
|
||||
|
||||
|
||||
// If the last macro id is close to the currently requested location, try to
|
||||
// reuse it. This implements a small cache.
|
||||
for (int i = MacroIDs.size()-1, e = MacroIDs.size()-6; i >= 0 && i != e; --i){
|
||||
MacroIDInfo &LastOne = MacroIDs[i];
|
||||
|
||||
// The instanitation point and source physloc have to exactly match to reuse
|
||||
// (for now). We could allow "nearby" instantiations in the future.
|
||||
if (LastOne.getVirtualLoc() != InstantLoc ||
|
||||
LastOne.getPhysicalLoc().getFileID() != PhysLoc.getFileID())
|
||||
continue;
|
||||
|
||||
// Check to see if the physloc of the token came from near enough to reuse.
|
||||
int PhysDelta = PhysLoc.getRawFilePos() -
|
||||
LastOne.getPhysicalLoc().getRawFilePos();
|
||||
if (SourceLocation::isValidMacroPhysOffs(PhysDelta))
|
||||
return SourceLocation::getMacroLoc(i, PhysDelta, false, false);
|
||||
}
|
||||
|
||||
|
||||
MacroIDs.push_back(MacroIDInfo::get(InstantLoc, PhysLoc));
|
||||
return SourceLocation::getMacroLoc(MacroIDs.size()-1, 0, false, false);
|
||||
}
|
||||
|
||||
/// getBufferData - Return a pointer to the start and end of the character
|
||||
/// data for the specified FileID.
|
||||
std::pair<const char*, const char*>
|
||||
SourceManager::getBufferData(unsigned FileID) const {
|
||||
const llvm::MemoryBuffer *Buf = getBuffer(FileID);
|
||||
return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd());
|
||||
}
|
||||
|
||||
|
||||
/// getCharacterData - Return a pointer to the start of the specified location
|
||||
/// in the appropriate MemoryBuffer.
|
||||
const char *SourceManager::getCharacterData(SourceLocation SL) const {
|
||||
// Note that this is a hot function in the getSpelling() path, which is
|
||||
// heavily used by -E mode.
|
||||
SL = getPhysicalLoc(SL);
|
||||
|
||||
return getContentCache(SL.getFileID())->Buffer->getBufferStart() +
|
||||
getFullFilePos(SL);
|
||||
}
|
||||
|
||||
|
||||
/// getColumnNumber - Return the column # for the specified file position.
|
||||
/// this is significantly cheaper to compute than the line number. This returns
|
||||
/// zero if the column number isn't known.
|
||||
unsigned SourceManager::getColumnNumber(SourceLocation Loc) const {
|
||||
unsigned FileID = Loc.getFileID();
|
||||
if (FileID == 0) return 0;
|
||||
|
||||
unsigned FilePos = getFullFilePos(Loc);
|
||||
const MemoryBuffer *Buffer = getBuffer(FileID);
|
||||
const char *Buf = Buffer->getBufferStart();
|
||||
|
||||
unsigned LineStart = FilePos;
|
||||
while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
|
||||
--LineStart;
|
||||
return FilePos-LineStart+1;
|
||||
}
|
||||
|
||||
/// getSourceName - This method returns the name of the file or buffer that
|
||||
/// the SourceLocation specifies. This can be modified with #line directives,
|
||||
/// etc.
|
||||
const char *SourceManager::getSourceName(SourceLocation Loc) const {
|
||||
unsigned FileID = Loc.getFileID();
|
||||
if (FileID == 0) return "";
|
||||
return getContentCache(FileID)->Buffer->getBufferIdentifier();
|
||||
}
|
||||
|
||||
static void ComputeLineNumbers(ContentCache* FI) DISABLE_INLINE;
|
||||
static void ComputeLineNumbers(ContentCache* FI) {
|
||||
const MemoryBuffer *Buffer = FI->Buffer;
|
||||
|
||||
// Find the file offsets of all of the *physical* source lines. This does
|
||||
// not look at trigraphs, escaped newlines, or anything else tricky.
|
||||
std::vector<unsigned> LineOffsets;
|
||||
|
||||
// Line #1 starts at char 0.
|
||||
LineOffsets.push_back(0);
|
||||
|
||||
const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart();
|
||||
const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd();
|
||||
unsigned Offs = 0;
|
||||
while (1) {
|
||||
// Skip over the contents of the line.
|
||||
// TODO: Vectorize this? This is very performance sensitive for programs
|
||||
// with lots of diagnostics and in -E mode.
|
||||
const unsigned char *NextBuf = (const unsigned char *)Buf;
|
||||
while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0')
|
||||
++NextBuf;
|
||||
Offs += NextBuf-Buf;
|
||||
Buf = NextBuf;
|
||||
|
||||
if (Buf[0] == '\n' || Buf[0] == '\r') {
|
||||
// If this is \n\r or \r\n, skip both characters.
|
||||
if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1])
|
||||
++Offs, ++Buf;
|
||||
++Offs, ++Buf;
|
||||
LineOffsets.push_back(Offs);
|
||||
} else {
|
||||
// Otherwise, this is a null. If end of file, exit.
|
||||
if (Buf == End) break;
|
||||
// Otherwise, skip the null.
|
||||
++Offs, ++Buf;
|
||||
}
|
||||
}
|
||||
LineOffsets.push_back(Offs);
|
||||
|
||||
// Copy the offsets into the FileInfo structure.
|
||||
FI->NumLines = LineOffsets.size();
|
||||
FI->SourceLineCache = new unsigned[LineOffsets.size()];
|
||||
std::copy(LineOffsets.begin(), LineOffsets.end(), FI->SourceLineCache);
|
||||
}
|
||||
|
||||
/// getLineNumber - Given a SourceLocation, return the physical line number
|
||||
/// for the position indicated. This requires building and caching a table of
|
||||
/// line offsets for the MemoryBuffer, so this is not cheap: use only when
|
||||
/// about to emit a diagnostic.
|
||||
unsigned SourceManager::getLineNumber(SourceLocation Loc) {
|
||||
unsigned FileID = Loc.getFileID();
|
||||
if (FileID == 0) return 0;
|
||||
|
||||
ContentCache* Content;
|
||||
|
||||
if (LastLineNoFileIDQuery == FileID)
|
||||
Content = LastLineNoContentCache;
|
||||
else
|
||||
Content = const_cast<ContentCache*>(getContentCache(FileID));
|
||||
|
||||
// If this is the first use of line information for this buffer, compute the
|
||||
/// SourceLineCache for it on demand.
|
||||
if (Content->SourceLineCache == 0)
|
||||
ComputeLineNumbers(Content);
|
||||
|
||||
// Okay, we know we have a line number table. Do a binary search to find the
|
||||
// line number that this character position lands on.
|
||||
unsigned *SourceLineCache = Content->SourceLineCache;
|
||||
unsigned *SourceLineCacheStart = SourceLineCache;
|
||||
unsigned *SourceLineCacheEnd = SourceLineCache + Content->NumLines;
|
||||
|
||||
unsigned QueriedFilePos = getFullFilePos(Loc)+1;
|
||||
|
||||
// If the previous query was to the same file, we know both the file pos from
|
||||
// that query and the line number returned. This allows us to narrow the
|
||||
// search space from the entire file to something near the match.
|
||||
if (LastLineNoFileIDQuery == FileID) {
|
||||
if (QueriedFilePos >= LastLineNoFilePos) {
|
||||
SourceLineCache = SourceLineCache+LastLineNoResult-1;
|
||||
|
||||
// The query is likely to be nearby the previous one. Here we check to
|
||||
// see if it is within 5, 10 or 20 lines. It can be far away in cases
|
||||
// where big comment blocks and vertical whitespace eat up lines but
|
||||
// contribute no tokens.
|
||||
if (SourceLineCache+5 < SourceLineCacheEnd) {
|
||||
if (SourceLineCache[5] > QueriedFilePos)
|
||||
SourceLineCacheEnd = SourceLineCache+5;
|
||||
else if (SourceLineCache+10 < SourceLineCacheEnd) {
|
||||
if (SourceLineCache[10] > QueriedFilePos)
|
||||
SourceLineCacheEnd = SourceLineCache+10;
|
||||
else if (SourceLineCache+20 < SourceLineCacheEnd) {
|
||||
if (SourceLineCache[20] > QueriedFilePos)
|
||||
SourceLineCacheEnd = SourceLineCache+20;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1;
|
||||
}
|
||||
}
|
||||
|
||||
// If the spread is large, do a "radix" test as our initial guess, based on
|
||||
// the assumption that lines average to approximately the same length.
|
||||
// NOTE: This is currently disabled, as it does not appear to be profitable in
|
||||
// initial measurements.
|
||||
if (0 && SourceLineCacheEnd-SourceLineCache > 20) {
|
||||
unsigned FileLen = Content->SourceLineCache[Content->NumLines-1];
|
||||
|
||||
// Take a stab at guessing where it is.
|
||||
unsigned ApproxPos = Content->NumLines*QueriedFilePos / FileLen;
|
||||
|
||||
// Check for -10 and +10 lines.
|
||||
unsigned LowerBound = std::max(int(ApproxPos-10), 0);
|
||||
unsigned UpperBound = std::min(ApproxPos+10, FileLen);
|
||||
|
||||
// If the computed lower bound is less than the query location, move it in.
|
||||
if (SourceLineCache < SourceLineCacheStart+LowerBound &&
|
||||
SourceLineCacheStart[LowerBound] < QueriedFilePos)
|
||||
SourceLineCache = SourceLineCacheStart+LowerBound;
|
||||
|
||||
// If the computed upper bound is greater than the query location, move it.
|
||||
if (SourceLineCacheEnd > SourceLineCacheStart+UpperBound &&
|
||||
SourceLineCacheStart[UpperBound] >= QueriedFilePos)
|
||||
SourceLineCacheEnd = SourceLineCacheStart+UpperBound;
|
||||
}
|
||||
|
||||
unsigned *Pos
|
||||
= std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos);
|
||||
unsigned LineNo = Pos-SourceLineCacheStart;
|
||||
|
||||
LastLineNoFileIDQuery = FileID;
|
||||
LastLineNoContentCache = Content;
|
||||
LastLineNoFilePos = QueriedFilePos;
|
||||
LastLineNoResult = LineNo;
|
||||
return LineNo;
|
||||
}
|
||||
|
||||
/// PrintStats - Print statistics to stderr.
|
||||
///
|
||||
void SourceManager::PrintStats() const {
|
||||
llvm::cerr << "\n*** Source Manager Stats:\n";
|
||||
llvm::cerr << FileInfos.size() << " files mapped, " << MemBufferInfos.size()
|
||||
<< " mem buffers mapped, " << FileIDs.size()
|
||||
<< " file ID's allocated.\n";
|
||||
llvm::cerr << " " << FileIDs.size() << " normal buffer FileID's, "
|
||||
<< MacroIDs.size() << " macro expansion FileID's.\n";
|
||||
|
||||
unsigned NumLineNumsComputed = 0;
|
||||
unsigned NumFileBytesMapped = 0;
|
||||
for (std::set<ContentCache>::const_iterator I =
|
||||
FileInfos.begin(), E = FileInfos.end(); I != E; ++I) {
|
||||
NumLineNumsComputed += I->SourceLineCache != 0;
|
||||
NumFileBytesMapped += I->Buffer->getBufferSize();
|
||||
}
|
||||
|
||||
llvm::cerr << NumFileBytesMapped << " bytes of files mapped, "
|
||||
<< NumLineNumsComputed << " files with line #'s computed.\n";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Serialization.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void ContentCache::Emit(llvm::Serializer& S) const {
|
||||
S.FlushRecord();
|
||||
S.EmitPtr(this);
|
||||
|
||||
if (Entry) {
|
||||
llvm::sys::Path Fname(Buffer->getBufferIdentifier());
|
||||
|
||||
if (Fname.isAbsolute())
|
||||
S.EmitCStr(Fname.c_str());
|
||||
else {
|
||||
// Create an absolute path.
|
||||
// FIXME: This will potentially contain ".." and "." in the path.
|
||||
llvm::sys::Path path = llvm::sys::Path::GetCurrentDirectory();
|
||||
path.appendComponent(Fname.c_str());
|
||||
S.EmitCStr(path.c_str());
|
||||
}
|
||||
}
|
||||
else {
|
||||
const char* p = Buffer->getBufferStart();
|
||||
const char* e = Buffer->getBufferEnd();
|
||||
|
||||
S.EmitInt(e-p);
|
||||
|
||||
for ( ; p != e; ++p)
|
||||
S.EmitInt(*p);
|
||||
}
|
||||
|
||||
S.FlushRecord();
|
||||
}
|
||||
|
||||
void ContentCache::ReadToSourceManager(llvm::Deserializer& D,
|
||||
SourceManager& SMgr,
|
||||
FileManager* FMgr,
|
||||
std::vector<char>& Buf) {
|
||||
if (FMgr) {
|
||||
llvm::SerializedPtrID PtrID = D.ReadPtrID();
|
||||
D.ReadCStr(Buf,false);
|
||||
|
||||
// Create/fetch the FileEntry.
|
||||
const char* start = &Buf[0];
|
||||
const FileEntry* E = FMgr->getFile(start,start+Buf.size());
|
||||
|
||||
// FIXME: Ideally we want a lazy materialization of the ContentCache
|
||||
// anyway, because we don't want to read in source files unless this
|
||||
// is absolutely needed.
|
||||
if (!E)
|
||||
D.RegisterPtr(PtrID,NULL);
|
||||
else
|
||||
// Get the ContextCache object and register it with the deserializer.
|
||||
D.RegisterPtr(PtrID,SMgr.getContentCache(E));
|
||||
}
|
||||
else {
|
||||
// Register the ContextCache object with the deserializer.
|
||||
SMgr.MemBufferInfos.push_back(ContentCache());
|
||||
ContentCache& Entry = const_cast<ContentCache&>(SMgr.MemBufferInfos.back());
|
||||
D.RegisterPtr(&Entry);
|
||||
|
||||
// Create the buffer.
|
||||
unsigned Size = D.ReadInt();
|
||||
Entry.Buffer = MemoryBuffer::getNewUninitMemBuffer(Size);
|
||||
|
||||
// Read the contents of the buffer.
|
||||
char* p = const_cast<char*>(Entry.Buffer->getBufferStart());
|
||||
for (unsigned i = 0; i < Size ; ++i)
|
||||
p[i] = D.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
void FileIDInfo::Emit(llvm::Serializer& S) const {
|
||||
S.Emit(IncludeLoc);
|
||||
S.EmitInt(ChunkNo);
|
||||
S.EmitPtr(Content);
|
||||
}
|
||||
|
||||
FileIDInfo FileIDInfo::ReadVal(llvm::Deserializer& D) {
|
||||
FileIDInfo I;
|
||||
I.IncludeLoc = SourceLocation::ReadVal(D);
|
||||
I.ChunkNo = D.ReadInt();
|
||||
D.ReadPtr(I.Content,false);
|
||||
return I;
|
||||
}
|
||||
|
||||
void MacroIDInfo::Emit(llvm::Serializer& S) const {
|
||||
S.Emit(VirtualLoc);
|
||||
S.Emit(PhysicalLoc);
|
||||
}
|
||||
|
||||
MacroIDInfo MacroIDInfo::ReadVal(llvm::Deserializer& D) {
|
||||
MacroIDInfo I;
|
||||
I.VirtualLoc = SourceLocation::ReadVal(D);
|
||||
I.PhysicalLoc = SourceLocation::ReadVal(D);
|
||||
return I;
|
||||
}
|
||||
|
||||
void SourceManager::Emit(llvm::Serializer& S) const {
|
||||
S.EnterBlock();
|
||||
S.EmitPtr(this);
|
||||
S.EmitInt(MainFileID);
|
||||
|
||||
// Emit: FileInfos. Just emit the file name.
|
||||
S.EnterBlock();
|
||||
|
||||
std::for_each(FileInfos.begin(),FileInfos.end(),
|
||||
S.MakeEmitter<ContentCache>());
|
||||
|
||||
S.ExitBlock();
|
||||
|
||||
// Emit: MemBufferInfos
|
||||
S.EnterBlock();
|
||||
|
||||
std::for_each(MemBufferInfos.begin(), MemBufferInfos.end(),
|
||||
S.MakeEmitter<ContentCache>());
|
||||
|
||||
S.ExitBlock();
|
||||
|
||||
// Emit: FileIDs
|
||||
S.EmitInt(FileIDs.size());
|
||||
std::for_each(FileIDs.begin(), FileIDs.end(), S.MakeEmitter<FileIDInfo>());
|
||||
|
||||
// Emit: MacroIDs
|
||||
S.EmitInt(MacroIDs.size());
|
||||
std::for_each(MacroIDs.begin(), MacroIDs.end(), S.MakeEmitter<MacroIDInfo>());
|
||||
|
||||
S.ExitBlock();
|
||||
}
|
||||
|
||||
SourceManager*
|
||||
SourceManager::CreateAndRegister(llvm::Deserializer& D, FileManager& FMgr){
|
||||
SourceManager *M = new SourceManager();
|
||||
D.RegisterPtr(M);
|
||||
|
||||
// Read: the FileID of the main source file of the translation unit.
|
||||
M->MainFileID = D.ReadInt();
|
||||
|
||||
std::vector<char> Buf;
|
||||
|
||||
{ // Read: FileInfos.
|
||||
llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation();
|
||||
while (!D.FinishedBlock(BLoc))
|
||||
ContentCache::ReadToSourceManager(D,*M,&FMgr,Buf);
|
||||
}
|
||||
|
||||
{ // Read: MemBufferInfos.
|
||||
llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation();
|
||||
while (!D.FinishedBlock(BLoc))
|
||||
ContentCache::ReadToSourceManager(D,*M,NULL,Buf);
|
||||
}
|
||||
|
||||
// Read: FileIDs.
|
||||
unsigned Size = D.ReadInt();
|
||||
M->FileIDs.reserve(Size);
|
||||
for (; Size > 0 ; --Size)
|
||||
M->FileIDs.push_back(FileIDInfo::ReadVal(D));
|
||||
|
||||
// Read: MacroIDs.
|
||||
Size = D.ReadInt();
|
||||
M->MacroIDs.reserve(Size);
|
||||
for (; Size > 0 ; --Size)
|
||||
M->MacroIDs.push_back(MacroIDInfo::ReadVal(D));
|
||||
|
||||
return M;
|
||||
}
|
||||
@@ -1,452 +0,0 @@
|
||||
//===--- TargetInfo.cpp - Information about Target machine ----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the TargetInfo and TargetInfoImpl interfaces.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/AST/Builtins.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include <set>
|
||||
using namespace clang;
|
||||
|
||||
void TargetInfoImpl::ANCHOR() {} // out-of-line virtual method for class.
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FIXME: These are temporary hacks, they should revector into the
|
||||
// TargetInfoImpl.
|
||||
|
||||
void TargetInfo::getFloatInfo(uint64_t &Size, unsigned &Align,
|
||||
const llvm::fltSemantics *&Format,
|
||||
FullSourceLoc Loc) {
|
||||
Align = 32; // FIXME: implement correctly.
|
||||
Size = 32;
|
||||
Format = &llvm::APFloat::IEEEsingle;
|
||||
}
|
||||
void TargetInfo::getDoubleInfo(uint64_t &Size, unsigned &Align,
|
||||
const llvm::fltSemantics *&Format,
|
||||
FullSourceLoc Loc) {
|
||||
Size = Align = 64; // FIXME: implement correctly.
|
||||
Format = &llvm::APFloat::IEEEdouble;
|
||||
}
|
||||
void TargetInfo::getLongDoubleInfo(uint64_t &Size, unsigned &Align,
|
||||
const llvm::fltSemantics *&Format,
|
||||
FullSourceLoc Loc) {
|
||||
Size = Align = 64; // FIXME: implement correctly.
|
||||
Format = &llvm::APFloat::IEEEdouble;
|
||||
//Size = 80; Align = 32; // FIXME: implement correctly.
|
||||
//Format = &llvm::APFloat::x87DoubleExtended;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
const char* TargetInfo::getTargetTriple() const {
|
||||
return PrimaryTarget->getTargetTriple();
|
||||
}
|
||||
|
||||
const char *TargetInfo::getTargetPrefix() const {
|
||||
return PrimaryTarget->getTargetPrefix();
|
||||
}
|
||||
|
||||
/// 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(FullSourceLoc Loc,
|
||||
unsigned DiagKind) {
|
||||
NonPortable = true;
|
||||
if (Diag && Loc.isValid()) Diag->Report(Loc, DiagKind);
|
||||
}
|
||||
|
||||
/// GetTargetDefineMap - Get the set of target #defines in an associative
|
||||
/// collection for easy lookup.
|
||||
static void GetTargetDefineMap(const TargetInfoImpl *Target,
|
||||
llvm::StringMap<std::string> &Map) {
|
||||
std::vector<char> Defines;
|
||||
Defines.reserve(4096);
|
||||
Target->getTargetDefines(Defines);
|
||||
|
||||
for (const char *DefStr = &Defines[0], *E = DefStr+Defines.size();
|
||||
DefStr != E;) {
|
||||
// Skip the '#define ' portion.
|
||||
assert(memcmp(DefStr, "#define ", strlen("#define ")) == 0 &&
|
||||
"#define didn't start with #define!");
|
||||
DefStr += strlen("#define ");
|
||||
|
||||
// Find the divider between the key and value.
|
||||
const char *SpacePos = strchr(DefStr, ' ');
|
||||
|
||||
std::string &Entry = Map.GetOrCreateValue(DefStr, SpacePos).getValue();
|
||||
|
||||
const char *EndPos = strchr(SpacePos+1, '\n');
|
||||
Entry = std::string(SpacePos+1, EndPos);
|
||||
DefStr = EndPos+1;
|
||||
}
|
||||
}
|
||||
|
||||
/// getTargetDefines - Appends the target-specific #define values for this
|
||||
/// target set to the specified buffer.
|
||||
void TargetInfo::getTargetDefines(std::vector<char> &Buffer) {
|
||||
// If we have no secondary targets, be a bit more efficient.
|
||||
if (SecondaryTargets.empty()) {
|
||||
PrimaryTarget->getTargetDefines(Buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
// This is tricky in the face of secondary targets. Specifically,
|
||||
// target-specific #defines that are present and identical across all
|
||||
// secondary targets are turned into #defines, #defines that are present in
|
||||
// the primary target but are missing or different in the secondary targets
|
||||
// are turned into #define_target, and #defines that are not defined in the
|
||||
// primary, but are defined in a secondary are turned into
|
||||
// #define_other_target. This allows the preprocessor to correctly track uses
|
||||
// of target-specific macros.
|
||||
|
||||
// Get the set of primary #defines.
|
||||
llvm::StringMap<std::string> PrimaryDefines;
|
||||
GetTargetDefineMap(PrimaryTarget, PrimaryDefines);
|
||||
|
||||
// Get the sets of secondary #defines.
|
||||
llvm::StringMap<std::string> *SecondaryDefines
|
||||
= new llvm::StringMap<std::string>[SecondaryTargets.size()];
|
||||
for (unsigned i = 0, e = SecondaryTargets.size(); i != e; ++i)
|
||||
GetTargetDefineMap(SecondaryTargets[i], SecondaryDefines[i]);
|
||||
|
||||
// Loop over all defines in the primary target, processing them until we run
|
||||
// out.
|
||||
for (llvm::StringMap<std::string>::iterator PDI =
|
||||
PrimaryDefines.begin(), E = PrimaryDefines.end(); PDI != E; ++PDI) {
|
||||
std::string DefineName(PDI->getKeyData(),
|
||||
PDI->getKeyData() + PDI->getKeyLength());
|
||||
std::string DefineValue = PDI->getValue();
|
||||
|
||||
// Check to see whether all secondary targets have this #define and whether
|
||||
// it is to the same value. Remember if not, but remove the #define from
|
||||
// their collection in any case if they have it.
|
||||
bool isPortable = true;
|
||||
|
||||
for (unsigned i = 0, e = SecondaryTargets.size(); i != e; ++i) {
|
||||
llvm::StringMap<std::string>::iterator I =
|
||||
SecondaryDefines[i].find(&DefineName[0],
|
||||
&DefineName[0]+DefineName.size());
|
||||
if (I == SecondaryDefines[i].end()) {
|
||||
// Secondary target doesn't have this #define.
|
||||
isPortable = false;
|
||||
} else {
|
||||
// Secondary target has this define, remember if it disagrees.
|
||||
if (isPortable)
|
||||
isPortable = I->getValue() == DefineValue;
|
||||
// Remove it from the secondary target unconditionally.
|
||||
SecondaryDefines[i].erase(I);
|
||||
}
|
||||
}
|
||||
|
||||
// If this define is non-portable, turn it into #define_target, otherwise
|
||||
// just use #define.
|
||||
const char *Command = isPortable ? "#define " : "#define_target ";
|
||||
Buffer.insert(Buffer.end(), Command, Command+strlen(Command));
|
||||
|
||||
// Insert "defname defvalue\n".
|
||||
Buffer.insert(Buffer.end(), DefineName.begin(), DefineName.end());
|
||||
Buffer.push_back(' ');
|
||||
Buffer.insert(Buffer.end(), DefineValue.begin(), DefineValue.end());
|
||||
Buffer.push_back('\n');
|
||||
}
|
||||
|
||||
// Now that all of the primary target's defines have been handled and removed
|
||||
// from the secondary target's define sets, go through the remaining secondary
|
||||
// target's #defines and taint them.
|
||||
for (unsigned i = 0, e = SecondaryTargets.size(); i != e; ++i) {
|
||||
llvm::StringMap<std::string> &Defs = SecondaryDefines[i];
|
||||
while (!Defs.empty()) {
|
||||
const char *DefStart = Defs.begin()->getKeyData();
|
||||
const char *DefEnd = DefStart + Defs.begin()->getKeyLength();
|
||||
|
||||
// Insert "#define_other_target defname".
|
||||
const char *Command = "#define_other_target ";
|
||||
Buffer.insert(Buffer.end(), Command, Command+strlen(Command));
|
||||
Buffer.insert(Buffer.end(), DefStart, DefEnd);
|
||||
Buffer.push_back('\n');
|
||||
|
||||
// If any other secondary targets have this same define, remove it from
|
||||
// them to avoid duplicate #define_other_target directives.
|
||||
for (unsigned j = i+1; j != e; ++j) {
|
||||
llvm::StringMap<std::string>::iterator I =
|
||||
SecondaryDefines[j].find(DefStart, DefEnd);
|
||||
if (I != SecondaryDefines[j].end())
|
||||
SecondaryDefines[j].erase(I);
|
||||
}
|
||||
Defs.erase(Defs.begin());
|
||||
}
|
||||
}
|
||||
|
||||
delete[] SecondaryDefines;
|
||||
}
|
||||
|
||||
/// ComputeWCharWidth - Determine the width of the wchar_t type for the primary
|
||||
/// target, diagnosing whether this is non-portable across the secondary
|
||||
/// targets.
|
||||
void TargetInfo::ComputeWCharInfo(FullSourceLoc Loc) {
|
||||
PrimaryTarget->getWCharInfo(WCharWidth, WCharAlign);
|
||||
|
||||
// Check whether this is portable across the secondary targets if the T-U is
|
||||
// portable so far.
|
||||
for (unsigned i = 0, e = SecondaryTargets.size(); i != e; ++i) {
|
||||
unsigned Width, Align;
|
||||
SecondaryTargets[i]->getWCharInfo(Width, Align);
|
||||
if (Width != WCharWidth || Align != WCharAlign)
|
||||
return DiagnoseNonPortability(Loc, diag::port_wchar_t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// getTargetBuiltins - Return information about target-specific builtins for
|
||||
/// the current primary target, and info about which builtins are non-portable
|
||||
/// across the current set of primary and secondary targets.
|
||||
void TargetInfo::getTargetBuiltins(const Builtin::Info *&Records,
|
||||
unsigned &NumRecords,
|
||||
std::vector<const char *> &NPortable) const {
|
||||
// Get info about what actual builtins we will expose.
|
||||
PrimaryTarget->getTargetBuiltins(Records, NumRecords);
|
||||
if (SecondaryTargets.empty()) return;
|
||||
|
||||
// Compute the set of non-portable builtins.
|
||||
|
||||
// Start by computing a mapping from the primary target's builtins to their
|
||||
// info records for efficient lookup.
|
||||
llvm::StringMap<const Builtin::Info*> PrimaryRecs;
|
||||
for (unsigned i = 0, e = NumRecords; i != e; ++i) {
|
||||
const char *BIName = Records[i].Name;
|
||||
PrimaryRecs.GetOrCreateValue(BIName, BIName+strlen(BIName)).getValue()
|
||||
= Records+i;
|
||||
}
|
||||
|
||||
for (unsigned i = 0, e = SecondaryTargets.size(); i != e; ++i) {
|
||||
// Get the builtins for this secondary target.
|
||||
const Builtin::Info *Records2nd;
|
||||
unsigned NumRecords2nd;
|
||||
SecondaryTargets[i]->getTargetBuiltins(Records2nd, NumRecords2nd);
|
||||
|
||||
// Remember all of the secondary builtin names.
|
||||
std::set<std::string> BuiltinNames2nd;
|
||||
|
||||
for (unsigned j = 0, e = NumRecords2nd; j != e; ++j) {
|
||||
BuiltinNames2nd.insert(Records2nd[j].Name);
|
||||
|
||||
// Check to see if the primary target has this builtin.
|
||||
llvm::StringMap<const Builtin::Info*>::iterator I =
|
||||
PrimaryRecs.find(Records2nd[j].Name,
|
||||
Records2nd[j].Name+strlen(Records2nd[j].Name));
|
||||
if (I != PrimaryRecs.end()) {
|
||||
const Builtin::Info *PrimBI = I->getValue();
|
||||
// If does. If they are not identical, mark the builtin as being
|
||||
// non-portable.
|
||||
if (Records2nd[j] != *PrimBI)
|
||||
NPortable.push_back(PrimBI->Name);
|
||||
} else {
|
||||
// The primary target doesn't have this, it is non-portable.
|
||||
NPortable.push_back(Records2nd[j].Name);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we checked all the secondary builtins, check to see if the
|
||||
// primary target has any builtins that the secondary one doesn't. If so,
|
||||
// then those are non-portable.
|
||||
for (unsigned j = 0, e = NumRecords; j != e; ++j) {
|
||||
if (!BuiltinNames2nd.count(Records[j].Name))
|
||||
NPortable.push_back(Records[j].Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// getVAListDeclaration - Return the declaration to use for
|
||||
/// __builtin_va_list, which is target-specific.
|
||||
const char *TargetInfo::getVAListDeclaration() const {
|
||||
return PrimaryTarget->getVAListDeclaration();
|
||||
}
|
||||
|
||||
/// isValidGCCRegisterName - Returns whether the passed in string
|
||||
/// is a valid register name according to GCC. This is used by Sema for
|
||||
/// inline asm statements.
|
||||
bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
|
||||
const char * const *Names;
|
||||
unsigned NumNames;
|
||||
|
||||
// Get rid of any register prefix.
|
||||
if (Name[0] == '%' || Name[0] == '#')
|
||||
Name++;
|
||||
|
||||
if (strcmp(Name, "memory") == 0 ||
|
||||
strcmp(Name, "cc") == 0)
|
||||
return true;
|
||||
|
||||
PrimaryTarget->getGCCRegNames(Names, NumNames);
|
||||
|
||||
// If we have a number it maps to an entry in the register name array.
|
||||
if (isdigit(Name[0])) {
|
||||
char *End;
|
||||
int n = (int)strtol(Name, &End, 0);
|
||||
if (*End == 0)
|
||||
return n >= 0 && (unsigned)n < NumNames;
|
||||
}
|
||||
|
||||
// Check register names.
|
||||
for (unsigned i = 0; i < NumNames; i++) {
|
||||
if (strcmp(Name, Names[i]) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now check aliases.
|
||||
const TargetInfoImpl::GCCRegAlias *Aliases;
|
||||
unsigned NumAliases;
|
||||
|
||||
PrimaryTarget->getGCCRegAliases(Aliases, NumAliases);
|
||||
for (unsigned i = 0; i < NumAliases; i++) {
|
||||
for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
|
||||
if (!Aliases[i].Aliases[j])
|
||||
break;
|
||||
if (strcmp(Aliases[i].Aliases[j], Name) == 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const
|
||||
{
|
||||
assert(isValidGCCRegisterName(Name) && "Invalid register passed in");
|
||||
|
||||
const char * const *Names;
|
||||
unsigned NumNames;
|
||||
|
||||
PrimaryTarget->getGCCRegNames(Names, NumNames);
|
||||
|
||||
// First, check if we have a number.
|
||||
if (isdigit(Name[0])) {
|
||||
char *End;
|
||||
int n = (int)strtol(Name, &End, 0);
|
||||
if (*End == 0) {
|
||||
assert(n >= 0 && (unsigned)n < NumNames &&
|
||||
"Out of bounds register number!");
|
||||
return Names[n];
|
||||
}
|
||||
}
|
||||
|
||||
// Now check aliases.
|
||||
const TargetInfoImpl::GCCRegAlias *Aliases;
|
||||
unsigned NumAliases;
|
||||
|
||||
PrimaryTarget->getGCCRegAliases(Aliases, NumAliases);
|
||||
for (unsigned i = 0; i < NumAliases; i++) {
|
||||
for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
|
||||
if (!Aliases[i].Aliases[j])
|
||||
break;
|
||||
if (strcmp(Aliases[i].Aliases[j], Name) == 0)
|
||||
return Aliases[i].Register;
|
||||
}
|
||||
}
|
||||
|
||||
return Name;
|
||||
}
|
||||
|
||||
bool TargetInfo::validateOutputConstraint(const char *Name,
|
||||
ConstraintInfo &info) const
|
||||
{
|
||||
// An output constraint must start with '=' or '+'
|
||||
if (*Name != '=' && *Name != '+')
|
||||
return false;
|
||||
|
||||
if (*Name == '+')
|
||||
info = CI_ReadWrite;
|
||||
else
|
||||
info = CI_None;
|
||||
|
||||
Name++;
|
||||
while (*Name) {
|
||||
switch (*Name) {
|
||||
default:
|
||||
if (!PrimaryTarget->validateAsmConstraint(*Name, info)) {
|
||||
// FIXME: This assert is in place temporarily
|
||||
// so we can add more constraints as we hit it.
|
||||
// Eventually, an unknown constraint should just be treated as 'g'.
|
||||
assert(0 && "Unknown output constraint type!");
|
||||
}
|
||||
case '&': // early clobber.
|
||||
break;
|
||||
case 'r': // general register.
|
||||
info = (ConstraintInfo)(info|CI_AllowsRegister);
|
||||
break;
|
||||
case 'm': // memory operand.
|
||||
info = (ConstraintInfo)(info|CI_AllowsMemory);
|
||||
break;
|
||||
case 'g': // general register, memory operand or immediate integer.
|
||||
info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister);
|
||||
break;
|
||||
}
|
||||
|
||||
Name++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TargetInfo::validateInputConstraint(const char *Name,
|
||||
unsigned NumOutputs,
|
||||
ConstraintInfo &info) const
|
||||
{
|
||||
while (*Name) {
|
||||
switch (*Name) {
|
||||
default:
|
||||
// Check if we have a matching constraint
|
||||
if (*Name >= '0' && *Name <= '9') {
|
||||
unsigned i = *Name - '0';
|
||||
|
||||
// Check if matching constraint is out of bounds.
|
||||
if (i >= NumOutputs)
|
||||
return false;
|
||||
} else if (!PrimaryTarget->validateAsmConstraint(*Name, info)) {
|
||||
// FIXME: This assert is in place temporarily
|
||||
// so we can add more constraints as we hit it.
|
||||
// Eventually, an unknown constraint should just be treated as 'g'.
|
||||
assert(0 && "Unknown input constraint type!");
|
||||
}
|
||||
case '%': // commutative
|
||||
// FIXME: Fail if % is used with the last operand.
|
||||
break;
|
||||
case 'i': // immediate integer.
|
||||
break;
|
||||
case 'r': // general register.
|
||||
info = (ConstraintInfo)(info|CI_AllowsRegister);
|
||||
break;
|
||||
case 'm': // memory operand.
|
||||
info = (ConstraintInfo)(info|CI_AllowsMemory);
|
||||
break;
|
||||
case 'g': // general register, memory operand or immediate integer.
|
||||
info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister);
|
||||
break;
|
||||
}
|
||||
|
||||
Name++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *TargetInfo::getClobbers() const
|
||||
{
|
||||
return PrimaryTarget->getClobbers();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,730 +0,0 @@
|
||||
//===--- Targets.cpp - Implement -arch option and targets -----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements construction of a TargetInfo object from a
|
||||
// target triple.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Builtins.h"
|
||||
#include "clang/AST/TargetBuiltins.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Common code shared among targets.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static void Define(std::vector<char> &Buf, const char *Macro,
|
||||
const char *Val = "1") {
|
||||
const char *Def = "#define ";
|
||||
Buf.insert(Buf.end(), Def, Def+strlen(Def));
|
||||
Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
|
||||
Buf.push_back(' ');
|
||||
Buf.insert(Buf.end(), Val, Val+strlen(Val));
|
||||
Buf.push_back('\n');
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
class DarwinTargetInfo : public TargetInfoImpl {
|
||||
public:
|
||||
DarwinTargetInfo(const std::string& triple) : TargetInfoImpl(triple) {}
|
||||
|
||||
virtual void getTargetDefines(std::vector<char> &Defs) const {
|
||||
// FIXME: we need a real target configuration system. For now, only define
|
||||
// __APPLE__ if the host has it.
|
||||
#ifdef __APPLE__
|
||||
Define(Defs, "__APPLE__");
|
||||
Define(Defs, "__MACH__");
|
||||
#endif
|
||||
|
||||
if (1) {// -fobjc-gc controls this.
|
||||
Define(Defs, "__weak", "");
|
||||
Define(Defs, "__strong", "");
|
||||
} else {
|
||||
Define(Defs, "__weak", "__attribute__((objc_gc(weak)))");
|
||||
Define(Defs, "__strong", "__attribute__((objc_gc(strong)))");
|
||||
Define(Defs, "__OBJC_GC__");
|
||||
}
|
||||
|
||||
// darwin_constant_cfstrings controls this.
|
||||
Define(Defs, "__CONSTANT_CFSTRINGS__");
|
||||
|
||||
if (0) // darwin_pascal_strings
|
||||
Define(Defs, "__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<char> &Defs, bool is64Bit) {
|
||||
// Target identification.
|
||||
Define(Defs, "__ppc__");
|
||||
Define(Defs, "_ARCH_PPC");
|
||||
Define(Defs, "__POWERPC__");
|
||||
if (is64Bit) {
|
||||
Define(Defs, "_ARCH_PPC64");
|
||||
Define(Defs, "_LP64");
|
||||
Define(Defs, "__LP64__");
|
||||
Define(Defs, "__ppc64__");
|
||||
} else {
|
||||
Define(Defs, "__ppc__");
|
||||
}
|
||||
|
||||
// Target properties.
|
||||
Define(Defs, "_BIG_ENDIAN");
|
||||
Define(Defs, "__BIG_ENDIAN__");
|
||||
|
||||
if (is64Bit) {
|
||||
Define(Defs, "__INTMAX_MAX__", "9223372036854775807L");
|
||||
Define(Defs, "__INTMAX_TYPE__", "long int");
|
||||
Define(Defs, "__LONG_MAX__", "9223372036854775807L");
|
||||
Define(Defs, "__PTRDIFF_TYPE__", "long int");
|
||||
Define(Defs, "__UINTMAX_TYPE__", "long unsigned int");
|
||||
} else {
|
||||
Define(Defs, "__INTMAX_MAX__", "9223372036854775807LL");
|
||||
Define(Defs, "__INTMAX_TYPE__", "long long int");
|
||||
Define(Defs, "__LONG_MAX__", "2147483647L");
|
||||
Define(Defs, "__PTRDIFF_TYPE__", "int");
|
||||
Define(Defs, "__UINTMAX_TYPE__", "long long unsigned int");
|
||||
}
|
||||
Define(Defs, "__INT_MAX__", "2147483647");
|
||||
Define(Defs, "__LONG_LONG_MAX__", "9223372036854775807LL");
|
||||
Define(Defs, "__CHAR_BIT__", "8");
|
||||
Define(Defs, "__SCHAR_MAX__", "127");
|
||||
Define(Defs, "__SHRT_MAX__", "32767");
|
||||
Define(Defs, "__SIZE_TYPE__", "long unsigned int");
|
||||
|
||||
// Subtarget options.
|
||||
Define(Defs, "__USER_LABEL_PREFIX__", "_");
|
||||
Define(Defs, "__NATURAL_ALIGNMENT__");
|
||||
Define(Defs, "__REGISTER_PREFIX__", "");
|
||||
|
||||
Define(Defs, "__WCHAR_MAX__", "2147483647");
|
||||
Define(Defs, "__WCHAR_TYPE__", "int");
|
||||
Define(Defs, "__WINT_TYPE__", "int");
|
||||
|
||||
// Float macros.
|
||||
Define(Defs, "__FLT_DENORM_MIN__", "1.40129846e-45F");
|
||||
Define(Defs, "__FLT_DIG__", "6");
|
||||
Define(Defs, "__FLT_EPSILON__", "1.19209290e-7F");
|
||||
Define(Defs, "__FLT_EVAL_METHOD__", "0");
|
||||
Define(Defs, "__FLT_HAS_INFINITY__");
|
||||
Define(Defs, "__FLT_HAS_QUIET_NAN__");
|
||||
Define(Defs, "__FLT_MANT_DIG__", "24");
|
||||
Define(Defs, "__FLT_MAX_10_EXP__", "38");
|
||||
Define(Defs, "__FLT_MAX_EXP__", "128");
|
||||
Define(Defs, "__FLT_MAX__", "3.40282347e+38F");
|
||||
Define(Defs, "__FLT_MIN_10_EXP__", "(-37)");
|
||||
Define(Defs, "__FLT_MIN_EXP__", "(-125)");
|
||||
Define(Defs, "__FLT_MIN__", "1.17549435e-38F");
|
||||
Define(Defs, "__FLT_RADIX__", "2");
|
||||
|
||||
// double macros.
|
||||
Define(Defs, "__DBL_DENORM_MIN__", "4.9406564584124654e-324");
|
||||
Define(Defs, "__DBL_DIG__", "15");
|
||||
Define(Defs, "__DBL_EPSILON__", "2.2204460492503131e-16");
|
||||
Define(Defs, "__DBL_HAS_INFINITY__");
|
||||
Define(Defs, "__DBL_HAS_QUIET_NAN__");
|
||||
Define(Defs, "__DBL_MANT_DIG__", "53");
|
||||
Define(Defs, "__DBL_MAX_10_EXP__", "308");
|
||||
Define(Defs, "__DBL_MAX_EXP__", "1024");
|
||||
Define(Defs, "__DBL_MAX__", "1.7976931348623157e+308");
|
||||
Define(Defs, "__DBL_MIN_10_EXP__", "(-307)");
|
||||
Define(Defs, "__DBL_MIN_EXP__", "(-1021)");
|
||||
Define(Defs, "__DBL_MIN__", "2.2250738585072014e-308");
|
||||
Define(Defs, "__DECIMAL_DIG__", "33");
|
||||
|
||||
// 128-bit long double macros.
|
||||
Define(Defs, "__LDBL_DENORM_MIN__",
|
||||
"4.94065645841246544176568792868221e-324L");
|
||||
Define(Defs, "__LDBL_DIG__", "31");
|
||||
Define(Defs, "__LDBL_EPSILON__",
|
||||
"4.94065645841246544176568792868221e-324L");
|
||||
Define(Defs, "__LDBL_HAS_INFINITY__");
|
||||
Define(Defs, "__LDBL_HAS_QUIET_NAN__");
|
||||
Define(Defs, "__LDBL_MANT_DIG__", "106");
|
||||
Define(Defs, "__LDBL_MAX_10_EXP__", "308");
|
||||
Define(Defs, "__LDBL_MAX_EXP__", "1024");
|
||||
Define(Defs, "__LDBL_MAX__",
|
||||
"1.79769313486231580793728971405301e+308L");
|
||||
Define(Defs, "__LDBL_MIN_10_EXP__", "(-291)");
|
||||
Define(Defs, "__LDBL_MIN_EXP__", "(-968)");
|
||||
Define(Defs, "__LDBL_MIN__",
|
||||
"2.00416836000897277799610805135016e-292L");
|
||||
Define(Defs, "__LONG_DOUBLE_128__");
|
||||
}
|
||||
|
||||
/// getX86Defines - Return a set of the X86-specific #defines that are
|
||||
/// not tied to a specific subtarget.
|
||||
static void getX86Defines(std::vector<char> &Defs, bool is64Bit) {
|
||||
// Target identification.
|
||||
if (is64Bit) {
|
||||
Define(Defs, "_LP64");
|
||||
Define(Defs, "__LP64__");
|
||||
Define(Defs, "__amd64__");
|
||||
Define(Defs, "__amd64");
|
||||
Define(Defs, "__x86_64");
|
||||
Define(Defs, "__x86_64__");
|
||||
} else {
|
||||
Define(Defs, "__i386__");
|
||||
Define(Defs, "__i386");
|
||||
Define(Defs, "i386");
|
||||
}
|
||||
|
||||
// Target properties.
|
||||
Define(Defs, "__LITTLE_ENDIAN__");
|
||||
|
||||
if (is64Bit) {
|
||||
Define(Defs, "__INTMAX_MAX__", "9223372036854775807L");
|
||||
Define(Defs, "__INTMAX_TYPE__", "long int");
|
||||
Define(Defs, "__LONG_MAX__", "9223372036854775807L");
|
||||
Define(Defs, "__PTRDIFF_TYPE__", "long int");
|
||||
Define(Defs, "__UINTMAX_TYPE__", "long unsigned int");
|
||||
} else {
|
||||
Define(Defs, "__INTMAX_MAX__", "9223372036854775807LL");
|
||||
Define(Defs, "__INTMAX_TYPE__", "long long int");
|
||||
Define(Defs, "__LONG_MAX__", "2147483647L");
|
||||
Define(Defs, "__PTRDIFF_TYPE__", "int");
|
||||
Define(Defs, "__UINTMAX_TYPE__", "long long unsigned int");
|
||||
}
|
||||
Define(Defs, "__CHAR_BIT__", "8");
|
||||
Define(Defs, "__INT_MAX__", "2147483647");
|
||||
Define(Defs, "__LONG_LONG_MAX__", "9223372036854775807LL");
|
||||
Define(Defs, "__SCHAR_MAX__", "127");
|
||||
Define(Defs, "__SHRT_MAX__", "32767");
|
||||
Define(Defs, "__SIZE_TYPE__", "long unsigned int");
|
||||
|
||||
// Subtarget options.
|
||||
Define(Defs, "__nocona");
|
||||
Define(Defs, "__nocona__");
|
||||
Define(Defs, "__tune_nocona__");
|
||||
Define(Defs, "__SSE2_MATH__");
|
||||
Define(Defs, "__SSE2__");
|
||||
Define(Defs, "__SSE_MATH__");
|
||||
Define(Defs, "__SSE__");
|
||||
Define(Defs, "__MMX__");
|
||||
Define(Defs, "__REGISTER_PREFIX__", "");
|
||||
|
||||
Define(Defs, "__WCHAR_MAX__", "2147483647");
|
||||
Define(Defs, "__WCHAR_TYPE__", "int");
|
||||
Define(Defs, "__WINT_TYPE__", "int");
|
||||
|
||||
// Float macros.
|
||||
Define(Defs, "__FLT_DENORM_MIN__", "1.40129846e-45F");
|
||||
Define(Defs, "__FLT_DIG__", "6");
|
||||
Define(Defs, "__FLT_EPSILON__", "1.19209290e-7F");
|
||||
Define(Defs, "__FLT_EVAL_METHOD__", "0");
|
||||
Define(Defs, "__FLT_HAS_INFINITY__");
|
||||
Define(Defs, "__FLT_HAS_QUIET_NAN__");
|
||||
Define(Defs, "__FLT_MANT_DIG__", "24");
|
||||
Define(Defs, "__FLT_MAX_10_EXP__", "38");
|
||||
Define(Defs, "__FLT_MAX_EXP__", "128");
|
||||
Define(Defs, "__FLT_MAX__", "3.40282347e+38F");
|
||||
Define(Defs, "__FLT_MIN_10_EXP__", "(-37)");
|
||||
Define(Defs, "__FLT_MIN_EXP__", "(-125)");
|
||||
Define(Defs, "__FLT_MIN__", "1.17549435e-38F");
|
||||
Define(Defs, "__FLT_RADIX__", "2");
|
||||
|
||||
// Double macros.
|
||||
Define(Defs, "__DBL_DENORM_MIN__", "4.9406564584124654e-324");
|
||||
Define(Defs, "__DBL_DIG__", "15");
|
||||
Define(Defs, "__DBL_EPSILON__", "2.2204460492503131e-16");
|
||||
Define(Defs, "__DBL_HAS_INFINITY__");
|
||||
Define(Defs, "__DBL_HAS_QUIET_NAN__");
|
||||
Define(Defs, "__DBL_MANT_DIG__", "53");
|
||||
Define(Defs, "__DBL_MAX_10_EXP__", "308");
|
||||
Define(Defs, "__DBL_MAX_EXP__", "1024");
|
||||
Define(Defs, "__DBL_MAX__", "1.7976931348623157e+308");
|
||||
Define(Defs, "__DBL_MIN_10_EXP__", "(-307)");
|
||||
Define(Defs, "__DBL_MIN_EXP__", "(-1021)");
|
||||
Define(Defs, "__DBL_MIN__", "2.2250738585072014e-308");
|
||||
Define(Defs, "__DECIMAL_DIG__", "21");
|
||||
|
||||
// 80-bit Long double macros.
|
||||
Define(Defs, "__LDBL_DENORM_MIN__", "3.64519953188247460253e-4951L");
|
||||
Define(Defs, "__LDBL_DIG__", "18");
|
||||
Define(Defs, "__LDBL_EPSILON__", "1.08420217248550443401e-19L");
|
||||
Define(Defs, "__LDBL_HAS_INFINITY__");
|
||||
Define(Defs, "__LDBL_HAS_QUIET_NAN__");
|
||||
Define(Defs, "__LDBL_MANT_DIG__", "64");
|
||||
Define(Defs, "__LDBL_MAX_10_EXP__", "4932");
|
||||
Define(Defs, "__LDBL_MAX_EXP__", "16384");
|
||||
Define(Defs, "__LDBL_MAX__", "1.18973149535723176502e+4932L");
|
||||
Define(Defs, "__LDBL_MIN_10_EXP__", "(-4931)");
|
||||
Define(Defs, "__LDBL_MIN_EXP__", "(-16381)");
|
||||
Define(Defs, "__LDBL_MIN__", "3.36210314311209350626e-4932L");
|
||||
}
|
||||
|
||||
static const char* getI386VAListDeclaration() {
|
||||
return "typedef char* __builtin_va_list;";
|
||||
}
|
||||
|
||||
static const char* getX86_64VAListDeclaration() {
|
||||
return
|
||||
"typedef struct __va_list_tag {"
|
||||
" unsigned gp_offset;"
|
||||
" unsigned fp_offset;"
|
||||
" void* overflow_arg_area;"
|
||||
" void* reg_save_area;"
|
||||
"} __builtin_va_list[1];";
|
||||
}
|
||||
|
||||
static const char* getPPCVAListDeclaration() {
|
||||
return
|
||||
"typedef struct __va_list_tag {"
|
||||
" unsigned char gpr;"
|
||||
" unsigned char fpr;"
|
||||
" unsigned short reserved;"
|
||||
" void* overflow_arg_area;"
|
||||
" void* reg_save_area;"
|
||||
"} __builtin_va_list[1];";
|
||||
}
|
||||
|
||||
|
||||
/// PPC builtin info.
|
||||
namespace clang {
|
||||
namespace PPC {
|
||||
|
||||
static const Builtin::Info BuiltinInfo[] = {
|
||||
#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS },
|
||||
#include "clang/AST/PPCBuiltins.def"
|
||||
};
|
||||
|
||||
static void getBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) {
|
||||
Records = BuiltinInfo;
|
||||
NumRecords = LastTSBuiltin-Builtin::FirstTSBuiltin;
|
||||
}
|
||||
|
||||
static const char * const GCCRegNames[] = {
|
||||
"0", "1", "2", "3", "4", "5", "6", "7",
|
||||
"8", "9", "10", "11", "12", "13", "14", "15",
|
||||
"16", "17", "18", "19", "20", "21", "22", "23",
|
||||
"24", "25", "26", "27", "28", "29", "30", "31",
|
||||
"0", "1", "2", "3", "4", "5", "6", "7",
|
||||
"8", "9", "10", "11", "12", "13", "14", "15",
|
||||
"16", "17", "18", "19", "20", "21", "22", "23",
|
||||
"24", "25", "26", "27", "28", "29", "30", "31",
|
||||
"mq", "lr", "ctr", "ap",
|
||||
"0", "1", "2", "3", "4", "5", "6", "7",
|
||||
"xer",
|
||||
"0", "1", "2", "3", "4", "5", "6", "7",
|
||||
"8", "9", "10", "11", "12", "13", "14", "15",
|
||||
"16", "17", "18", "19", "20", "21", "22", "23",
|
||||
"24", "25", "26", "27", "28", "29", "30", "31",
|
||||
"vrsave", "vscr",
|
||||
"spe_acc", "spefscr",
|
||||
"sfp"
|
||||
};
|
||||
|
||||
static void getGCCRegNames(const char * const *&Names,
|
||||
unsigned &NumNames) {
|
||||
Names = GCCRegNames;
|
||||
NumNames = llvm::array_lengthof(GCCRegNames);
|
||||
}
|
||||
|
||||
static const TargetInfoImpl::GCCRegAlias GCCRegAliases[] = {
|
||||
// While some of these aliases do map to different registers
|
||||
// they still share the same register name.
|
||||
{ { "cc", "cr0", "fr0", "r0", "v0"}, "0" },
|
||||
{ { "cr1", "fr1", "r1", "sp", "v1"}, "1" },
|
||||
{ { "cr2", "fr2", "r2", "toc", "v2"}, "2" },
|
||||
{ { "cr3", "fr3", "r3", "v3"}, "3" },
|
||||
{ { "cr4", "fr4", "r4", "v4"}, "4" },
|
||||
{ { "cr5", "fr5", "r5", "v5"}, "5" },
|
||||
{ { "cr6", "fr6", "r6", "v6"}, "6" },
|
||||
{ { "cr7", "fr7", "r7", "v7"}, "7" },
|
||||
{ { "fr8", "r8", "v8"}, "8" },
|
||||
{ { "fr9", "r9", "v9"}, "9" },
|
||||
{ { "fr10", "r10", "v10"}, "10" },
|
||||
{ { "fr11", "r11", "v11"}, "11" },
|
||||
{ { "fr12", "r12", "v12"}, "12" },
|
||||
{ { "fr13", "r13", "v13"}, "13" },
|
||||
{ { "fr14", "r14", "v14"}, "14" },
|
||||
{ { "fr15", "r15", "v15"}, "15" },
|
||||
{ { "fr16", "r16", "v16"}, "16" },
|
||||
{ { "fr17", "r17", "v17"}, "17" },
|
||||
{ { "fr18", "r18", "v18"}, "18" },
|
||||
{ { "fr19", "r19", "v19"}, "19" },
|
||||
{ { "fr20", "r20", "v20"}, "20" },
|
||||
{ { "fr21", "r21", "v21"}, "21" },
|
||||
{ { "fr22", "r22", "v22"}, "22" },
|
||||
{ { "fr23", "r23", "v23"}, "23" },
|
||||
{ { "fr24", "r24", "v24"}, "24" },
|
||||
{ { "fr25", "r25", "v25"}, "25" },
|
||||
{ { "fr26", "r26", "v26"}, "26" },
|
||||
{ { "fr27", "r27", "v27"}, "27" },
|
||||
{ { "fr28", "r28", "v28"}, "28" },
|
||||
{ { "fr29", "r29", "v29"}, "29" },
|
||||
{ { "fr30", "r30", "v30"}, "30" },
|
||||
{ { "fr31", "r31", "v31"}, "31" },
|
||||
};
|
||||
|
||||
static void getGCCRegAliases(const TargetInfoImpl::GCCRegAlias *&Aliases,
|
||||
unsigned &NumAliases) {
|
||||
Aliases = GCCRegAliases;
|
||||
NumAliases = llvm::array_lengthof(GCCRegAliases);
|
||||
}
|
||||
|
||||
static bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) {
|
||||
switch (c) {
|
||||
default: return false;
|
||||
case 'O': // Zero
|
||||
return true;
|
||||
case 'b': // Base register
|
||||
case 'f': // Floating point register
|
||||
info = (TargetInfo::ConstraintInfo)(info|TargetInfo::CI_AllowsRegister);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const char *getClobbers() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *getTargetPrefix() {
|
||||
return "ppc";
|
||||
}
|
||||
|
||||
} // End namespace PPC
|
||||
|
||||
/// X86 builtin info.
|
||||
namespace X86 {
|
||||
static const Builtin::Info BuiltinInfo[] = {
|
||||
#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS },
|
||||
#include "clang/AST/X86Builtins.def"
|
||||
};
|
||||
|
||||
static void getBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) {
|
||||
Records = BuiltinInfo;
|
||||
NumRecords = LastTSBuiltin-Builtin::FirstTSBuiltin;
|
||||
}
|
||||
|
||||
static const char *GCCRegNames[] = {
|
||||
"ax", "dx", "cx", "bx", "si", "di", "bp", "sp",
|
||||
"st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
|
||||
"argp", "flags", "fspr", "dirflag", "frame",
|
||||
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
|
||||
"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
|
||||
};
|
||||
|
||||
static void getGCCRegNames(const char * const *&Names,
|
||||
unsigned &NumNames) {
|
||||
Names = GCCRegNames;
|
||||
NumNames = llvm::array_lengthof(GCCRegNames);
|
||||
}
|
||||
|
||||
static const TargetInfoImpl::GCCRegAlias GCCRegAliases[] = {
|
||||
{ { "al", "ah", "eax", "rax" }, "ax" },
|
||||
{ { "bl", "bh", "ebx", "rbx" }, "bx" },
|
||||
{ { "cl", "ch", "ecx", "rcx" }, "cx" },
|
||||
{ { "dl", "dh", "edx", "rdx" }, "dx" },
|
||||
{ { "esi", "rsi" }, "si" },
|
||||
{ { "esp", "rsp" }, "sp" },
|
||||
{ { "ebp", "rbp" }, "bp" },
|
||||
};
|
||||
|
||||
static void getGCCRegAliases(const TargetInfoImpl::GCCRegAlias *&Aliases,
|
||||
unsigned &NumAliases) {
|
||||
Aliases = GCCRegAliases;
|
||||
NumAliases = llvm::array_lengthof(GCCRegAliases);
|
||||
}
|
||||
|
||||
static bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) {
|
||||
switch (c) {
|
||||
default: return false;
|
||||
case 'a': // eax.
|
||||
case 'b': // ebx.
|
||||
case 'c': // ecx.
|
||||
case 'd': // edx.
|
||||
case 'S': // esi.
|
||||
case 'D': // edi.
|
||||
case 'A': // edx:eax.
|
||||
case 't': // top of floating point stack.
|
||||
case 'u': // second from top of floating point stack.
|
||||
case 'q': // a, b, c, d registers or any integer register in 64-bit.
|
||||
info = (TargetInfo::ConstraintInfo)(info|TargetInfo::CI_AllowsRegister);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const char *getClobbers() {
|
||||
return "~{dirflag},~{fpsr},~{flags}";
|
||||
}
|
||||
|
||||
const char *getTargetPrefix() {
|
||||
return "x86";
|
||||
}
|
||||
|
||||
} // End namespace X86
|
||||
} // end namespace clang.
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Specific target implementations.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
namespace {
|
||||
class DarwinPPCTargetInfo : public DarwinTargetInfo {
|
||||
public:
|
||||
DarwinPPCTargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {}
|
||||
|
||||
virtual void getTargetDefines(std::vector<char> &Defines) const {
|
||||
DarwinTargetInfo::getTargetDefines(Defines);
|
||||
getPowerPCDefines(Defines, false);
|
||||
}
|
||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
||||
unsigned &NumRecords) const {
|
||||
PPC::getBuiltins(Records, NumRecords);
|
||||
}
|
||||
virtual const char *getVAListDeclaration() const {
|
||||
return getPPCVAListDeclaration();
|
||||
}
|
||||
virtual const char *getTargetPrefix() const {
|
||||
return PPC::getTargetPrefix();
|
||||
}
|
||||
virtual void getGCCRegNames(const char * const *&Names,
|
||||
unsigned &NumNames) const {
|
||||
PPC::getGCCRegNames(Names, NumNames);
|
||||
}
|
||||
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
|
||||
unsigned &NumAliases) const {
|
||||
PPC::getGCCRegAliases(Aliases, NumAliases);
|
||||
}
|
||||
virtual bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) const {
|
||||
return PPC::validateAsmConstraint(c, info);
|
||||
}
|
||||
virtual const char *getClobbers() const {
|
||||
return PPC::getClobbers();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
namespace {
|
||||
class DarwinPPC64TargetInfo : public DarwinTargetInfo {
|
||||
public:
|
||||
DarwinPPC64TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {}
|
||||
|
||||
virtual void getTargetDefines(std::vector<char> &Defines) const {
|
||||
DarwinTargetInfo::getTargetDefines(Defines);
|
||||
getPowerPCDefines(Defines, true);
|
||||
}
|
||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
||||
unsigned &NumRecords) const {
|
||||
PPC::getBuiltins(Records, NumRecords);
|
||||
}
|
||||
virtual const char *getVAListDeclaration() const {
|
||||
return getPPCVAListDeclaration();
|
||||
}
|
||||
virtual const char *getTargetPrefix() const {
|
||||
return PPC::getTargetPrefix();
|
||||
}
|
||||
virtual void getGCCRegNames(const char * const *&Names,
|
||||
unsigned &NumNames) const {
|
||||
PPC::getGCCRegNames(Names, NumNames);
|
||||
}
|
||||
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
|
||||
unsigned &NumAliases) const {
|
||||
PPC::getGCCRegAliases(Aliases, NumAliases);
|
||||
}
|
||||
virtual bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) const {
|
||||
return PPC::validateAsmConstraint(c, info);
|
||||
}
|
||||
virtual const char *getClobbers() const {
|
||||
return PPC::getClobbers();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
namespace {
|
||||
class DarwinI386TargetInfo : public DarwinTargetInfo {
|
||||
public:
|
||||
DarwinI386TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {}
|
||||
|
||||
virtual void getTargetDefines(std::vector<char> &Defines) const {
|
||||
DarwinTargetInfo::getTargetDefines(Defines);
|
||||
getX86Defines(Defines, false);
|
||||
}
|
||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
||||
unsigned &NumRecords) const {
|
||||
X86::getBuiltins(Records, NumRecords);
|
||||
}
|
||||
virtual const char *getVAListDeclaration() const {
|
||||
return getI386VAListDeclaration();
|
||||
}
|
||||
virtual const char *getTargetPrefix() const {
|
||||
return X86::getTargetPrefix();
|
||||
}
|
||||
virtual void getGCCRegNames(const char * const *&Names,
|
||||
unsigned &NumNames) const {
|
||||
X86::getGCCRegNames(Names, NumNames);
|
||||
}
|
||||
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
|
||||
unsigned &NumAliases) const {
|
||||
X86::getGCCRegAliases(Aliases, NumAliases);
|
||||
}
|
||||
virtual bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) const {
|
||||
return X86::validateAsmConstraint(c, info);
|
||||
}
|
||||
virtual const char *getClobbers() const {
|
||||
return X86::getClobbers();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
namespace {
|
||||
class DarwinX86_64TargetInfo : public DarwinTargetInfo {
|
||||
public:
|
||||
DarwinX86_64TargetInfo(const std::string& triple) :DarwinTargetInfo(triple) {}
|
||||
|
||||
virtual void getTargetDefines(std::vector<char> &Defines) const {
|
||||
DarwinTargetInfo::getTargetDefines(Defines);
|
||||
getX86Defines(Defines, true);
|
||||
}
|
||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
||||
unsigned &NumRecords) const {
|
||||
X86::getBuiltins(Records, NumRecords);
|
||||
}
|
||||
virtual const char *getVAListDeclaration() const {
|
||||
return getX86_64VAListDeclaration();
|
||||
}
|
||||
virtual const char *getTargetPrefix() const {
|
||||
return X86::getTargetPrefix();
|
||||
}
|
||||
virtual void getGCCRegNames(const char * const *&Names,
|
||||
unsigned &NumNames) const {
|
||||
X86::getGCCRegNames(Names, NumNames);
|
||||
}
|
||||
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
|
||||
unsigned &NumAliases) const {
|
||||
X86::getGCCRegAliases(Aliases, NumAliases);
|
||||
}
|
||||
virtual bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) const {
|
||||
return X86::validateAsmConstraint(c, info);
|
||||
}
|
||||
virtual const char *getClobbers() const {
|
||||
return X86::getClobbers();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
namespace {
|
||||
class LinuxTargetInfo : public DarwinTargetInfo {
|
||||
public:
|
||||
LinuxTargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {
|
||||
// Note: I have no idea if this is right, just for testing.
|
||||
WCharWidth = 16;
|
||||
WCharAlign = 16;
|
||||
}
|
||||
|
||||
virtual void getTargetDefines(std::vector<char> &Defines) const {
|
||||
// TODO: linux-specific stuff.
|
||||
getX86Defines(Defines, false);
|
||||
}
|
||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
||||
unsigned &NumRecords) const {
|
||||
X86::getBuiltins(Records, NumRecords);
|
||||
}
|
||||
virtual const char *getVAListDeclaration() const {
|
||||
return getI386VAListDeclaration();
|
||||
}
|
||||
virtual const char *getTargetPrefix() const {
|
||||
return X86::getTargetPrefix();
|
||||
}
|
||||
virtual void getGCCRegNames(const char * const *&Names,
|
||||
unsigned &NumNames) const {
|
||||
X86::getGCCRegNames(Names, NumNames);
|
||||
}
|
||||
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
|
||||
unsigned &NumAliases) const {
|
||||
X86::getGCCRegAliases(Aliases, NumAliases);
|
||||
}
|
||||
virtual bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) const {
|
||||
return X86::validateAsmConstraint(c, info);
|
||||
}
|
||||
virtual const char *getClobbers() const {
|
||||
return X86::getClobbers();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Driver code
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static inline bool IsX86(const std::string& TT) {
|
||||
return (TT.size() >= 5 && TT[0] == 'i' && TT[2] == '8' && TT[3] == '6' &&
|
||||
TT[4] == '-' && TT[1] - '3' < 6);
|
||||
}
|
||||
|
||||
/// CreateTarget - Create the TargetInfoImpl object for the specified target
|
||||
/// enum value.
|
||||
static TargetInfoImpl *CreateTarget(const std::string& T) {
|
||||
if (T.find("ppc-") == 0 || T.find("powerpc-") == 0)
|
||||
return new DarwinPPCTargetInfo(T);
|
||||
else if (T.find("ppc64-") == 0 || T.find("powerpc64-") == 0)
|
||||
return new DarwinPPC64TargetInfo(T);
|
||||
else if (T.find("x86_64-") == 0)
|
||||
return new DarwinX86_64TargetInfo(T);
|
||||
else if (IsX86(T))
|
||||
return new DarwinI386TargetInfo(T);
|
||||
else if (T.find("bogusW16W16-") == 0) // For testing portability.
|
||||
return new LinuxTargetInfo(T);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// CreateTargetInfo - Return the set of target info objects as specified by
|
||||
/// the -arch command line option.
|
||||
TargetInfo* TargetInfo::CreateTargetInfo(const std::string* TriplesStart,
|
||||
const std::string* TriplesEnd,
|
||||
Diagnostic *Diags) {
|
||||
|
||||
// Create the primary target and target info.
|
||||
TargetInfoImpl* PrimaryTarget = CreateTarget(*TriplesStart);
|
||||
|
||||
if (!PrimaryTarget)
|
||||
return NULL;
|
||||
|
||||
TargetInfo *TI = new TargetInfo(PrimaryTarget, Diags);
|
||||
|
||||
// Add all secondary targets.
|
||||
for (const std::string* I=TriplesStart+1; I != TriplesEnd; ++I) {
|
||||
TargetInfoImpl* SecondaryTarget = CreateTarget(*I);
|
||||
|
||||
if (!SecondaryTarget) {
|
||||
fprintf (stderr,
|
||||
"Warning: secondary target '%s' unrecognized.\n",
|
||||
I->c_str());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
TI->AddSecondaryTarget(SecondaryTarget);
|
||||
}
|
||||
|
||||
return TI;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
//===--- TokenKinds.cpp - Token Kinds Support -----------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the TokenKind enum and support functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
|
||||
#include <cassert>
|
||||
using namespace clang;
|
||||
|
||||
static const char * const TokNames[] = {
|
||||
#define TOK(X) #X,
|
||||
#define KEYWORD(X,Y) #X,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
0
|
||||
};
|
||||
|
||||
const char *tok::getTokenName(enum TokenKind Kind) {
|
||||
assert(Kind < tok::NUM_TOKENS);
|
||||
return TokNames[Kind];
|
||||
}
|
||||
@@ -1,446 +0,0 @@
|
||||
//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This contains code to emit Builtin calls as LLVM code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CodeGenFunction.h"
|
||||
#include "CodeGenModule.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Builtins.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/TargetBuiltins.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
using namespace llvm;
|
||||
|
||||
RValue CodeGenFunction::EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E) {
|
||||
switch (BuiltinID) {
|
||||
default: {
|
||||
if (getContext().BuiltinInfo.isLibFunction(BuiltinID))
|
||||
return EmitCallExpr(CGM.getBuiltinLibFunction(BuiltinID), E);
|
||||
|
||||
// See if we have a target specific intrinsic.
|
||||
Intrinsic::ID IntrinsicID;
|
||||
const char *TargetPrefix = Target.getTargetPrefix();
|
||||
const char *BuiltinName = getContext().BuiltinInfo.GetName(BuiltinID);
|
||||
#define GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN
|
||||
#include "llvm/Intrinsics.gen"
|
||||
#undef GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN
|
||||
|
||||
if (IntrinsicID != Intrinsic::not_intrinsic) {
|
||||
SmallVector<Value*, 16> Args;
|
||||
|
||||
Function *F = CGM.getIntrinsic(IntrinsicID);
|
||||
const llvm::FunctionType *FTy = F->getFunctionType();
|
||||
|
||||
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
|
||||
Value *ArgValue = EmitScalarExpr(E->getArg(i));
|
||||
|
||||
// If the intrinsic arg type is different from the builtin arg type
|
||||
// we need to do a bit cast.
|
||||
const llvm::Type *PTy = FTy->getParamType(i);
|
||||
if (PTy != ArgValue->getType()) {
|
||||
assert(PTy->canLosslesslyBitCastTo(FTy->getParamType(i)) &&
|
||||
"Must be able to losslessly bit cast to param");
|
||||
ArgValue = Builder.CreateBitCast(ArgValue, PTy);
|
||||
}
|
||||
|
||||
Args.push_back(ArgValue);
|
||||
}
|
||||
|
||||
Value *V = Builder.CreateCall(F, &Args[0], &Args[0] + Args.size());
|
||||
QualType BuiltinRetType = E->getType();
|
||||
|
||||
const llvm::Type *RetTy = llvm::Type::VoidTy;
|
||||
if (!BuiltinRetType->isVoidType()) RetTy = ConvertType(BuiltinRetType);
|
||||
|
||||
if (RetTy != V->getType()) {
|
||||
assert(V->getType()->canLosslesslyBitCastTo(RetTy) &&
|
||||
"Must be able to losslessly bit cast result type");
|
||||
V = Builder.CreateBitCast(V, RetTy);
|
||||
}
|
||||
|
||||
return RValue::get(V);
|
||||
}
|
||||
|
||||
// See if we have a target specific builtin that needs to be lowered.
|
||||
Value *V = 0;
|
||||
|
||||
if (strcmp(TargetPrefix, "x86") == 0)
|
||||
V = EmitX86BuiltinExpr(BuiltinID, E);
|
||||
else if (strcmp(TargetPrefix, "ppc") == 0)
|
||||
V = EmitPPCBuiltinExpr(BuiltinID, E);
|
||||
|
||||
if (V)
|
||||
return RValue::get(V);
|
||||
|
||||
WarnUnsupported(E, "builtin function");
|
||||
|
||||
// Unknown builtin, for now just dump it out and return undef.
|
||||
if (hasAggregateLLVMType(E->getType()))
|
||||
return RValue::getAggregate(CreateTempAlloca(ConvertType(E->getType())));
|
||||
return RValue::get(UndefValue::get(ConvertType(E->getType())));
|
||||
}
|
||||
case Builtin::BI__builtin___CFStringMakeConstantString: {
|
||||
const Expr *Arg = E->getArg(0);
|
||||
|
||||
while (1) {
|
||||
if (const ParenExpr *PE = dyn_cast<ParenExpr>(Arg))
|
||||
Arg = PE->getSubExpr();
|
||||
else if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(Arg))
|
||||
Arg = CE->getSubExpr();
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
const StringLiteral *Literal = cast<StringLiteral>(Arg);
|
||||
std::string S(Literal->getStrData(), Literal->getByteLength());
|
||||
|
||||
return RValue::get(CGM.GetAddrOfConstantCFString(S));
|
||||
}
|
||||
case Builtin::BI__builtin_va_start:
|
||||
case Builtin::BI__builtin_va_end: {
|
||||
Value *ArgValue = EmitScalarExpr(E->getArg(0));
|
||||
const llvm::Type *DestType =
|
||||
llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
|
||||
if (ArgValue->getType() != DestType)
|
||||
ArgValue = Builder.CreateBitCast(ArgValue, DestType,
|
||||
ArgValue->getNameStart());
|
||||
|
||||
Intrinsic::ID inst = (BuiltinID == Builtin::BI__builtin_va_start) ?
|
||||
Intrinsic::vastart : Intrinsic::vaend;
|
||||
return RValue::get(Builder.CreateCall(CGM.getIntrinsic(inst), ArgValue));
|
||||
}
|
||||
case Builtin::BI__builtin_classify_type: {
|
||||
APSInt Result(32);
|
||||
if (!E->isBuiltinClassifyType(Result))
|
||||
assert(0 && "Expr not __builtin_classify_type!");
|
||||
return RValue::get(ConstantInt::get(Result));
|
||||
}
|
||||
case Builtin::BI__builtin_constant_p: {
|
||||
APSInt Result(32);
|
||||
// FIXME: Analyze the parameter and check if it is a constant.
|
||||
Result = 0;
|
||||
return RValue::get(ConstantInt::get(Result));
|
||||
}
|
||||
case Builtin::BI__builtin_abs: {
|
||||
Value *ArgValue = EmitScalarExpr(E->getArg(0));
|
||||
|
||||
llvm::BinaryOperator *NegOp =
|
||||
Builder.CreateNeg(ArgValue, (ArgValue->getName() + "neg").c_str());
|
||||
Value *CmpResult =
|
||||
Builder.CreateICmpSGE(ArgValue, NegOp->getOperand(0), "abscond");
|
||||
Value *Result =
|
||||
Builder.CreateSelect(CmpResult, ArgValue, NegOp, "abs");
|
||||
|
||||
return RValue::get(Result);
|
||||
}
|
||||
case Builtin::BI__builtin_expect:
|
||||
return RValue::get(EmitScalarExpr(E->getArg(0)));
|
||||
case Builtin::BI__builtin_bswap32:
|
||||
case Builtin::BI__builtin_bswap64: {
|
||||
Value *ArgValue = EmitScalarExpr(E->getArg(0));
|
||||
const llvm::Type *ArgType = ArgValue->getType();
|
||||
Value *F = CGM.getIntrinsic(Intrinsic::bswap, &ArgType, 1);
|
||||
return RValue::get(Builder.CreateCall(F, ArgValue, "tmp"));
|
||||
}
|
||||
case Builtin::BI__builtin_inff: {
|
||||
APFloat f(APFloat::IEEEsingle, APFloat::fcInfinity, false);
|
||||
return RValue::get(ConstantFP::get(llvm::Type::FloatTy, f));
|
||||
}
|
||||
case Builtin::BI__builtin_inf:
|
||||
// FIXME: mapping long double onto double.
|
||||
case Builtin::BI__builtin_infl: {
|
||||
APFloat f(APFloat::IEEEdouble, APFloat::fcInfinity, false);
|
||||
return RValue::get(ConstantFP::get(llvm::Type::DoubleTy, f));
|
||||
}
|
||||
case Builtin::BI__builtin_isgreater:
|
||||
case Builtin::BI__builtin_isgreaterequal:
|
||||
case Builtin::BI__builtin_isless:
|
||||
case Builtin::BI__builtin_islessequal:
|
||||
case Builtin::BI__builtin_islessgreater:
|
||||
case Builtin::BI__builtin_isunordered: {
|
||||
// Ordered comparisons: we know the arguments to these are matching scalar
|
||||
// floating point values.
|
||||
Value *LHS = EmitScalarExpr(E->getArg(0));
|
||||
Value *RHS = EmitScalarExpr(E->getArg(1));
|
||||
|
||||
switch (BuiltinID) {
|
||||
default: assert(0 && "Unknown ordered comparison");
|
||||
case Builtin::BI__builtin_isgreater:
|
||||
LHS = Builder.CreateFCmpOGT(LHS, RHS, "cmp");
|
||||
break;
|
||||
case Builtin::BI__builtin_isgreaterequal:
|
||||
LHS = Builder.CreateFCmpOGE(LHS, RHS, "cmp");
|
||||
break;
|
||||
case Builtin::BI__builtin_isless:
|
||||
LHS = Builder.CreateFCmpOLT(LHS, RHS, "cmp");
|
||||
break;
|
||||
case Builtin::BI__builtin_islessequal:
|
||||
LHS = Builder.CreateFCmpOLE(LHS, RHS, "cmp");
|
||||
break;
|
||||
case Builtin::BI__builtin_islessgreater:
|
||||
LHS = Builder.CreateFCmpONE(LHS, RHS, "cmp");
|
||||
break;
|
||||
case Builtin::BI__builtin_isunordered:
|
||||
LHS = Builder.CreateFCmpUNO(LHS, RHS, "cmp");
|
||||
break;
|
||||
}
|
||||
// ZExt bool to int type.
|
||||
return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType()),
|
||||
"tmp"));
|
||||
}
|
||||
}
|
||||
return RValue::get(0);
|
||||
}
|
||||
|
||||
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
|
||||
const CallExpr *E) {
|
||||
|
||||
llvm::SmallVector<Value*, 4> Ops;
|
||||
|
||||
for (unsigned i = 0, e = E->getNumArgs(); i != e; i++)
|
||||
Ops.push_back(EmitScalarExpr(E->getArg(i)));
|
||||
|
||||
switch (BuiltinID) {
|
||||
default: return 0;
|
||||
case X86::BI__builtin_ia32_mulps:
|
||||
return Builder.CreateMul(Ops[0], Ops[1], "mulps");
|
||||
case X86::BI__builtin_ia32_pand:
|
||||
return Builder.CreateAnd(Ops[0], Ops[1], "pand");
|
||||
case X86::BI__builtin_ia32_por:
|
||||
return Builder.CreateAnd(Ops[0], Ops[1], "por");
|
||||
case X86::BI__builtin_ia32_pxor:
|
||||
return Builder.CreateAnd(Ops[0], Ops[1], "pxor");
|
||||
case X86::BI__builtin_ia32_pandn: {
|
||||
Ops[0] = Builder.CreateNot(Ops[0], "tmp");
|
||||
return Builder.CreateAnd(Ops[0], Ops[1], "pandn");
|
||||
}
|
||||
case X86::BI__builtin_ia32_paddb:
|
||||
case X86::BI__builtin_ia32_paddd:
|
||||
case X86::BI__builtin_ia32_paddq:
|
||||
case X86::BI__builtin_ia32_paddw:
|
||||
case X86::BI__builtin_ia32_addps:
|
||||
return Builder.CreateAdd(Ops[0], Ops[1], "add");
|
||||
case X86::BI__builtin_ia32_psubb:
|
||||
case X86::BI__builtin_ia32_psubd:
|
||||
case X86::BI__builtin_ia32_psubq:
|
||||
case X86::BI__builtin_ia32_psubw:
|
||||
case X86::BI__builtin_ia32_subps:
|
||||
return Builder.CreateSub(Ops[0], Ops[1], "sub");
|
||||
case X86::BI__builtin_ia32_divps:
|
||||
return Builder.CreateFDiv(Ops[0], Ops[1], "divps");
|
||||
case X86::BI__builtin_ia32_pmullw:
|
||||
return Builder.CreateMul(Ops[0], Ops[1], "pmul");
|
||||
case X86::BI__builtin_ia32_punpckhbw:
|
||||
return EmitShuffleVector(Ops[0], Ops[1], 4, 12, 5, 13, 6, 14, 7, 15,
|
||||
"punpckhbw");
|
||||
case X86::BI__builtin_ia32_punpckhwd:
|
||||
return EmitShuffleVector(Ops[0], Ops[1], 2, 6, 3, 7, "punpckhwd");
|
||||
case X86::BI__builtin_ia32_punpckhdq:
|
||||
return EmitShuffleVector(Ops[0], Ops[1], 1, 3, "punpckhdq");
|
||||
case X86::BI__builtin_ia32_punpcklbw:
|
||||
return EmitShuffleVector(Ops[0], Ops[1], 0, 8, 1, 9, 2, 10, 3, 11,
|
||||
"punpcklbw");
|
||||
case X86::BI__builtin_ia32_punpcklwd:
|
||||
return EmitShuffleVector(Ops[0], Ops[1], 0, 4, 1, 5, "punpcklwd");
|
||||
case X86::BI__builtin_ia32_punpckldq:
|
||||
return EmitShuffleVector(Ops[0], Ops[1], 0, 2, "punpckldq");
|
||||
case X86::BI__builtin_ia32_pslldi:
|
||||
case X86::BI__builtin_ia32_psllqi:
|
||||
case X86::BI__builtin_ia32_psllwi:
|
||||
case X86::BI__builtin_ia32_psradi:
|
||||
case X86::BI__builtin_ia32_psrawi:
|
||||
case X86::BI__builtin_ia32_psrldi:
|
||||
case X86::BI__builtin_ia32_psrlqi:
|
||||
case X86::BI__builtin_ia32_psrlwi: {
|
||||
Ops[1] = Builder.CreateZExt(Ops[1], llvm::Type::Int64Ty, "zext");
|
||||
const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::Int64Ty, 1);
|
||||
Ops[1] = Builder.CreateBitCast(Ops[1], Ty, "bitcast");
|
||||
const char *name = 0;
|
||||
Intrinsic::ID ID = Intrinsic::not_intrinsic;
|
||||
|
||||
switch (BuiltinID) {
|
||||
default: assert(0 && "Unsupported shift intrinsic!");
|
||||
case X86::BI__builtin_ia32_pslldi:
|
||||
name = "pslldi";
|
||||
ID = Intrinsic::x86_mmx_psll_d;
|
||||
break;
|
||||
case X86::BI__builtin_ia32_psllqi:
|
||||
name = "psllqi";
|
||||
ID = Intrinsic::x86_mmx_psll_q;
|
||||
break;
|
||||
case X86::BI__builtin_ia32_psllwi:
|
||||
name = "psllwi";
|
||||
ID = Intrinsic::x86_mmx_psll_w;
|
||||
break;
|
||||
case X86::BI__builtin_ia32_psradi:
|
||||
name = "psradi";
|
||||
ID = Intrinsic::x86_mmx_psra_d;
|
||||
break;
|
||||
case X86::BI__builtin_ia32_psrawi:
|
||||
name = "psrawi";
|
||||
ID = Intrinsic::x86_mmx_psra_w;
|
||||
break;
|
||||
case X86::BI__builtin_ia32_psrldi:
|
||||
name = "psrldi";
|
||||
ID = Intrinsic::x86_mmx_psrl_d;
|
||||
break;
|
||||
case X86::BI__builtin_ia32_psrlqi:
|
||||
name = "psrlqi";
|
||||
ID = Intrinsic::x86_mmx_psrl_q;
|
||||
break;
|
||||
case X86::BI__builtin_ia32_psrlwi:
|
||||
name = "psrlwi";
|
||||
ID = Intrinsic::x86_mmx_psrl_w;
|
||||
break;
|
||||
}
|
||||
llvm::Function *F = CGM.getIntrinsic(ID);
|
||||
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
|
||||
}
|
||||
case X86::BI__builtin_ia32_pshufd: {
|
||||
unsigned i = cast<ConstantInt>(Ops[1])->getZExtValue();
|
||||
return EmitShuffleVector(Ops[0], Ops[0],
|
||||
i & 0x3, (i & 0xc) >> 2,
|
||||
(i & 0x30) >> 4, (i & 0xc0) >> 6,
|
||||
"pshufd");
|
||||
}
|
||||
case X86::BI__builtin_ia32_vec_init_v4hi:
|
||||
case X86::BI__builtin_ia32_vec_init_v8qi:
|
||||
case X86::BI__builtin_ia32_vec_init_v2si:
|
||||
return EmitVector(&Ops[0], Ops.size());
|
||||
case X86::BI__builtin_ia32_vec_ext_v2si:
|
||||
return Builder.CreateExtractElement(Ops[0], Ops[1], "result");
|
||||
case X86::BI__builtin_ia32_cmpordss:
|
||||
case X86::BI__builtin_ia32_cmpunordss:
|
||||
case X86::BI__builtin_ia32_cmpeqss:
|
||||
case X86::BI__builtin_ia32_cmpltss:
|
||||
case X86::BI__builtin_ia32_cmpless:
|
||||
case X86::BI__builtin_ia32_cmpneqss:
|
||||
case X86::BI__builtin_ia32_cmpnltss:
|
||||
case X86::BI__builtin_ia32_cmpnless: {
|
||||
unsigned i = 0;
|
||||
const char *name = 0;
|
||||
switch (BuiltinID) {
|
||||
default: assert(0 && "Unknown compare builtin!");
|
||||
case X86::BI__builtin_ia32_cmpeqss:
|
||||
i = 0;
|
||||
name = "cmpeqss";
|
||||
break;
|
||||
case X86::BI__builtin_ia32_cmpltss:
|
||||
i = 1;
|
||||
name = "cmpltss";
|
||||
break;
|
||||
case X86::BI__builtin_ia32_cmpless:
|
||||
i = 2;
|
||||
name = "cmpless";
|
||||
break;
|
||||
case X86::BI__builtin_ia32_cmpunordss:
|
||||
i = 3;
|
||||
name = "cmpunordss";
|
||||
break;
|
||||
case X86::BI__builtin_ia32_cmpneqss:
|
||||
i = 4;
|
||||
name = "cmpneqss";
|
||||
break;
|
||||
case X86::BI__builtin_ia32_cmpnltss:
|
||||
i = 5;
|
||||
name = "cmpntlss";
|
||||
break;
|
||||
case X86::BI__builtin_ia32_cmpnless:
|
||||
i = 6;
|
||||
name = "cmpnless";
|
||||
break;
|
||||
case X86::BI__builtin_ia32_cmpordss:
|
||||
i = 7;
|
||||
name = "cmpordss";
|
||||
break;
|
||||
}
|
||||
|
||||
Ops.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, i));
|
||||
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ss);
|
||||
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
|
||||
}
|
||||
case X86::BI__builtin_ia32_cmpordps:
|
||||
case X86::BI__builtin_ia32_cmpunordps:
|
||||
case X86::BI__builtin_ia32_cmpeqps:
|
||||
case X86::BI__builtin_ia32_cmpltps:
|
||||
case X86::BI__builtin_ia32_cmpleps:
|
||||
case X86::BI__builtin_ia32_cmpneqps:
|
||||
case X86::BI__builtin_ia32_cmpngtps:
|
||||
case X86::BI__builtin_ia32_cmpnltps:
|
||||
case X86::BI__builtin_ia32_cmpgtps:
|
||||
case X86::BI__builtin_ia32_cmpgeps:
|
||||
case X86::BI__builtin_ia32_cmpngeps:
|
||||
case X86::BI__builtin_ia32_cmpnleps: {
|
||||
unsigned i = 0;
|
||||
const char *name = 0;
|
||||
bool ShouldSwap = false;
|
||||
switch (BuiltinID) {
|
||||
default: assert(0 && "Unknown compare builtin!");
|
||||
case X86::BI__builtin_ia32_cmpeqps: i = 0; name = "cmpeqps"; break;
|
||||
case X86::BI__builtin_ia32_cmpltps: i = 1; name = "cmpltps"; break;
|
||||
case X86::BI__builtin_ia32_cmpleps: i = 2; name = "cmpleps"; break;
|
||||
case X86::BI__builtin_ia32_cmpunordps: i = 3; name = "cmpunordps"; break;
|
||||
case X86::BI__builtin_ia32_cmpneqps: i = 4; name = "cmpneqps"; break;
|
||||
case X86::BI__builtin_ia32_cmpnltps: i = 5; name = "cmpntlps"; break;
|
||||
case X86::BI__builtin_ia32_cmpnleps: i = 6; name = "cmpnleps"; break;
|
||||
case X86::BI__builtin_ia32_cmpordps: i = 7; name = "cmpordps"; break;
|
||||
case X86::BI__builtin_ia32_cmpgtps:
|
||||
ShouldSwap = true;
|
||||
i = 1;
|
||||
name = "cmpgtps";
|
||||
break;
|
||||
case X86::BI__builtin_ia32_cmpgeps:
|
||||
i = 2;
|
||||
name = "cmpgeps";
|
||||
ShouldSwap = true;
|
||||
break;
|
||||
case X86::BI__builtin_ia32_cmpngtps:
|
||||
i = 5;
|
||||
name = "cmpngtps";
|
||||
ShouldSwap = true;
|
||||
break;
|
||||
case X86::BI__builtin_ia32_cmpngeps:
|
||||
i = 6;
|
||||
name = "cmpngeps";
|
||||
ShouldSwap = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ShouldSwap)
|
||||
std::swap(Ops[0], Ops[1]);
|
||||
|
||||
Ops.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, i));
|
||||
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ps);
|
||||
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
|
||||
}
|
||||
case X86::BI__builtin_ia32_movss:
|
||||
return EmitShuffleVector(Ops[0], Ops[1], 4, 1, 2, 3, "movss");
|
||||
case X86::BI__builtin_ia32_shufps:
|
||||
unsigned i = cast<ConstantInt>(Ops[2])->getZExtValue();
|
||||
return EmitShuffleVector(Ops[0], Ops[1],
|
||||
i & 0x3, (i & 0xc) >> 2,
|
||||
((i & 0x30) >> 4) + 4,
|
||||
((i & 0x60) >> 6) + 4, "shufps");
|
||||
}
|
||||
}
|
||||
|
||||
Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
|
||||
const CallExpr *E) {
|
||||
switch (BuiltinID) {
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
//===--- CGDecl.cpp - Emit LLVM Code for declarations ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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 "CodeGenModule.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "llvm/GlobalVariable.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::FileVar:
|
||||
assert(0 && "Should not see file-scope variables inside a function!");
|
||||
case Decl::ParmVar:
|
||||
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::BlockVar:
|
||||
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:
|
||||
return EmitStaticBlockVarDecl(D);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitStaticBlockVarDecl(const BlockVarDecl &D) {
|
||||
QualType Ty = D.getCanonicalType();
|
||||
assert(Ty->isConstantSizeType(getContext()) && "VLAs can't be static");
|
||||
|
||||
llvm::Value *&DMEntry = LocalDeclMap[&D];
|
||||
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
|
||||
|
||||
const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
|
||||
llvm::Constant *Init = 0;
|
||||
if (D.getInit() == 0) {
|
||||
Init = llvm::Constant::getNullValue(LTy);
|
||||
} else {
|
||||
Init = CGM.EmitGlobalInit(D.getInit());
|
||||
}
|
||||
|
||||
assert(Init && "Unable to create initialiser for static decl");
|
||||
|
||||
DMEntry =
|
||||
new llvm::GlobalVariable(LTy, false,
|
||||
llvm::GlobalValue::InternalLinkage,
|
||||
Init, D.getName(), &CGM.getModule());
|
||||
|
||||
}
|
||||
|
||||
/// EmitLocalBlockVarDecl - Emit code and set up an entry in LocalDeclMap for a
|
||||
/// variable declaration with auto, register, or no storage class specifier.
|
||||
/// These turn into simple stack objects.
|
||||
void CodeGenFunction::EmitLocalBlockVarDecl(const BlockVarDecl &D) {
|
||||
QualType Ty = D.getCanonicalType();
|
||||
|
||||
llvm::Value *DeclPtr;
|
||||
if (Ty->isConstantSizeType(getContext())) {
|
||||
// A normal fixed sized variable becomes an alloca in the entry block.
|
||||
const llvm::Type *LTy = ConvertType(Ty);
|
||||
// TODO: Alignment
|
||||
DeclPtr = CreateTempAlloca(LTy, D.getName());
|
||||
} else {
|
||||
// TODO: Create a dynamic alloca.
|
||||
assert(0 && "FIXME: Local VLAs not implemented yet");
|
||||
}
|
||||
|
||||
llvm::Value *&DMEntry = LocalDeclMap[&D];
|
||||
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
|
||||
DMEntry = DeclPtr;
|
||||
|
||||
// If this local has an initializer, emit it now.
|
||||
if (const Expr *Init = D.getInit()) {
|
||||
if (!hasAggregateLLVMType(Init->getType())) {
|
||||
llvm::Value *V = EmitScalarExpr(Init);
|
||||
Builder.CreateStore(V, DeclPtr, D.getType().isVolatileQualified());
|
||||
} else if (Init->getType()->isComplexType()) {
|
||||
EmitComplexExprIntoAddr(Init, DeclPtr, D.getType().isVolatileQualified());
|
||||
} else {
|
||||
EmitAggExpr(Init, DeclPtr, D.getType().isVolatileQualified());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit an alloca for the specified parameter and set up LocalDeclMap.
|
||||
void CodeGenFunction::EmitParmDecl(const ParmVarDecl &D, llvm::Value *Arg) {
|
||||
QualType Ty = D.getCanonicalType();
|
||||
|
||||
llvm::Value *DeclPtr;
|
||||
if (!Ty->isConstantSizeType(getContext())) {
|
||||
// Variable sized values always are passed by-reference.
|
||||
DeclPtr = Arg;
|
||||
} else {
|
||||
// A fixed sized first class variable becomes an alloca in the entry block.
|
||||
const llvm::Type *LTy = ConvertType(Ty);
|
||||
if (LTy->isFirstClassType()) {
|
||||
// TODO: Alignment
|
||||
DeclPtr = new llvm::AllocaInst(LTy, 0, std::string(D.getName())+".addr",
|
||||
AllocaInsertPt);
|
||||
|
||||
// Store the initial value into the alloca.
|
||||
Builder.CreateStore(Arg, DeclPtr);
|
||||
} else {
|
||||
// Otherwise, if this is an aggregate, just use the input pointer.
|
||||
DeclPtr = Arg;
|
||||
}
|
||||
Arg->setName(D.getName());
|
||||
}
|
||||
|
||||
llvm::Value *&DMEntry = LocalDeclMap[&D];
|
||||
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
|
||||
DMEntry = DeclPtr;
|
||||
}
|
||||
|
||||
@@ -1,520 +0,0 @@
|
||||
//===--- CGExpr.cpp - Emit LLVM Code from Expressions ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This contains code to emit Expr nodes as LLVM code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CodeGenFunction.h"
|
||||
#include "CodeGenModule.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Miscellaneous Helper Methods
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
|
||||
/// block.
|
||||
llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty,
|
||||
const char *Name) {
|
||||
return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt);
|
||||
}
|
||||
|
||||
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
|
||||
/// expression and compare the result against zero, returning an Int1Ty value.
|
||||
llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) {
|
||||
QualType BoolTy = getContext().BoolTy;
|
||||
if (!E->getType()->isComplexType())
|
||||
return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy);
|
||||
|
||||
return EmitComplexToScalarConversion(EmitComplexExpr(E), E->getType(),BoolTy);
|
||||
}
|
||||
|
||||
/// EmitAnyExpr - Emit code to compute the specified expression which can have
|
||||
/// any type. The result is returned as an RValue struct. If this is an
|
||||
/// aggregate expression, the aggloc/agglocvolatile arguments indicate where
|
||||
/// the result should be returned.
|
||||
RValue CodeGenFunction::EmitAnyExpr(const Expr *E, llvm::Value *AggLoc,
|
||||
bool isAggLocVolatile) {
|
||||
if (!hasAggregateLLVMType(E->getType()))
|
||||
return RValue::get(EmitScalarExpr(E));
|
||||
else if (E->getType()->isComplexType())
|
||||
return RValue::getComplex(EmitComplexExpr(E));
|
||||
|
||||
EmitAggExpr(E, AggLoc, isAggLocVolatile);
|
||||
return RValue::getAggregate(AggLoc);
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LValue Expression Emission
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// EmitLValue - Emit code to compute a designator that specifies the location
|
||||
/// of the expression.
|
||||
///
|
||||
/// This can return one of two things: a simple address or a bitfield
|
||||
/// reference. In either case, the LLVM Value* in the LValue structure is
|
||||
/// guaranteed to be an LLVM pointer type.
|
||||
///
|
||||
/// If this returns a bitfield reference, nothing about the pointee type of
|
||||
/// the LLVM value is known: For example, it may not be a pointer to an
|
||||
/// integer.
|
||||
///
|
||||
/// If this returns a normal address, and if the lvalue's C type is fixed
|
||||
/// size, this method guarantees that the returned pointer type will point to
|
||||
/// an LLVM type of the same size of the lvalue's type. If the lvalue has a
|
||||
/// variable length type, this is not possible.
|
||||
///
|
||||
LValue CodeGenFunction::EmitLValue(const Expr *E) {
|
||||
switch (E->getStmtClass()) {
|
||||
default: {
|
||||
WarnUnsupported(E, "l-value expression");
|
||||
llvm::Type *Ty = llvm::PointerType::getUnqual(ConvertType(E->getType()));
|
||||
return LValue::MakeAddr(llvm::UndefValue::get(Ty));
|
||||
}
|
||||
|
||||
case Expr::CallExprClass: return EmitCallExprLValue(cast<CallExpr>(E));
|
||||
case Expr::DeclRefExprClass: return EmitDeclRefLValue(cast<DeclRefExpr>(E));
|
||||
case Expr::ParenExprClass:return EmitLValue(cast<ParenExpr>(E)->getSubExpr());
|
||||
case Expr::PreDefinedExprClass:
|
||||
return EmitPreDefinedLValue(cast<PreDefinedExpr>(E));
|
||||
case Expr::StringLiteralClass:
|
||||
return EmitStringLiteralLValue(cast<StringLiteral>(E));
|
||||
|
||||
case Expr::UnaryOperatorClass:
|
||||
return EmitUnaryOpLValue(cast<UnaryOperator>(E));
|
||||
case Expr::ArraySubscriptExprClass:
|
||||
return EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E));
|
||||
case Expr::OCUVectorElementExprClass:
|
||||
return EmitOCUVectorElementExpr(cast<OCUVectorElementExpr>(E));
|
||||
case Expr::MemberExprClass: return EmitMemberExpr(cast<MemberExpr>(E));
|
||||
}
|
||||
}
|
||||
|
||||
/// EmitLoadOfLValue - Given an expression that represents a value lvalue,
|
||||
/// this method emits the address of the lvalue, then loads the result as an
|
||||
/// rvalue, returning the rvalue.
|
||||
RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) {
|
||||
if (LV.isSimple()) {
|
||||
llvm::Value *Ptr = LV.getAddress();
|
||||
const llvm::Type *EltTy =
|
||||
cast<llvm::PointerType>(Ptr->getType())->getElementType();
|
||||
|
||||
// Simple scalar l-value.
|
||||
if (EltTy->isFirstClassType())
|
||||
return RValue::get(Builder.CreateLoad(Ptr, "tmp"));
|
||||
|
||||
assert(ExprType->isFunctionType() && "Unknown scalar value");
|
||||
return RValue::get(Ptr);
|
||||
}
|
||||
|
||||
if (LV.isVectorElt()) {
|
||||
llvm::Value *Vec = Builder.CreateLoad(LV.getVectorAddr(), "tmp");
|
||||
return RValue::get(Builder.CreateExtractElement(Vec, LV.getVectorIdx(),
|
||||
"vecext"));
|
||||
}
|
||||
|
||||
// If this is a reference to a subset of the elements of a vector, either
|
||||
// shuffle the input or extract/insert them as appropriate.
|
||||
if (LV.isOCUVectorElt())
|
||||
return EmitLoadOfOCUElementLValue(LV, ExprType);
|
||||
|
||||
assert(0 && "Bitfield ref not impl!");
|
||||
//an invalid RValue, but the assert will
|
||||
//ensure that this point is never reached
|
||||
return RValue();
|
||||
}
|
||||
|
||||
// If this is a reference to a subset of the elements of a vector, either
|
||||
// shuffle the input or extract/insert them as appropriate.
|
||||
RValue CodeGenFunction::EmitLoadOfOCUElementLValue(LValue LV,
|
||||
QualType ExprType) {
|
||||
llvm::Value *Vec = Builder.CreateLoad(LV.getOCUVectorAddr(), "tmp");
|
||||
|
||||
unsigned EncFields = LV.getOCUVectorElts();
|
||||
|
||||
// If the result of the expression is a non-vector type, we must be
|
||||
// extracting a single element. Just codegen as an extractelement.
|
||||
const VectorType *ExprVT = ExprType->getAsVectorType();
|
||||
if (!ExprVT) {
|
||||
unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(0, EncFields);
|
||||
llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx);
|
||||
return RValue::get(Builder.CreateExtractElement(Vec, Elt, "tmp"));
|
||||
}
|
||||
|
||||
// If the source and destination have the same number of elements, use a
|
||||
// vector shuffle instead of insert/extracts.
|
||||
unsigned NumResultElts = ExprVT->getNumElements();
|
||||
unsigned NumSourceElts =
|
||||
cast<llvm::VectorType>(Vec->getType())->getNumElements();
|
||||
|
||||
if (NumResultElts == NumSourceElts) {
|
||||
llvm::SmallVector<llvm::Constant*, 4> Mask;
|
||||
for (unsigned i = 0; i != NumResultElts; ++i) {
|
||||
unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(i, EncFields);
|
||||
Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx));
|
||||
}
|
||||
|
||||
llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size());
|
||||
Vec = Builder.CreateShuffleVector(Vec,
|
||||
llvm::UndefValue::get(Vec->getType()),
|
||||
MaskV, "tmp");
|
||||
return RValue::get(Vec);
|
||||
}
|
||||
|
||||
// Start out with an undef of the result type.
|
||||
llvm::Value *Result = llvm::UndefValue::get(ConvertType(ExprType));
|
||||
|
||||
// Extract/Insert each element of the result.
|
||||
for (unsigned i = 0; i != NumResultElts; ++i) {
|
||||
unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(i, EncFields);
|
||||
llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx);
|
||||
Elt = Builder.CreateExtractElement(Vec, Elt, "tmp");
|
||||
|
||||
llvm::Value *OutIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
|
||||
Result = Builder.CreateInsertElement(Result, Elt, OutIdx, "tmp");
|
||||
}
|
||||
|
||||
return RValue::get(Result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
|
||||
/// lvalue, where both are guaranteed to the have the same type, and that type
|
||||
/// is 'Ty'.
|
||||
void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
|
||||
QualType Ty) {
|
||||
if (!Dst.isSimple()) {
|
||||
if (Dst.isVectorElt()) {
|
||||
// Read/modify/write the vector, inserting the new element.
|
||||
// FIXME: Volatility.
|
||||
llvm::Value *Vec = Builder.CreateLoad(Dst.getVectorAddr(), "tmp");
|
||||
Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(),
|
||||
Dst.getVectorIdx(), "vecins");
|
||||
Builder.CreateStore(Vec, Dst.getVectorAddr());
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is an update of elements of a vector, insert them as appropriate.
|
||||
if (Dst.isOCUVectorElt())
|
||||
return EmitStoreThroughOCUComponentLValue(Src, Dst, Ty);
|
||||
|
||||
assert(0 && "FIXME: Don't support store to bitfield yet");
|
||||
}
|
||||
|
||||
llvm::Value *DstAddr = Dst.getAddress();
|
||||
assert(Src.isScalar() && "Can't emit an agg store with this method");
|
||||
// FIXME: Handle volatility etc.
|
||||
const llvm::Type *SrcTy = Src.getScalarVal()->getType();
|
||||
const llvm::PointerType *DstPtr = cast<llvm::PointerType>(DstAddr->getType());
|
||||
const llvm::Type *AddrTy = DstPtr->getElementType();
|
||||
unsigned AS = DstPtr->getAddressSpace();
|
||||
|
||||
if (AddrTy != SrcTy)
|
||||
DstAddr = Builder.CreateBitCast(DstAddr,
|
||||
llvm::PointerType::get(SrcTy, AS),
|
||||
"storetmp");
|
||||
Builder.CreateStore(Src.getScalarVal(), DstAddr);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitStoreThroughOCUComponentLValue(RValue Src, LValue Dst,
|
||||
QualType Ty) {
|
||||
// This access turns into a read/modify/write of the vector. Load the input
|
||||
// value now.
|
||||
llvm::Value *Vec = Builder.CreateLoad(Dst.getOCUVectorAddr(), "tmp");
|
||||
// FIXME: Volatility.
|
||||
unsigned EncFields = Dst.getOCUVectorElts();
|
||||
|
||||
llvm::Value *SrcVal = Src.getScalarVal();
|
||||
|
||||
if (const VectorType *VTy = Ty->getAsVectorType()) {
|
||||
unsigned NumSrcElts = VTy->getNumElements();
|
||||
|
||||
// Extract/Insert each element.
|
||||
for (unsigned i = 0; i != NumSrcElts; ++i) {
|
||||
llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
|
||||
Elt = Builder.CreateExtractElement(SrcVal, Elt, "tmp");
|
||||
|
||||
unsigned Idx = OCUVectorElementExpr::getAccessedFieldNo(i, EncFields);
|
||||
llvm::Value *OutIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, Idx);
|
||||
Vec = Builder.CreateInsertElement(Vec, Elt, OutIdx, "tmp");
|
||||
}
|
||||
} else {
|
||||
// If the Src is a scalar (not a vector) it must be updating one element.
|
||||
unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(0, EncFields);
|
||||
llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx);
|
||||
Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt, "tmp");
|
||||
}
|
||||
|
||||
Builder.CreateStore(Vec, Dst.getOCUVectorAddr());
|
||||
}
|
||||
|
||||
|
||||
LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
|
||||
const ValueDecl *D = E->getDecl();
|
||||
if (isa<BlockVarDecl>(D) || isa<ParmVarDecl>(D)) {
|
||||
llvm::Value *V = LocalDeclMap[D];
|
||||
assert(V && "BlockVarDecl not entered in LocalDeclMap?");
|
||||
return LValue::MakeAddr(V);
|
||||
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
return LValue::MakeAddr(CGM.GetAddrOfFunctionDecl(FD, false));
|
||||
} else if (const FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
|
||||
return LValue::MakeAddr(CGM.GetAddrOfGlobalVar(FVD, false));
|
||||
}
|
||||
assert(0 && "Unimp declref");
|
||||
//an invalid LValue, but the assert will
|
||||
//ensure that this point is never reached.
|
||||
return LValue();
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
|
||||
// __extension__ doesn't affect lvalue-ness.
|
||||
if (E->getOpcode() == UnaryOperator::Extension)
|
||||
return EmitLValue(E->getSubExpr());
|
||||
|
||||
switch (E->getOpcode()) {
|
||||
default: assert(0 && "Unknown unary operator lvalue!");
|
||||
case UnaryOperator::Deref:
|
||||
return LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()));
|
||||
case UnaryOperator::Real:
|
||||
case UnaryOperator::Imag:
|
||||
LValue LV = EmitLValue(E->getSubExpr());
|
||||
|
||||
llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
|
||||
llvm::Constant *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty,
|
||||
E->getOpcode() == UnaryOperator::Imag);
|
||||
llvm::Value *Ops[] = {Zero, Idx};
|
||||
return LValue::MakeAddr(Builder.CreateGEP(LV.getAddress(), Ops, Ops+2,
|
||||
"idx"));
|
||||
}
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) {
|
||||
assert(!E->isWide() && "FIXME: Wide strings not supported yet!");
|
||||
const char *StrData = E->getStrData();
|
||||
unsigned Len = E->getByteLength();
|
||||
std::string StringLiteral(StrData, StrData+Len);
|
||||
return LValue::MakeAddr(CGM.GetAddrOfConstantString(StringLiteral));
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::EmitPreDefinedLValue(const PreDefinedExpr *E) {
|
||||
std::string FunctionName(CurFuncDecl->getName());
|
||||
std::string GlobalVarName;
|
||||
|
||||
switch (E->getIdentType()) {
|
||||
default:
|
||||
assert(0 && "unknown pre-defined ident type");
|
||||
case PreDefinedExpr::Func:
|
||||
GlobalVarName = "__func__.";
|
||||
break;
|
||||
case PreDefinedExpr::Function:
|
||||
GlobalVarName = "__FUNCTION__.";
|
||||
break;
|
||||
case PreDefinedExpr::PrettyFunction:
|
||||
// FIXME:: Demangle C++ method names
|
||||
GlobalVarName = "__PRETTY_FUNCTION__.";
|
||||
break;
|
||||
}
|
||||
|
||||
GlobalVarName += CurFuncDecl->getName();
|
||||
|
||||
// FIXME: Can cache/reuse these within the module.
|
||||
llvm::Constant *C=llvm::ConstantArray::get(FunctionName);
|
||||
|
||||
// Create a global variable for this.
|
||||
C = new llvm::GlobalVariable(C->getType(), true,
|
||||
llvm::GlobalValue::InternalLinkage,
|
||||
C, GlobalVarName, CurFn->getParent());
|
||||
return LValue::MakeAddr(C);
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
|
||||
// The index must always be an integer, which is not an aggregate. Emit it.
|
||||
llvm::Value *Idx = EmitScalarExpr(E->getIdx());
|
||||
|
||||
// If the base is a vector type, then we are forming a vector element lvalue
|
||||
// with this subscript.
|
||||
if (E->getLHS()->getType()->isVectorType()) {
|
||||
// Emit the vector as an lvalue to get its address.
|
||||
LValue LHS = EmitLValue(E->getLHS());
|
||||
assert(LHS.isSimple() && "Can only subscript lvalue vectors here!");
|
||||
// FIXME: This should properly sign/zero/extend or truncate Idx to i32.
|
||||
return LValue::MakeVectorElt(LHS.getAddress(), Idx);
|
||||
}
|
||||
|
||||
// The base must be a pointer, which is not an aggregate. Emit it.
|
||||
llvm::Value *Base = EmitScalarExpr(E->getBase());
|
||||
|
||||
// Extend or truncate the index type to 32 or 64-bits.
|
||||
QualType IdxTy = E->getIdx()->getType();
|
||||
bool IdxSigned = IdxTy->isSignedIntegerType();
|
||||
unsigned IdxBitwidth = cast<llvm::IntegerType>(Idx->getType())->getBitWidth();
|
||||
if (IdxBitwidth != LLVMPointerWidth)
|
||||
Idx = Builder.CreateIntCast(Idx, llvm::IntegerType::get(LLVMPointerWidth),
|
||||
IdxSigned, "idxprom");
|
||||
|
||||
// We know that the pointer points to a type of the correct size, unless the
|
||||
// size is a VLA.
|
||||
if (!E->getType()->isConstantSizeType(getContext()))
|
||||
assert(0 && "VLA idx not implemented");
|
||||
return LValue::MakeAddr(Builder.CreateGEP(Base, Idx, "arrayidx"));
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::
|
||||
EmitOCUVectorElementExpr(const OCUVectorElementExpr *E) {
|
||||
// Emit the base vector as an l-value.
|
||||
LValue Base = EmitLValue(E->getBase());
|
||||
assert(Base.isSimple() && "Can only subscript lvalue vectors here!");
|
||||
|
||||
return LValue::MakeOCUVectorElt(Base.getAddress(),
|
||||
E->getEncodedElementAccess());
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
|
||||
|
||||
bool isUnion = false;
|
||||
Expr *BaseExpr = E->getBase();
|
||||
llvm::Value *BaseValue = NULL;
|
||||
|
||||
// If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
|
||||
if (E->isArrow()) {
|
||||
BaseValue = EmitScalarExpr(BaseExpr);
|
||||
const PointerType *PTy =
|
||||
cast<PointerType>(BaseExpr->getType().getCanonicalType());
|
||||
if (PTy->getPointeeType()->isUnionType())
|
||||
isUnion = true;
|
||||
}
|
||||
else {
|
||||
LValue BaseLV = EmitLValue(BaseExpr);
|
||||
// FIXME: this isn't right for bitfields.
|
||||
BaseValue = BaseLV.getAddress();
|
||||
if (BaseExpr->getType()->isUnionType())
|
||||
isUnion = true;
|
||||
}
|
||||
|
||||
FieldDecl *Field = E->getMemberDecl();
|
||||
|
||||
assert (!Field->isBitField() && "Bit-field access is not yet implmented");
|
||||
|
||||
unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
|
||||
llvm::Value *Idxs[2] = { llvm::Constant::getNullValue(llvm::Type::Int32Ty),
|
||||
llvm::ConstantInt::get(llvm::Type::Int32Ty, idx) };
|
||||
|
||||
llvm::Value *V = Builder.CreateGEP(BaseValue,Idxs, Idxs + 2, "tmp");
|
||||
// Match union field type.
|
||||
if (isUnion) {
|
||||
const llvm::Type * FieldTy = ConvertType(Field->getType());
|
||||
const llvm::PointerType * BaseTy =
|
||||
cast<llvm::PointerType>(BaseValue->getType());
|
||||
if (FieldTy != BaseTy->getElementType()) {
|
||||
unsigned AS = BaseTy->getAddressSpace();
|
||||
V = Builder.CreateBitCast(V,
|
||||
llvm::PointerType::get(FieldTy, AS),
|
||||
"tmp");
|
||||
}
|
||||
}
|
||||
return LValue::MakeAddr(V);
|
||||
|
||||
// FIXME: If record field does not have one to one match with llvm::StructType
|
||||
// field then apply appropriate masks to select only member field bits.
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Expression Emission
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
|
||||
RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) {
|
||||
if (const ImplicitCastExpr *IcExpr =
|
||||
dyn_cast<const ImplicitCastExpr>(E->getCallee()))
|
||||
if (const DeclRefExpr *DRExpr =
|
||||
dyn_cast<const DeclRefExpr>(IcExpr->getSubExpr()))
|
||||
if (const FunctionDecl *FDecl =
|
||||
dyn_cast<const FunctionDecl>(DRExpr->getDecl()))
|
||||
if (unsigned builtinID = FDecl->getIdentifier()->getBuiltinID())
|
||||
return EmitBuiltinExpr(builtinID, E);
|
||||
|
||||
llvm::Value *Callee = EmitScalarExpr(E->getCallee());
|
||||
return EmitCallExpr(Callee, E);
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
|
||||
// Can only get l-value for call expression returning aggregate type
|
||||
RValue RV = EmitCallExpr(E);
|
||||
return LValue::MakeAddr(RV.getAggregateAddr());
|
||||
}
|
||||
|
||||
RValue CodeGenFunction::EmitCallExpr(llvm::Value *Callee, const CallExpr *E) {
|
||||
// The callee type will always be a pointer to function type, get the function
|
||||
// type.
|
||||
QualType CalleeTy = E->getCallee()->getType();
|
||||
CalleeTy = cast<PointerType>(CalleeTy.getCanonicalType())->getPointeeType();
|
||||
|
||||
// Get information about the argument types.
|
||||
FunctionTypeProto::arg_type_iterator ArgTyIt = 0, ArgTyEnd = 0;
|
||||
|
||||
// Calling unprototyped functions provides no argument info.
|
||||
if (const FunctionTypeProto *FTP = dyn_cast<FunctionTypeProto>(CalleeTy)) {
|
||||
ArgTyIt = FTP->arg_type_begin();
|
||||
ArgTyEnd = FTP->arg_type_end();
|
||||
}
|
||||
|
||||
llvm::SmallVector<llvm::Value*, 16> Args;
|
||||
|
||||
// Handle struct-return functions by passing a pointer to the location that
|
||||
// we would like to return into.
|
||||
if (hasAggregateLLVMType(E->getType())) {
|
||||
// Create a temporary alloca to hold the result of the call. :(
|
||||
Args.push_back(CreateTempAlloca(ConvertType(E->getType())));
|
||||
// FIXME: set the stret attribute on the argument.
|
||||
}
|
||||
|
||||
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
|
||||
QualType ArgTy = E->getArg(i)->getType();
|
||||
|
||||
if (!hasAggregateLLVMType(ArgTy)) {
|
||||
// Scalar argument is passed by-value.
|
||||
Args.push_back(EmitScalarExpr(E->getArg(i)));
|
||||
} else if (ArgTy->isComplexType()) {
|
||||
// Make a temporary alloca to pass the argument.
|
||||
llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy));
|
||||
EmitComplexExprIntoAddr(E->getArg(i), DestMem, false);
|
||||
Args.push_back(DestMem);
|
||||
} else {
|
||||
llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy));
|
||||
EmitAggExpr(E->getArg(i), DestMem, false);
|
||||
Args.push_back(DestMem);
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Value *V = Builder.CreateCall(Callee, &Args[0], &Args[0]+Args.size());
|
||||
if (V->getType() != llvm::Type::VoidTy)
|
||||
V->setName("call");
|
||||
else if (E->getType()->isComplexType())
|
||||
return RValue::getComplex(LoadComplexFromAddr(Args[0], false));
|
||||
else if (hasAggregateLLVMType(E->getType()))
|
||||
// Struct return.
|
||||
return RValue::getAggregate(Args[0]);
|
||||
else {
|
||||
// void return.
|
||||
assert(E->getType()->isVoidType() && "Should only have a void expr here");
|
||||
V = 0;
|
||||
}
|
||||
|
||||
return RValue::get(V);
|
||||
}
|
||||
@@ -1,301 +0,0 @@
|
||||
//===--- CGExprAgg.cpp - Emit LLVM Code from Aggregate Expressions --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This contains code to emit Aggregate Expr nodes as LLVM code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CodeGenFunction.h"
|
||||
#include "CodeGenModule.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Aggregate Expression Emitter
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN AggExprEmitter : public StmtVisitor<AggExprEmitter> {
|
||||
CodeGenFunction &CGF;
|
||||
llvm::LLVMFoldingBuilder &Builder;
|
||||
llvm::Value *DestPtr;
|
||||
bool VolatileDest;
|
||||
public:
|
||||
AggExprEmitter(CodeGenFunction &cgf, llvm::Value *destPtr, bool volatileDest)
|
||||
: CGF(cgf), Builder(CGF.Builder),
|
||||
DestPtr(destPtr), VolatileDest(volatileDest) {
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Utilities
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// EmitAggLoadOfLValue - Given an expression with aggregate type that
|
||||
/// represents a value lvalue, this method emits the address of the lvalue,
|
||||
/// then loads the result into DestPtr.
|
||||
void EmitAggLoadOfLValue(const Expr *E);
|
||||
|
||||
void EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr,
|
||||
QualType EltTy);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Visitor Methods
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
void VisitStmt(Stmt *S) {
|
||||
CGF.WarnUnsupported(S, "aggregate expression");
|
||||
}
|
||||
void VisitParenExpr(ParenExpr *PE) { Visit(PE->getSubExpr()); }
|
||||
|
||||
// l-values.
|
||||
void VisitDeclRefExpr(DeclRefExpr *DRE) { EmitAggLoadOfLValue(DRE); }
|
||||
void VisitMemberExpr(MemberExpr *ME) { EmitAggLoadOfLValue(ME); }
|
||||
void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); }
|
||||
void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); }
|
||||
|
||||
void VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
|
||||
EmitAggLoadOfLValue(E);
|
||||
}
|
||||
|
||||
// Operators.
|
||||
// case Expr::UnaryOperatorClass:
|
||||
// case Expr::CastExprClass:
|
||||
void VisitImplicitCastExpr(ImplicitCastExpr *E);
|
||||
void VisitCallExpr(const CallExpr *E);
|
||||
void VisitStmtExpr(const StmtExpr *E);
|
||||
void VisitBinaryOperator(const BinaryOperator *BO);
|
||||
void VisitBinAssign(const BinaryOperator *E);
|
||||
|
||||
|
||||
void VisitConditionalOperator(const ConditionalOperator *CO);
|
||||
void VisitInitListExpr(InitListExpr *E);
|
||||
// case Expr::ChooseExprClass:
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utilities
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void AggExprEmitter::EmitAggregateCopy(llvm::Value *DestPtr,
|
||||
llvm::Value *SrcPtr, QualType Ty) {
|
||||
assert(!Ty->isComplexType() && "Shouldn't happen for complex");
|
||||
|
||||
// Aggregate assignment turns into llvm.memcpy.
|
||||
const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
|
||||
if (DestPtr->getType() != BP)
|
||||
DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp");
|
||||
if (SrcPtr->getType() != BP)
|
||||
SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp");
|
||||
|
||||
// Get size and alignment info for this aggregate.
|
||||
std::pair<uint64_t, unsigned> TypeInfo =
|
||||
CGF.getContext().getTypeInfo(Ty, SourceLocation());
|
||||
|
||||
// FIXME: Handle variable sized types.
|
||||
const llvm::Type *IntPtr = llvm::IntegerType::get(CGF.LLVMPointerWidth);
|
||||
|
||||
llvm::Value *MemCpyOps[4] = {
|
||||
DestPtr, SrcPtr,
|
||||
// TypeInfo.first describes size in bits.
|
||||
llvm::ConstantInt::get(IntPtr, TypeInfo.first/8),
|
||||
llvm::ConstantInt::get(llvm::Type::Int32Ty, TypeInfo.second)
|
||||
};
|
||||
|
||||
Builder.CreateCall(CGF.CGM.getMemCpyFn(), MemCpyOps, MemCpyOps+4);
|
||||
}
|
||||
|
||||
|
||||
/// EmitAggLoadOfLValue - Given an expression with aggregate type that
|
||||
/// represents a value lvalue, this method emits the address of the lvalue,
|
||||
/// then loads the result into DestPtr.
|
||||
void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) {
|
||||
LValue LV = CGF.EmitLValue(E);
|
||||
assert(LV.isSimple() && "Can't have aggregate bitfield, vector, etc");
|
||||
llvm::Value *SrcPtr = LV.getAddress();
|
||||
|
||||
// If the result is ignored, don't copy from the value.
|
||||
if (DestPtr == 0)
|
||||
// FIXME: If the source is volatile, we must read from it.
|
||||
return;
|
||||
|
||||
EmitAggregateCopy(DestPtr, SrcPtr, E->getType());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Visitor Methods
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void AggExprEmitter::VisitImplicitCastExpr(ImplicitCastExpr *E)
|
||||
{
|
||||
QualType STy = E->getSubExpr()->getType().getCanonicalType();
|
||||
QualType Ty = E->getType().getCanonicalType();
|
||||
|
||||
assert(STy == Ty && "Implicit cast types must be equal");
|
||||
|
||||
Visit(E->getSubExpr());
|
||||
}
|
||||
|
||||
void AggExprEmitter::VisitCallExpr(const CallExpr *E)
|
||||
{
|
||||
RValue RV = CGF.EmitCallExpr(E);
|
||||
assert(RV.isAggregate() && "Return value must be aggregate value!");
|
||||
|
||||
// If the result is ignored, don't copy from the value.
|
||||
if (DestPtr == 0)
|
||||
// FIXME: If the source is volatile, we must read from it.
|
||||
return;
|
||||
|
||||
EmitAggregateCopy(DestPtr, RV.getAggregateAddr(), E->getType());
|
||||
}
|
||||
|
||||
void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) {
|
||||
CGF.EmitCompoundStmt(*E->getSubStmt(), true, DestPtr, VolatileDest);
|
||||
}
|
||||
|
||||
void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) {
|
||||
CGF.WarnUnsupported(E, "aggregate binary expression");
|
||||
}
|
||||
|
||||
void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
|
||||
assert(E->getLHS()->getType().getCanonicalType() ==
|
||||
E->getRHS()->getType().getCanonicalType() && "Invalid assignment");
|
||||
LValue LHS = CGF.EmitLValue(E->getLHS());
|
||||
|
||||
// Codegen the RHS so that it stores directly into the LHS.
|
||||
CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), false /*FIXME: VOLATILE LHS*/);
|
||||
|
||||
// If the result of the assignment is used, copy the RHS there also.
|
||||
if (DestPtr) {
|
||||
assert(0 && "FIXME: Chained agg assignment not implemented yet");
|
||||
}
|
||||
}
|
||||
|
||||
void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) {
|
||||
llvm::BasicBlock *LHSBlock = new llvm::BasicBlock("cond.?");
|
||||
llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("cond.:");
|
||||
llvm::BasicBlock *ContBlock = new llvm::BasicBlock("cond.cont");
|
||||
|
||||
llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
|
||||
Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
|
||||
|
||||
CGF.EmitBlock(LHSBlock);
|
||||
|
||||
// Handle the GNU extension for missing LHS.
|
||||
assert(E->getLHS() && "Must have LHS for aggregate value");
|
||||
|
||||
Visit(E->getLHS());
|
||||
Builder.CreateBr(ContBlock);
|
||||
LHSBlock = Builder.GetInsertBlock();
|
||||
|
||||
CGF.EmitBlock(RHSBlock);
|
||||
|
||||
Visit(E->getRHS());
|
||||
Builder.CreateBr(ContBlock);
|
||||
RHSBlock = Builder.GetInsertBlock();
|
||||
|
||||
CGF.EmitBlock(ContBlock);
|
||||
}
|
||||
|
||||
void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
|
||||
|
||||
unsigned NumInitElements = E->getNumInits();
|
||||
|
||||
if (!E->getType()->isArrayType()) {
|
||||
CGF.WarnUnsupported(E, "aggregate init-list expression");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<llvm::Constant*> ArrayElts;
|
||||
const llvm::PointerType *APType = cast<llvm::PointerType>(DestPtr->getType());
|
||||
const llvm::ArrayType *AType =
|
||||
cast<llvm::ArrayType>(APType->getElementType());
|
||||
|
||||
// Copy initializer elements.
|
||||
bool AllConstElements = true;
|
||||
unsigned i = 0;
|
||||
for (i = 0; i < NumInitElements; ++i) {
|
||||
if (llvm::Constant *C =
|
||||
dyn_cast<llvm::Constant>(CGF.EmitScalarExpr(E->getInit(i))))
|
||||
ArrayElts.push_back(C);
|
||||
else {
|
||||
AllConstElements = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned NumArrayElements = AType->getNumElements();
|
||||
const llvm::Type *ElementType = CGF.ConvertType(E->getInit(0)->getType());
|
||||
|
||||
if (AllConstElements) {
|
||||
// Initialize remaining array elements.
|
||||
for (/*Do not initialize i*/; i < NumArrayElements; ++i)
|
||||
ArrayElts.push_back(llvm::Constant::getNullValue(ElementType));
|
||||
|
||||
// Create global value to hold this array.
|
||||
llvm::Constant *V = llvm::ConstantArray::get(AType, ArrayElts);
|
||||
V = new llvm::GlobalVariable(V->getType(), true,
|
||||
llvm::GlobalValue::InternalLinkage,
|
||||
V, ".array",
|
||||
&CGF.CGM.getModule());
|
||||
|
||||
EmitAggregateCopy(DestPtr, V , E->getType());
|
||||
return;
|
||||
}
|
||||
|
||||
// Emit indiviudal array element stores.
|
||||
unsigned index = 0;
|
||||
llvm::Value *NextVal = NULL;
|
||||
llvm::Value *Idxs[] = {
|
||||
llvm::Constant::getNullValue(llvm::Type::Int32Ty),
|
||||
NULL
|
||||
};
|
||||
|
||||
// Emit already seen constants initializers.
|
||||
for (i = 0; i < ArrayElts.size(); i++) {
|
||||
Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, index++);
|
||||
NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2, ".array");
|
||||
Builder.CreateStore(ArrayElts[i], NextVal);
|
||||
}
|
||||
|
||||
// Emit remaining initializers
|
||||
for (/*Do not initizalize i*/; i < NumInitElements; ++i) {
|
||||
Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, index++);
|
||||
NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2, ".array");
|
||||
llvm::Value *V = CGF.EmitScalarExpr(E->getInit(i));
|
||||
Builder.CreateStore(V, NextVal);
|
||||
}
|
||||
|
||||
// Emit remaining default initializers
|
||||
for (/*Do not initialize i*/; i < NumArrayElements; ++i) {
|
||||
Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, index++);
|
||||
NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2, ".array");
|
||||
Builder.CreateStore(llvm::Constant::getNullValue(ElementType), NextVal);
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Entry Points into this File
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// EmitAggExpr - Emit the computation of the specified expression of
|
||||
/// aggregate type. The result is computed into DestPtr. Note that if
|
||||
/// DestPtr is null, the value of the aggregate expression is not needed.
|
||||
void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr,
|
||||
bool VolatileDest) {
|
||||
assert(E && hasAggregateLLVMType(E->getType()) &&
|
||||
"Invalid aggregate expression to emit");
|
||||
|
||||
AggExprEmitter(*this, DestPtr, VolatileDest).Visit(const_cast<Expr*>(E));
|
||||
}
|
||||
@@ -1,536 +0,0 @@
|
||||
//===--- CGExprComplex.cpp - Emit LLVM Code for Complex Exprs -------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This contains code to emit Expr nodes with complex types as LLVM code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CodeGenFunction.h"
|
||||
#include "CodeGenModule.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Complex Expression Emitter
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
typedef CodeGenFunction::ComplexPairTy ComplexPairTy;
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN ComplexExprEmitter
|
||||
: public StmtVisitor<ComplexExprEmitter, ComplexPairTy> {
|
||||
CodeGenFunction &CGF;
|
||||
llvm::LLVMFoldingBuilder &Builder;
|
||||
public:
|
||||
ComplexExprEmitter(CodeGenFunction &cgf) : CGF(cgf), Builder(CGF.Builder) {
|
||||
}
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Utilities
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// EmitLoadOfLValue - Given an expression with complex type that represents a
|
||||
/// value l-value, this method emits the address of the l-value, then loads
|
||||
/// and returns the result.
|
||||
ComplexPairTy EmitLoadOfLValue(const Expr *E) {
|
||||
LValue LV = CGF.EmitLValue(E);
|
||||
// FIXME: Volatile
|
||||
return EmitLoadOfComplex(LV.getAddress(), false);
|
||||
}
|
||||
|
||||
/// EmitLoadOfComplex - Given a pointer to a complex value, emit code to load
|
||||
/// the real and imaginary pieces.
|
||||
ComplexPairTy EmitLoadOfComplex(llvm::Value *SrcPtr, bool isVolatile);
|
||||
|
||||
/// EmitStoreOfComplex - Store the specified real/imag parts into the
|
||||
/// specified value pointer.
|
||||
void EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *ResPtr, bool isVol);
|
||||
|
||||
/// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType.
|
||||
ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType,
|
||||
QualType DestType);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Visitor Methods
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
ComplexPairTy VisitStmt(Stmt *S) {
|
||||
S->dump(CGF.getContext().getSourceManager());
|
||||
assert(0 && "Stmt can't have complex result type!");
|
||||
return ComplexPairTy();
|
||||
}
|
||||
ComplexPairTy VisitExpr(Expr *S);
|
||||
ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());}
|
||||
ComplexPairTy VisitImaginaryLiteral(const ImaginaryLiteral *IL);
|
||||
|
||||
// l-values.
|
||||
ComplexPairTy VisitDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); }
|
||||
ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); }
|
||||
ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); }
|
||||
|
||||
// FIXME: CompoundLiteralExpr
|
||||
|
||||
ComplexPairTy EmitCast(Expr *Op, QualType DestTy);
|
||||
ComplexPairTy VisitImplicitCastExpr(ImplicitCastExpr *E) {
|
||||
// Unlike for scalars, we don't have to worry about function->ptr demotion
|
||||
// here.
|
||||
return EmitCast(E->getSubExpr(), E->getType());
|
||||
}
|
||||
ComplexPairTy VisitCastExpr(CastExpr *E) {
|
||||
return EmitCast(E->getSubExpr(), E->getType());
|
||||
}
|
||||
ComplexPairTy VisitCallExpr(const CallExpr *E);
|
||||
ComplexPairTy VisitStmtExpr(const StmtExpr *E);
|
||||
|
||||
// Operators.
|
||||
ComplexPairTy VisitPrePostIncDec(const UnaryOperator *E,
|
||||
bool isInc, bool isPre);
|
||||
ComplexPairTy VisitUnaryPostDec(const UnaryOperator *E) {
|
||||
return VisitPrePostIncDec(E, false, false);
|
||||
}
|
||||
ComplexPairTy VisitUnaryPostInc(const UnaryOperator *E) {
|
||||
return VisitPrePostIncDec(E, true, false);
|
||||
}
|
||||
ComplexPairTy VisitUnaryPreDec(const UnaryOperator *E) {
|
||||
return VisitPrePostIncDec(E, false, true);
|
||||
}
|
||||
ComplexPairTy VisitUnaryPreInc(const UnaryOperator *E) {
|
||||
return VisitPrePostIncDec(E, true, true);
|
||||
}
|
||||
ComplexPairTy VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); }
|
||||
ComplexPairTy VisitUnaryPlus (const UnaryOperator *E) {
|
||||
return Visit(E->getSubExpr());
|
||||
}
|
||||
ComplexPairTy VisitUnaryMinus (const UnaryOperator *E);
|
||||
ComplexPairTy VisitUnaryNot (const UnaryOperator *E);
|
||||
// LNot,SizeOf,AlignOf,Real,Imag never return complex.
|
||||
ComplexPairTy VisitUnaryExtension(const UnaryOperator *E) {
|
||||
return Visit(E->getSubExpr());
|
||||
}
|
||||
|
||||
struct BinOpInfo {
|
||||
ComplexPairTy LHS;
|
||||
ComplexPairTy RHS;
|
||||
QualType Ty; // Computation Type.
|
||||
};
|
||||
|
||||
BinOpInfo EmitBinOps(const BinaryOperator *E);
|
||||
ComplexPairTy EmitCompoundAssign(const CompoundAssignOperator *E,
|
||||
ComplexPairTy (ComplexExprEmitter::*Func)
|
||||
(const BinOpInfo &));
|
||||
|
||||
ComplexPairTy EmitBinAdd(const BinOpInfo &Op);
|
||||
ComplexPairTy EmitBinSub(const BinOpInfo &Op);
|
||||
ComplexPairTy EmitBinMul(const BinOpInfo &Op);
|
||||
ComplexPairTy EmitBinDiv(const BinOpInfo &Op);
|
||||
|
||||
ComplexPairTy VisitBinMul(const BinaryOperator *E) {
|
||||
return EmitBinMul(EmitBinOps(E));
|
||||
}
|
||||
ComplexPairTy VisitBinAdd(const BinaryOperator *E) {
|
||||
return EmitBinAdd(EmitBinOps(E));
|
||||
}
|
||||
ComplexPairTy VisitBinSub(const BinaryOperator *E) {
|
||||
return EmitBinSub(EmitBinOps(E));
|
||||
}
|
||||
ComplexPairTy VisitBinDiv(const BinaryOperator *E) {
|
||||
return EmitBinDiv(EmitBinOps(E));
|
||||
}
|
||||
|
||||
// Compound assignments.
|
||||
ComplexPairTy VisitBinAddAssign(const CompoundAssignOperator *E) {
|
||||
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinAdd);
|
||||
}
|
||||
ComplexPairTy VisitBinSubAssign(const CompoundAssignOperator *E) {
|
||||
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinSub);
|
||||
}
|
||||
ComplexPairTy VisitBinMulAssign(const CompoundAssignOperator *E) {
|
||||
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinMul);
|
||||
}
|
||||
ComplexPairTy VisitBinDivAssign(const CompoundAssignOperator *E) {
|
||||
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinDiv);
|
||||
}
|
||||
|
||||
// GCC rejects rem/and/or/xor for integer complex.
|
||||
// Logical and/or always return int, never complex.
|
||||
|
||||
// No comparisons produce a complex result.
|
||||
ComplexPairTy VisitBinAssign (const BinaryOperator *E);
|
||||
ComplexPairTy VisitBinComma (const BinaryOperator *E);
|
||||
|
||||
|
||||
ComplexPairTy VisitConditionalOperator(const ConditionalOperator *CO);
|
||||
ComplexPairTy VisitChooseExpr(ChooseExpr *CE);
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utilities
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// EmitLoadOfComplex - Given an RValue reference for a complex, emit code to
|
||||
/// load the real and imaginary pieces, returning them as Real/Imag.
|
||||
ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr,
|
||||
bool isVolatile) {
|
||||
llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
|
||||
llvm::Constant *One = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1);
|
||||
|
||||
llvm::SmallString<64> Name(SrcPtr->getNameStart(),
|
||||
SrcPtr->getNameStart()+SrcPtr->getNameLen());
|
||||
|
||||
Name += ".realp";
|
||||
llvm::Value *Ops[] = {Zero, Zero};
|
||||
llvm::Value *RealPtr = Builder.CreateGEP(SrcPtr, Ops, Ops+2, Name.c_str());
|
||||
|
||||
Name.pop_back(); // .realp -> .real
|
||||
llvm::Value *Real = Builder.CreateLoad(RealPtr, isVolatile, Name.c_str());
|
||||
|
||||
Name.resize(Name.size()-4); // .real -> .imagp
|
||||
Name += "imagp";
|
||||
|
||||
Ops[1] = One; // { Ops = { Zero, One }
|
||||
llvm::Value *ImagPtr = Builder.CreateGEP(SrcPtr, Ops, Ops+2, Name.c_str());
|
||||
|
||||
Name.pop_back(); // .imagp -> .imag
|
||||
llvm::Value *Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.c_str());
|
||||
return ComplexPairTy(Real, Imag);
|
||||
}
|
||||
|
||||
/// EmitStoreOfComplex - Store the specified real/imag parts into the
|
||||
/// specified value pointer.
|
||||
void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr,
|
||||
bool isVolatile) {
|
||||
llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
|
||||
llvm::Constant *One = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1);
|
||||
|
||||
llvm::Value *Ops[] = {Zero, Zero};
|
||||
llvm::Value *RealPtr = Builder.CreateGEP(Ptr, Ops, Ops+2, "real");
|
||||
|
||||
Ops[1] = One; // { Ops = { Zero, One }
|
||||
llvm::Value *ImagPtr = Builder.CreateGEP(Ptr, Ops, Ops+2, "imag");
|
||||
|
||||
Builder.CreateStore(Val.first, RealPtr, isVolatile);
|
||||
Builder.CreateStore(Val.second, ImagPtr, isVolatile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Visitor Methods
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) {
|
||||
CGF.WarnUnsupported(E, "complex expression");
|
||||
const llvm::Type *EltTy =
|
||||
CGF.ConvertType(E->getType()->getAsComplexType()->getElementType());
|
||||
llvm::Value *U = llvm::UndefValue::get(EltTy);
|
||||
return ComplexPairTy(U, U);
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::
|
||||
VisitImaginaryLiteral(const ImaginaryLiteral *IL) {
|
||||
llvm::Value *Imag = CGF.EmitScalarExpr(IL->getSubExpr());
|
||||
return ComplexPairTy(llvm::Constant::getNullValue(Imag->getType()), Imag);
|
||||
}
|
||||
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitCallExpr(const CallExpr *E) {
|
||||
return CGF.EmitCallExpr(E).getComplexVal();
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitStmtExpr(const StmtExpr *E) {
|
||||
return CGF.EmitCompoundStmt(*E->getSubStmt(), true).getComplexVal();
|
||||
}
|
||||
|
||||
/// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType.
|
||||
ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val,
|
||||
QualType SrcType,
|
||||
QualType DestType) {
|
||||
// Get the src/dest element type.
|
||||
SrcType = cast<ComplexType>(SrcType.getCanonicalType())->getElementType();
|
||||
DestType = cast<ComplexType>(DestType.getCanonicalType())->getElementType();
|
||||
|
||||
// C99 6.3.1.6: When a value of complextype is converted to another
|
||||
// complex type, both the real and imaginary parts followthe conversion
|
||||
// rules for the corresponding real types.
|
||||
Val.first = CGF.EmitScalarConversion(Val.first, SrcType, DestType);
|
||||
Val.second = CGF.EmitScalarConversion(Val.second, SrcType, DestType);
|
||||
return Val;
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::EmitCast(Expr *Op, QualType DestTy) {
|
||||
// Two cases here: cast from (complex to complex) and (scalar to complex).
|
||||
if (Op->getType()->isComplexType())
|
||||
return EmitComplexToComplexCast(Visit(Op), Op->getType(), DestTy);
|
||||
|
||||
// C99 6.3.1.7: When a value of real type is converted to a complex type, the
|
||||
// real part of the complex result value is determined by the rules of
|
||||
// conversion to the corresponding real type and the imaginary part of the
|
||||
// complex result value is a positive zero or an unsigned zero.
|
||||
llvm::Value *Elt = CGF.EmitScalarExpr(Op);
|
||||
|
||||
// Convert the input element to the element type of the complex.
|
||||
DestTy = cast<ComplexType>(DestTy.getCanonicalType())->getElementType();
|
||||
Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy);
|
||||
|
||||
// Return (realval, 0).
|
||||
return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType()));
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
|
||||
bool isInc, bool isPre) {
|
||||
LValue LV = CGF.EmitLValue(E->getSubExpr());
|
||||
// FIXME: Handle volatile!
|
||||
ComplexPairTy InVal = EmitLoadOfComplex(LV.getAddress(), false);
|
||||
|
||||
uint64_t AmountVal = isInc ? 1 : -1;
|
||||
|
||||
llvm::Value *NextVal;
|
||||
if (isa<llvm::IntegerType>(InVal.first->getType()))
|
||||
NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal);
|
||||
else if (InVal.first->getType() == llvm::Type::FloatTy)
|
||||
// FIXME: Handle long double.
|
||||
NextVal =
|
||||
llvm::ConstantFP::get(InVal.first->getType(),
|
||||
llvm::APFloat(static_cast<float>(AmountVal)));
|
||||
else {
|
||||
// FIXME: Handle long double.
|
||||
assert(InVal.first->getType() == llvm::Type::DoubleTy);
|
||||
NextVal =
|
||||
llvm::ConstantFP::get(InVal.first->getType(),
|
||||
llvm::APFloat(static_cast<double>(AmountVal)));
|
||||
}
|
||||
|
||||
// Add the inc/dec to the real part.
|
||||
NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
|
||||
|
||||
ComplexPairTy IncVal(NextVal, InVal.second);
|
||||
|
||||
// Store the updated result through the lvalue.
|
||||
EmitStoreOfComplex(IncVal, LV.getAddress(), false); /* FIXME: Volatile */
|
||||
|
||||
// If this is a postinc, return the value read from memory, otherwise use the
|
||||
// updated value.
|
||||
return isPre ? IncVal : InVal;
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
|
||||
ComplexPairTy Op = Visit(E->getSubExpr());
|
||||
llvm::Value *ResR = Builder.CreateNeg(Op.first, "neg.r");
|
||||
llvm::Value *ResI = Builder.CreateNeg(Op.second, "neg.i");
|
||||
return ComplexPairTy(ResR, ResI);
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
|
||||
// ~(a+ib) = a + i*-b
|
||||
ComplexPairTy Op = Visit(E->getSubExpr());
|
||||
llvm::Value *ResI = Builder.CreateNeg(Op.second, "conj.i");
|
||||
return ComplexPairTy(Op.first, ResI);
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) {
|
||||
llvm::Value *ResR = Builder.CreateAdd(Op.LHS.first, Op.RHS.first, "add.r");
|
||||
llvm::Value *ResI = Builder.CreateAdd(Op.LHS.second, Op.RHS.second, "add.i");
|
||||
return ComplexPairTy(ResR, ResI);
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) {
|
||||
llvm::Value *ResR = Builder.CreateSub(Op.LHS.first, Op.RHS.first, "sub.r");
|
||||
llvm::Value *ResI = Builder.CreateSub(Op.LHS.second, Op.RHS.second, "sub.i");
|
||||
return ComplexPairTy(ResR, ResI);
|
||||
}
|
||||
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
|
||||
llvm::Value *ResRl = Builder.CreateMul(Op.LHS.first, Op.RHS.first, "mul.rl");
|
||||
llvm::Value *ResRr = Builder.CreateMul(Op.LHS.second, Op.RHS.second,"mul.rr");
|
||||
llvm::Value *ResR = Builder.CreateSub(ResRl, ResRr, "mul.r");
|
||||
|
||||
llvm::Value *ResIl = Builder.CreateMul(Op.LHS.second, Op.RHS.first, "mul.il");
|
||||
llvm::Value *ResIr = Builder.CreateMul(Op.LHS.first, Op.RHS.second, "mul.ir");
|
||||
llvm::Value *ResI = Builder.CreateAdd(ResIl, ResIr, "mul.i");
|
||||
return ComplexPairTy(ResR, ResI);
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
|
||||
llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second;
|
||||
llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second;
|
||||
|
||||
// (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
|
||||
llvm::Value *Tmp1 = Builder.CreateMul(LHSr, RHSr, "tmp"); // a*c
|
||||
llvm::Value *Tmp2 = Builder.CreateMul(LHSi, RHSi, "tmp"); // b*d
|
||||
llvm::Value *Tmp3 = Builder.CreateAdd(Tmp1, Tmp2, "tmp"); // ac+bd
|
||||
|
||||
llvm::Value *Tmp4 = Builder.CreateMul(RHSr, RHSr, "tmp"); // c*c
|
||||
llvm::Value *Tmp5 = Builder.CreateMul(RHSi, RHSi, "tmp"); // d*d
|
||||
llvm::Value *Tmp6 = Builder.CreateAdd(Tmp4, Tmp5, "tmp"); // cc+dd
|
||||
|
||||
llvm::Value *Tmp7 = Builder.CreateMul(LHSi, RHSr, "tmp"); // b*c
|
||||
llvm::Value *Tmp8 = Builder.CreateMul(LHSr, RHSi, "tmp"); // a*d
|
||||
llvm::Value *Tmp9 = Builder.CreateSub(Tmp7, Tmp8, "tmp"); // bc-ad
|
||||
|
||||
llvm::Value *DSTr, *DSTi;
|
||||
if (Tmp3->getType()->isFloatingPoint()) {
|
||||
DSTr = Builder.CreateFDiv(Tmp3, Tmp6, "tmp");
|
||||
DSTi = Builder.CreateFDiv(Tmp9, Tmp6, "tmp");
|
||||
} else {
|
||||
if (Op.Ty->getAsComplexType()->getElementType()->isUnsignedIntegerType()) {
|
||||
DSTr = Builder.CreateUDiv(Tmp3, Tmp6, "tmp");
|
||||
DSTi = Builder.CreateUDiv(Tmp9, Tmp6, "tmp");
|
||||
} else {
|
||||
DSTr = Builder.CreateSDiv(Tmp3, Tmp6, "tmp");
|
||||
DSTi = Builder.CreateSDiv(Tmp9, Tmp6, "tmp");
|
||||
}
|
||||
}
|
||||
|
||||
return ComplexPairTy(DSTr, DSTi);
|
||||
}
|
||||
|
||||
ComplexExprEmitter::BinOpInfo
|
||||
ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) {
|
||||
BinOpInfo Ops;
|
||||
Ops.LHS = Visit(E->getLHS());
|
||||
Ops.RHS = Visit(E->getRHS());
|
||||
Ops.Ty = E->getType();
|
||||
return Ops;
|
||||
}
|
||||
|
||||
|
||||
// Compound assignments.
|
||||
ComplexPairTy ComplexExprEmitter::
|
||||
EmitCompoundAssign(const CompoundAssignOperator *E,
|
||||
ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&)){
|
||||
QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType();
|
||||
|
||||
// Load the LHS and RHS operands.
|
||||
LValue LHSLV = CGF.EmitLValue(E->getLHS());
|
||||
|
||||
BinOpInfo OpInfo;
|
||||
OpInfo.Ty = E->getComputationType();
|
||||
|
||||
// We know the LHS is a complex lvalue.
|
||||
OpInfo.LHS = EmitLoadOfComplex(LHSLV.getAddress(), false);// FIXME: Volatile.
|
||||
OpInfo.LHS = EmitComplexToComplexCast(OpInfo.LHS, LHSTy, OpInfo.Ty);
|
||||
|
||||
// It is possible for the RHS to be complex or scalar.
|
||||
OpInfo.RHS = EmitCast(E->getRHS(), OpInfo.Ty);
|
||||
|
||||
// Expand the binary operator.
|
||||
ComplexPairTy Result = (this->*Func)(OpInfo);
|
||||
|
||||
// Truncate the result back to the LHS type.
|
||||
Result = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy);
|
||||
|
||||
// Store the result value into the LHS lvalue.
|
||||
EmitStoreOfComplex(Result, LHSLV.getAddress(), false); // FIXME: VOLATILE
|
||||
return Result;
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
|
||||
assert(E->getLHS()->getType().getCanonicalType() ==
|
||||
E->getRHS()->getType().getCanonicalType() && "Invalid assignment");
|
||||
// Emit the RHS.
|
||||
ComplexPairTy Val = Visit(E->getRHS());
|
||||
|
||||
// Compute the address to store into.
|
||||
LValue LHS = CGF.EmitLValue(E->getLHS());
|
||||
|
||||
// Store into it.
|
||||
// FIXME: Volatility!
|
||||
EmitStoreOfComplex(Val, LHS.getAddress(), false);
|
||||
return Val;
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) {
|
||||
CGF.EmitStmt(E->getLHS());
|
||||
return Visit(E->getRHS());
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::
|
||||
VisitConditionalOperator(const ConditionalOperator *E) {
|
||||
llvm::BasicBlock *LHSBlock = new llvm::BasicBlock("cond.?");
|
||||
llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("cond.:");
|
||||
llvm::BasicBlock *ContBlock = new llvm::BasicBlock("cond.cont");
|
||||
|
||||
llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
|
||||
Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
|
||||
|
||||
CGF.EmitBlock(LHSBlock);
|
||||
|
||||
// Handle the GNU extension for missing LHS.
|
||||
assert(E->getLHS() && "Must have LHS for complex value");
|
||||
|
||||
ComplexPairTy LHS = Visit(E->getLHS());
|
||||
Builder.CreateBr(ContBlock);
|
||||
LHSBlock = Builder.GetInsertBlock();
|
||||
|
||||
CGF.EmitBlock(RHSBlock);
|
||||
|
||||
ComplexPairTy RHS = Visit(E->getRHS());
|
||||
Builder.CreateBr(ContBlock);
|
||||
RHSBlock = Builder.GetInsertBlock();
|
||||
|
||||
CGF.EmitBlock(ContBlock);
|
||||
|
||||
// Create a PHI node for the real part.
|
||||
llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), "cond.r");
|
||||
RealPN->reserveOperandSpace(2);
|
||||
RealPN->addIncoming(LHS.first, LHSBlock);
|
||||
RealPN->addIncoming(RHS.first, RHSBlock);
|
||||
|
||||
// Create a PHI node for the imaginary part.
|
||||
llvm::PHINode *ImagPN = Builder.CreatePHI(LHS.first->getType(), "cond.i");
|
||||
ImagPN->reserveOperandSpace(2);
|
||||
ImagPN->addIncoming(LHS.second, LHSBlock);
|
||||
ImagPN->addIncoming(RHS.second, RHSBlock);
|
||||
|
||||
return ComplexPairTy(RealPN, ImagPN);
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitChooseExpr(ChooseExpr *E) {
|
||||
// Emit the LHS or RHS as appropriate.
|
||||
return Visit(E->isConditionTrue(CGF.getContext()) ? E->getLHS() :E->getRHS());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Entry Point into this File
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// EmitComplexExpr - Emit the computation of the specified expression of
|
||||
/// complex type, ignoring the result.
|
||||
ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E) {
|
||||
assert(E && E->getType()->isComplexType() &&
|
||||
"Invalid complex expression to emit");
|
||||
|
||||
return ComplexExprEmitter(*this).Visit(const_cast<Expr*>(E));
|
||||
}
|
||||
|
||||
/// EmitComplexExprIntoAddr - Emit the computation of the specified expression
|
||||
/// of complex type, storing into the specified Value*.
|
||||
void CodeGenFunction::EmitComplexExprIntoAddr(const Expr *E,
|
||||
llvm::Value *DestAddr,
|
||||
bool DestIsVolatile) {
|
||||
assert(E && E->getType()->isComplexType() &&
|
||||
"Invalid complex expression to emit");
|
||||
ComplexExprEmitter Emitter(*this);
|
||||
ComplexPairTy Val = Emitter.Visit(const_cast<Expr*>(E));
|
||||
Emitter.EmitStoreOfComplex(Val, DestAddr, DestIsVolatile);
|
||||
}
|
||||
|
||||
/// LoadComplexFromAddr - Load a complex number from the specified address.
|
||||
ComplexPairTy CodeGenFunction::LoadComplexFromAddr(llvm::Value *SrcAddr,
|
||||
bool SrcIsVolatile) {
|
||||
return ComplexExprEmitter(*this).EmitLoadOfComplex(SrcAddr, SrcIsVolatile);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
||||
//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This contains code to emit Objective-C code as LLVM code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CodeGenFunction.h"
|
||||
#include "CodeGenModule.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "llvm/Constant.h"
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E){
|
||||
std::string S(E->getString()->getStrData(), E->getString()->getByteLength());
|
||||
return CGM.GetAddrOfConstantCFString(S);
|
||||
}
|
||||
|
||||
@@ -1,502 +0,0 @@
|
||||
//===--- CGStmt.cpp - Emit LLVM Code from Statements ----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This contains code to emit Stmt nodes as LLVM code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CodeGenFunction.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Function.h"
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Statement Emission
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void CodeGenFunction::EmitStmt(const Stmt *S) {
|
||||
assert(S && "Null statement?");
|
||||
|
||||
switch (S->getStmtClass()) {
|
||||
default:
|
||||
// Must be an expression in a stmt context. Emit the value (to get
|
||||
// side-effects) and ignore the result.
|
||||
if (const Expr *E = dyn_cast<Expr>(S)) {
|
||||
if (!hasAggregateLLVMType(E->getType()))
|
||||
EmitScalarExpr(E);
|
||||
else if (E->getType()->isComplexType())
|
||||
EmitComplexExpr(E);
|
||||
else
|
||||
EmitAggExpr(E, 0, false);
|
||||
} else {
|
||||
WarnUnsupported(S, "statement");
|
||||
}
|
||||
break;
|
||||
case Stmt::NullStmtClass: break;
|
||||
case Stmt::CompoundStmtClass: EmitCompoundStmt(cast<CompoundStmt>(*S)); break;
|
||||
case Stmt::LabelStmtClass: EmitLabelStmt(cast<LabelStmt>(*S)); break;
|
||||
case Stmt::GotoStmtClass: EmitGotoStmt(cast<GotoStmt>(*S)); break;
|
||||
|
||||
case Stmt::IfStmtClass: EmitIfStmt(cast<IfStmt>(*S)); break;
|
||||
case Stmt::WhileStmtClass: EmitWhileStmt(cast<WhileStmt>(*S)); break;
|
||||
case Stmt::DoStmtClass: EmitDoStmt(cast<DoStmt>(*S)); break;
|
||||
case Stmt::ForStmtClass: EmitForStmt(cast<ForStmt>(*S)); break;
|
||||
|
||||
case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break;
|
||||
case Stmt::DeclStmtClass: EmitDeclStmt(cast<DeclStmt>(*S)); break;
|
||||
|
||||
case Stmt::BreakStmtClass: EmitBreakStmt(); break;
|
||||
case Stmt::ContinueStmtClass: EmitContinueStmt(); break;
|
||||
case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
|
||||
case Stmt::DefaultStmtClass: EmitDefaultStmt(cast<DefaultStmt>(*S)); break;
|
||||
case Stmt::CaseStmtClass: EmitCaseStmt(cast<CaseStmt>(*S)); break;
|
||||
}
|
||||
}
|
||||
|
||||
/// EmitCompoundStmt - Emit a compound statement {..} node. If GetLast is true,
|
||||
/// this captures the expression result of the last sub-statement and returns it
|
||||
/// (for use by the statement expression extension).
|
||||
RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
|
||||
llvm::Value *AggLoc, bool isAggVol) {
|
||||
// FIXME: handle vla's etc.
|
||||
if (S.body_empty() || !isa<Expr>(S.body_back())) GetLast = false;
|
||||
|
||||
for (CompoundStmt::const_body_iterator I = S.body_begin(),
|
||||
E = S.body_end()-GetLast; I != E; ++I)
|
||||
EmitStmt(*I);
|
||||
|
||||
|
||||
if (!GetLast)
|
||||
return RValue::get(0);
|
||||
|
||||
return EmitAnyExpr(cast<Expr>(S.body_back()), AggLoc);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB) {
|
||||
// Emit a branch from this block to the next one if this was a real block. If
|
||||
// this was just a fall-through block after a terminator, don't emit it.
|
||||
llvm::BasicBlock *LastBB = Builder.GetInsertBlock();
|
||||
|
||||
if (LastBB->getTerminator()) {
|
||||
// If the previous block is already terminated, don't touch it.
|
||||
} else if (LastBB->empty() && LastBB->getValueName() == 0) {
|
||||
// If the last block was an empty placeholder, remove it now.
|
||||
// TODO: cache and reuse these.
|
||||
Builder.GetInsertBlock()->eraseFromParent();
|
||||
} else {
|
||||
// Otherwise, create a fall-through branch.
|
||||
Builder.CreateBr(BB);
|
||||
}
|
||||
CurFn->getBasicBlockList().push_back(BB);
|
||||
Builder.SetInsertPoint(BB);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
|
||||
llvm::BasicBlock *NextBB = getBasicBlockForLabel(&S);
|
||||
|
||||
EmitBlock(NextBB);
|
||||
EmitStmt(S.getSubStmt());
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
|
||||
Builder.CreateBr(getBasicBlockForLabel(S.getLabel()));
|
||||
|
||||
// Emit a block after the branch so that dead code after a goto has some place
|
||||
// to go.
|
||||
Builder.SetInsertPoint(new llvm::BasicBlock("", CurFn));
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
|
||||
// C99 6.8.4.1: The first substatement is executed if the expression compares
|
||||
// unequal to 0. The condition must be a scalar type.
|
||||
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
|
||||
|
||||
llvm::BasicBlock *ContBlock = new llvm::BasicBlock("ifend");
|
||||
llvm::BasicBlock *ThenBlock = new llvm::BasicBlock("ifthen");
|
||||
llvm::BasicBlock *ElseBlock = ContBlock;
|
||||
|
||||
if (S.getElse())
|
||||
ElseBlock = new llvm::BasicBlock("ifelse");
|
||||
|
||||
// Insert the conditional branch.
|
||||
Builder.CreateCondBr(BoolCondVal, ThenBlock, ElseBlock);
|
||||
|
||||
// Emit the 'then' code.
|
||||
EmitBlock(ThenBlock);
|
||||
EmitStmt(S.getThen());
|
||||
llvm::BasicBlock *BB = Builder.GetInsertBlock();
|
||||
if (isDummyBlock(BB)) {
|
||||
BB->eraseFromParent();
|
||||
Builder.SetInsertPoint(ThenBlock);
|
||||
}
|
||||
else
|
||||
Builder.CreateBr(ContBlock);
|
||||
|
||||
// Emit the 'else' code if present.
|
||||
if (const Stmt *Else = S.getElse()) {
|
||||
EmitBlock(ElseBlock);
|
||||
EmitStmt(Else);
|
||||
llvm::BasicBlock *BB = Builder.GetInsertBlock();
|
||||
if (isDummyBlock(BB)) {
|
||||
BB->eraseFromParent();
|
||||
Builder.SetInsertPoint(ElseBlock);
|
||||
}
|
||||
else
|
||||
Builder.CreateBr(ContBlock);
|
||||
}
|
||||
|
||||
// Emit the continuation block for code after the if.
|
||||
EmitBlock(ContBlock);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
|
||||
// Emit the header for the loop, insert it, which will create an uncond br to
|
||||
// it.
|
||||
llvm::BasicBlock *LoopHeader = new llvm::BasicBlock("whilecond");
|
||||
EmitBlock(LoopHeader);
|
||||
|
||||
// Evaluate the conditional in the while header. C99 6.8.5.1: The evaluation
|
||||
// of the controlling expression takes place before each execution of the loop
|
||||
// body.
|
||||
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
|
||||
|
||||
// while(1) is common, avoid extra exit blocks. Be sure
|
||||
// to correctly handle break/continue though.
|
||||
bool EmitBoolCondBranch = true;
|
||||
if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
|
||||
if (C->isOne())
|
||||
EmitBoolCondBranch = false;
|
||||
|
||||
// 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.
|
||||
if (EmitBoolCondBranch)
|
||||
Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock);
|
||||
|
||||
// Store the blocks to use for break and continue.
|
||||
BreakContinueStack.push_back(BreakContinue(ExitBlock, LoopHeader));
|
||||
|
||||
// Emit the loop body.
|
||||
EmitBlock(LoopBody);
|
||||
EmitStmt(S.getBody());
|
||||
|
||||
BreakContinueStack.pop_back();
|
||||
|
||||
// Cycle to the condition.
|
||||
Builder.CreateBr(LoopHeader);
|
||||
|
||||
// Emit the exit block.
|
||||
EmitBlock(ExitBlock);
|
||||
|
||||
// If LoopHeader is a simple forwarding block then eliminate it.
|
||||
if (!EmitBoolCondBranch
|
||||
&& &LoopHeader->front() == LoopHeader->getTerminator()) {
|
||||
LoopHeader->replaceAllUsesWith(LoopBody);
|
||||
LoopHeader->getTerminator()->eraseFromParent();
|
||||
LoopHeader->eraseFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
|
||||
// Emit the body for the loop, insert it, which will create an uncond br to
|
||||
// it.
|
||||
llvm::BasicBlock *LoopBody = new llvm::BasicBlock("dobody");
|
||||
llvm::BasicBlock *AfterDo = new llvm::BasicBlock("afterdo");
|
||||
EmitBlock(LoopBody);
|
||||
|
||||
llvm::BasicBlock *DoCond = new llvm::BasicBlock("docond");
|
||||
|
||||
// Store the blocks to use for break and continue.
|
||||
BreakContinueStack.push_back(BreakContinue(AfterDo, DoCond));
|
||||
|
||||
// Emit the body of the loop into the block.
|
||||
EmitStmt(S.getBody());
|
||||
|
||||
BreakContinueStack.pop_back();
|
||||
|
||||
EmitBlock(DoCond);
|
||||
|
||||
// C99 6.8.5.2: "The evaluation of the controlling expression takes place
|
||||
// after each execution of the loop body."
|
||||
|
||||
// Evaluate the conditional in the while header.
|
||||
// C99 6.8.5p2/p4: The first substatement is executed if the expression
|
||||
// compares unequal to 0. The condition must be a scalar type.
|
||||
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
|
||||
|
||||
// "do {} while (0)" is common in macros, avoid extra blocks. Be sure
|
||||
// to correctly handle break/continue though.
|
||||
bool EmitBoolCondBranch = true;
|
||||
if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
|
||||
if (C->isZero())
|
||||
EmitBoolCondBranch = false;
|
||||
|
||||
// As long as the condition is true, iterate the loop.
|
||||
if (EmitBoolCondBranch)
|
||||
Builder.CreateCondBr(BoolCondVal, LoopBody, AfterDo);
|
||||
|
||||
// Emit the exit block.
|
||||
EmitBlock(AfterDo);
|
||||
|
||||
// If DoCond is a simple forwarding block then eliminate it.
|
||||
if (!EmitBoolCondBranch && &DoCond->front() == DoCond->getTerminator()) {
|
||||
DoCond->replaceAllUsesWith(AfterDo);
|
||||
DoCond->getTerminator()->eraseFromParent();
|
||||
DoCond->eraseFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitForStmt(const ForStmt &S) {
|
||||
// FIXME: What do we do if the increment (f.e.) contains a stmt expression,
|
||||
// which contains a continue/break?
|
||||
// TODO: We could keep track of whether the loop body contains any
|
||||
// break/continue statements and not create unnecessary blocks (like
|
||||
// "afterfor" for a condless loop) if it doesn't.
|
||||
|
||||
// Evaluate the first part before the loop.
|
||||
if (S.getInit())
|
||||
EmitStmt(S.getInit());
|
||||
|
||||
// Start the loop with a block that tests the condition.
|
||||
llvm::BasicBlock *CondBlock = new llvm::BasicBlock("forcond");
|
||||
llvm::BasicBlock *AfterFor = new llvm::BasicBlock("afterfor");
|
||||
|
||||
EmitBlock(CondBlock);
|
||||
|
||||
// Evaluate the condition if present. If not, treat it as a non-zero-constant
|
||||
// according to 6.8.5.3p2, aka, true.
|
||||
if (S.getCond()) {
|
||||
// C99 6.8.5p2/p4: The first substatement is executed if the expression
|
||||
// compares unequal to 0. The condition must be a scalar type.
|
||||
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
|
||||
|
||||
// As long as the condition is true, iterate the loop.
|
||||
llvm::BasicBlock *ForBody = new llvm::BasicBlock("forbody");
|
||||
Builder.CreateCondBr(BoolCondVal, ForBody, AfterFor);
|
||||
EmitBlock(ForBody);
|
||||
} else {
|
||||
// Treat it as a non-zero constant. Don't even create a new block for the
|
||||
// body, just fall into it.
|
||||
}
|
||||
|
||||
// If the for loop doesn't have an increment we can just use the
|
||||
// condition as the continue block.
|
||||
llvm::BasicBlock *ContinueBlock;
|
||||
if (S.getInc())
|
||||
ContinueBlock = new llvm::BasicBlock("forinc");
|
||||
else
|
||||
ContinueBlock = CondBlock;
|
||||
|
||||
// Store the blocks to use for break and continue.
|
||||
BreakContinueStack.push_back(BreakContinue(AfterFor, ContinueBlock));
|
||||
|
||||
// If the condition is true, execute the body of the for stmt.
|
||||
EmitStmt(S.getBody());
|
||||
|
||||
BreakContinueStack.pop_back();
|
||||
|
||||
if (S.getInc())
|
||||
EmitBlock(ContinueBlock);
|
||||
|
||||
// If there is an increment, emit it next.
|
||||
if (S.getInc())
|
||||
EmitStmt(S.getInc());
|
||||
|
||||
// Finally, branch back up to the condition for the next iteration.
|
||||
Builder.CreateBr(CondBlock);
|
||||
|
||||
// Emit the fall-through block.
|
||||
EmitBlock(AfterFor);
|
||||
}
|
||||
|
||||
/// EmitReturnStmt - Note that due to GCC extensions, this can have an operand
|
||||
/// if the function returns void, or may be missing one if the function returns
|
||||
/// non-void. Fun stuff :).
|
||||
void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
|
||||
// Emit the result value, even if unused, to evalute the side effects.
|
||||
const Expr *RV = S.getRetValue();
|
||||
|
||||
QualType FnRetTy = CurFuncDecl->getType().getCanonicalType();
|
||||
FnRetTy = cast<FunctionType>(FnRetTy)->getResultType();
|
||||
|
||||
if (FnRetTy->isVoidType()) {
|
||||
// If the function returns void, emit ret void.
|
||||
Builder.CreateRetVoid();
|
||||
} else if (RV == 0) {
|
||||
// Handle "return;" in a function that returns a value.
|
||||
const llvm::Type *RetTy = CurFn->getFunctionType()->getReturnType();
|
||||
if (RetTy == llvm::Type::VoidTy)
|
||||
Builder.CreateRetVoid(); // struct return etc.
|
||||
else
|
||||
Builder.CreateRet(llvm::UndefValue::get(RetTy));
|
||||
} else if (!hasAggregateLLVMType(RV->getType())) {
|
||||
Builder.CreateRet(EmitScalarExpr(RV));
|
||||
} else if (RV->getType()->isComplexType()) {
|
||||
llvm::Value *SRetPtr = CurFn->arg_begin();
|
||||
EmitComplexExprIntoAddr(RV, SRetPtr, false);
|
||||
} else {
|
||||
llvm::Value *SRetPtr = CurFn->arg_begin();
|
||||
EmitAggExpr(RV, SRetPtr, false);
|
||||
}
|
||||
|
||||
// Emit a block after the branch so that dead code after a return has some
|
||||
// place to go.
|
||||
EmitBlock(new llvm::BasicBlock());
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
|
||||
for (const ScopedDecl *Decl = S.getDecl(); Decl;
|
||||
Decl = Decl->getNextDeclarator())
|
||||
EmitDecl(*Decl);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitBreakStmt() {
|
||||
assert(!BreakContinueStack.empty() && "break stmt not in a loop or switch!");
|
||||
|
||||
llvm::BasicBlock *Block = BreakContinueStack.back().BreakBlock;
|
||||
Builder.CreateBr(Block);
|
||||
EmitBlock(new llvm::BasicBlock());
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitContinueStmt() {
|
||||
assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
|
||||
|
||||
llvm::BasicBlock *Block = BreakContinueStack.back().ContinueBlock;
|
||||
Builder.CreateBr(Block);
|
||||
EmitBlock(new llvm::BasicBlock());
|
||||
}
|
||||
|
||||
/// EmitCaseStmtRange - If case statement range is not too big then
|
||||
/// add multiple cases to switch instruction, one for each value within
|
||||
/// the range. If range is too big then emit "if" condition check.
|
||||
void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
|
||||
assert (S.getRHS() && "Unexpected RHS value in CaseStmt");
|
||||
|
||||
const Expr *L = S.getLHS();
|
||||
const Expr *R = S.getRHS();
|
||||
llvm::ConstantInt *LV = cast<llvm::ConstantInt>(EmitScalarExpr(L));
|
||||
llvm::ConstantInt *RV = cast<llvm::ConstantInt>(EmitScalarExpr(R));
|
||||
llvm::APInt LHS = LV->getValue();
|
||||
const llvm::APInt &RHS = RV->getValue();
|
||||
|
||||
llvm::APInt Range = RHS - LHS;
|
||||
if (Range.ult(llvm::APInt(Range.getBitWidth(), 64))) {
|
||||
// Range is small enough to add multiple switch instruction cases.
|
||||
StartBlock("sw.bb");
|
||||
llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
|
||||
SwitchInsn->addCase(LV, CaseDest);
|
||||
LHS++;
|
||||
while (LHS != RHS) {
|
||||
SwitchInsn->addCase(llvm::ConstantInt::get(LHS), CaseDest);
|
||||
LHS++;
|
||||
}
|
||||
SwitchInsn->addCase(RV, CaseDest);
|
||||
EmitStmt(S.getSubStmt());
|
||||
return;
|
||||
}
|
||||
|
||||
// The range is too big. Emit "if" condition.
|
||||
llvm::BasicBlock *FalseDest = NULL;
|
||||
llvm::BasicBlock *CaseDest = new llvm::BasicBlock("sw.bb");
|
||||
|
||||
// If we have already seen one case statement range for this switch
|
||||
// instruction then piggy-back otherwise use default block as false
|
||||
// destination.
|
||||
if (CaseRangeBlock)
|
||||
FalseDest = CaseRangeBlock;
|
||||
else
|
||||
FalseDest = SwitchInsn->getDefaultDest();
|
||||
|
||||
// Start new block to hold case statement range check instructions.
|
||||
StartBlock("case.range");
|
||||
CaseRangeBlock = Builder.GetInsertBlock();
|
||||
|
||||
// Emit range check.
|
||||
llvm::Value *Diff =
|
||||
Builder.CreateSub(SwitchInsn->getCondition(), LV, "tmp");
|
||||
llvm::Value *Cond =
|
||||
Builder.CreateICmpULE(Diff, llvm::ConstantInt::get(Range), "tmp");
|
||||
Builder.CreateCondBr(Cond, CaseDest, FalseDest);
|
||||
|
||||
// Now emit case statement body.
|
||||
EmitBlock(CaseDest);
|
||||
EmitStmt(S.getSubStmt());
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
|
||||
if (S.getRHS()) {
|
||||
EmitCaseStmtRange(S);
|
||||
return;
|
||||
}
|
||||
|
||||
StartBlock("sw.bb");
|
||||
llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
|
||||
llvm::APSInt CaseVal(32);
|
||||
S.getLHS()->isIntegerConstantExpr(CaseVal, getContext());
|
||||
llvm::ConstantInt *LV = llvm::ConstantInt::get(CaseVal);
|
||||
SwitchInsn->addCase(LV, CaseDest);
|
||||
EmitStmt(S.getSubStmt());
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) {
|
||||
StartBlock("sw.default");
|
||||
// Current insert block is the default destination.
|
||||
SwitchInsn->setSuccessor(0, Builder.GetInsertBlock());
|
||||
EmitStmt(S.getSubStmt());
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
|
||||
llvm::Value *CondV = EmitScalarExpr(S.getCond());
|
||||
|
||||
// Handle nested switch statements.
|
||||
llvm::SwitchInst *SavedSwitchInsn = SwitchInsn;
|
||||
llvm::BasicBlock *SavedCRBlock = CaseRangeBlock;
|
||||
CaseRangeBlock = NULL;
|
||||
|
||||
// Create basic block to hold stuff that comes after switch statement.
|
||||
// Initially use it to hold DefaultStmt.
|
||||
llvm::BasicBlock *NextBlock = new llvm::BasicBlock("after.sw");
|
||||
SwitchInsn = Builder.CreateSwitch(CondV, NextBlock);
|
||||
|
||||
// All break statements jump to NextBlock. If BreakContinueStack is non empty
|
||||
// then reuse last ContinueBlock.
|
||||
llvm::BasicBlock *ContinueBlock = NULL;
|
||||
if (!BreakContinueStack.empty())
|
||||
ContinueBlock = BreakContinueStack.back().ContinueBlock;
|
||||
BreakContinueStack.push_back(BreakContinue(NextBlock, ContinueBlock));
|
||||
|
||||
// Emit switch body.
|
||||
EmitStmt(S.getBody());
|
||||
BreakContinueStack.pop_back();
|
||||
|
||||
// If one or more case statement range is seen then use CaseRangeBlock
|
||||
// as the default block. False edge of CaseRangeBlock will lead to
|
||||
// original default block.
|
||||
if (CaseRangeBlock)
|
||||
SwitchInsn->setSuccessor(0, CaseRangeBlock);
|
||||
|
||||
// Prune insert block if it is dummy.
|
||||
llvm::BasicBlock *BB = Builder.GetInsertBlock();
|
||||
if (isDummyBlock(BB))
|
||||
BB->eraseFromParent();
|
||||
else // Otherwise, branch to continuation.
|
||||
Builder.CreateBr(NextBlock);
|
||||
|
||||
// Place NextBlock as the new insert point.
|
||||
CurFn->getBasicBlockList().push_back(NextBlock);
|
||||
Builder.SetInsertPoint(NextBlock);
|
||||
SwitchInsn = SavedSwitchInsn;
|
||||
CaseRangeBlock = SavedCRBlock;
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
//===--- CodeGenFunction.cpp - Emit LLVM Code from ASTs for a Function ----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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"
|
||||
#include "llvm/Support/CFG.h"
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
|
||||
: CGM(cgm), Target(CGM.getContext().Target), SwitchInsn(NULL),
|
||||
CaseRangeBlock(NULL) {}
|
||||
|
||||
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->isReferenceType() &&
|
||||
!T->isVoidType() && !T->isVectorType() && !T->isFunctionType();
|
||||
}
|
||||
|
||||
|
||||
void CodeGenFunction::GenerateCode(const FunctionDecl *FD) {
|
||||
LLVMIntTy = ConvertType(getContext().IntTy);
|
||||
LLVMPointerWidth = static_cast<unsigned>(
|
||||
getContext().getTypeSize(getContext().getPointerType(getContext().VoidTy),
|
||||
SourceLocation()));
|
||||
|
||||
CurFuncDecl = FD;
|
||||
CurFn = cast<llvm::Function>(CGM.GetAddrOfFunctionDecl(FD, true));
|
||||
assert(CurFn->isDeclaration() && "Function already has body?");
|
||||
|
||||
// TODO: Set up linkage and many other things. Note, this is a simple
|
||||
// approximation of what we really want.
|
||||
if (FD->getStorageClass() == FunctionDecl::Static)
|
||||
CurFn->setLinkage(llvm::Function::InternalLinkage);
|
||||
else if (FD->isInline())
|
||||
CurFn->setLinkage(llvm::Function::WeakLinkage);
|
||||
|
||||
llvm::BasicBlock *EntryBB = new llvm::BasicBlock("entry", CurFn);
|
||||
|
||||
// Create a marker to make it easy to insert allocas into the entryblock
|
||||
// later. Don't create this with the builder, because we don't want it
|
||||
// folded.
|
||||
llvm::Value *Undef = llvm::UndefValue::get(llvm::Type::Int32Ty);
|
||||
AllocaInsertPt = new llvm::BitCastInst(Undef, llvm::Type::Int32Ty, "allocapt",
|
||||
EntryBB);
|
||||
|
||||
Builder.SetInsertPoint(EntryBB);
|
||||
|
||||
// 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. If insert point
|
||||
// is a dummy block with no predecessors then remove the block itself.
|
||||
llvm::BasicBlock *BB = Builder.GetInsertBlock();
|
||||
if (isDummyBlock(BB))
|
||||
BB->eraseFromParent();
|
||||
else {
|
||||
// FIXME: if this is C++ main, this should return 0.
|
||||
if (CurFn->getReturnType() == llvm::Type::VoidTy)
|
||||
Builder.CreateRetVoid();
|
||||
else
|
||||
Builder.CreateRet(llvm::UndefValue::get(CurFn->getReturnType()));
|
||||
}
|
||||
assert(BreakContinueStack.empty() &&
|
||||
"mismatched push/pop in break/continue stack!");
|
||||
|
||||
// Remove the AllocaInsertPt instruction, which is just a convenience for us.
|
||||
AllocaInsertPt->eraseFromParent();
|
||||
AllocaInsertPt = 0;
|
||||
|
||||
// Verify that the function is well formed.
|
||||
assert(!verifyFunction(*CurFn));
|
||||
}
|
||||
|
||||
/// isDummyBlock - Return true if BB is an empty basic block
|
||||
/// with no predecessors.
|
||||
bool CodeGenFunction::isDummyBlock(const llvm::BasicBlock *BB) {
|
||||
if (BB->empty() && pred_begin(BB) == pred_end(BB))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// StartBlock - Start new block named N. If insert block is a dummy block
|
||||
/// then reuse it.
|
||||
void CodeGenFunction::StartBlock(const char *N) {
|
||||
llvm::BasicBlock *BB = Builder.GetInsertBlock();
|
||||
if (!isDummyBlock(BB))
|
||||
EmitBlock(new llvm::BasicBlock(N));
|
||||
else
|
||||
BB->setName(N);
|
||||
}
|
||||
|
||||
/// getCGRecordLayout - Return record layout info.
|
||||
const CGRecordLayout *CodeGenFunction::getCGRecordLayout(CodeGenTypes &CGT,
|
||||
QualType RTy) {
|
||||
assert (isa<RecordType>(RTy)
|
||||
&& "Unexpected type. RecordType expected here.");
|
||||
|
||||
const llvm::Type *Ty = ConvertType(RTy);
|
||||
assert (Ty && "Unable to find llvm::Type");
|
||||
|
||||
return CGT.getCGRecordLayout(Ty);
|
||||
}
|
||||
|
||||
/// WarnUnsupported - Print out a warning that codegen doesn't support the
|
||||
/// specified stmt yet.
|
||||
void CodeGenFunction::WarnUnsupported(const Stmt *S, const char *Type) {
|
||||
CGM.WarnUnsupported(S, Type);
|
||||
}
|
||||
|
||||
@@ -1,444 +0,0 @@
|
||||
//===--- CodeGenFunction.h - Per-Function state for LLVM CodeGen ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the internal per-function state used for llvm translation.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CODEGEN_CODEGENFUNCTION_H
|
||||
#define CODEGEN_CODEGENFUNCTION_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/LLVMBuilder.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
class FunctionDecl;
|
||||
class TargetInfo;
|
||||
class QualType;
|
||||
class FunctionTypeProto;
|
||||
|
||||
class Stmt;
|
||||
class CompoundStmt;
|
||||
class LabelStmt;
|
||||
class GotoStmt;
|
||||
class IfStmt;
|
||||
class WhileStmt;
|
||||
class DoStmt;
|
||||
class ForStmt;
|
||||
class ReturnStmt;
|
||||
class DeclStmt;
|
||||
class CaseStmt;
|
||||
class DefaultStmt;
|
||||
class SwitchStmt;
|
||||
|
||||
class Expr;
|
||||
class DeclRefExpr;
|
||||
class StringLiteral;
|
||||
class IntegerLiteral;
|
||||
class FloatingLiteral;
|
||||
class CharacterLiteral;
|
||||
class TypesCompatibleExpr;
|
||||
|
||||
class ImplicitCastExpr;
|
||||
class CastExpr;
|
||||
class CallExpr;
|
||||
class UnaryOperator;
|
||||
class BinaryOperator;
|
||||
class CompoundAssignOperator;
|
||||
class ArraySubscriptExpr;
|
||||
class OCUVectorElementExpr;
|
||||
class ConditionalOperator;
|
||||
class ChooseExpr;
|
||||
class PreDefinedExpr;
|
||||
class ObjCStringLiteral;
|
||||
class MemberExpr;
|
||||
|
||||
class BlockVarDecl;
|
||||
class EnumConstantDecl;
|
||||
class ParmVarDecl;
|
||||
namespace CodeGen {
|
||||
class CodeGenModule;
|
||||
class CodeGenTypes;
|
||||
class CGRecordLayout;
|
||||
|
||||
/// RValue - This trivial value class is used to represent the result of an
|
||||
/// expression that is evaluated. It can be one of three things: either a
|
||||
/// simple LLVM SSA value, a pair of SSA values for complex numbers, or the
|
||||
/// address of an aggregate value in memory.
|
||||
class RValue {
|
||||
llvm::Value *V1, *V2;
|
||||
// TODO: Encode this into the low bit of pointer for more efficient
|
||||
// return-by-value.
|
||||
enum { Scalar, Complex, Aggregate } Flavor;
|
||||
|
||||
// FIXME: Aggregate rvalues need to retain information about whether they are
|
||||
// volatile or not.
|
||||
public:
|
||||
|
||||
bool isScalar() const { return Flavor == Scalar; }
|
||||
bool isComplex() const { return Flavor == Complex; }
|
||||
bool isAggregate() const { return Flavor == Aggregate; }
|
||||
|
||||
/// getScalar() - Return the Value* of this scalar value.
|
||||
llvm::Value *getScalarVal() const {
|
||||
assert(isScalar() && "Not a scalar!");
|
||||
return V1;
|
||||
}
|
||||
|
||||
/// getComplexVal - Return the real/imag components of this complex value.
|
||||
///
|
||||
std::pair<llvm::Value *, llvm::Value *> getComplexVal() const {
|
||||
return std::pair<llvm::Value *, llvm::Value *>(V1, V2);
|
||||
}
|
||||
|
||||
/// getAggregateAddr() - Return the Value* of the address of the aggregate.
|
||||
llvm::Value *getAggregateAddr() const {
|
||||
assert(isAggregate() && "Not an aggregate!");
|
||||
return V1;
|
||||
}
|
||||
|
||||
static RValue get(llvm::Value *V) {
|
||||
RValue ER;
|
||||
ER.V1 = V;
|
||||
ER.Flavor = Scalar;
|
||||
return ER;
|
||||
}
|
||||
static RValue getComplex(llvm::Value *V1, llvm::Value *V2) {
|
||||
RValue ER;
|
||||
ER.V1 = V1;
|
||||
ER.V2 = V2;
|
||||
ER.Flavor = Complex;
|
||||
return ER;
|
||||
}
|
||||
static RValue getComplex(const std::pair<llvm::Value *, llvm::Value *> &C) {
|
||||
RValue ER;
|
||||
ER.V1 = C.first;
|
||||
ER.V2 = C.second;
|
||||
ER.Flavor = Complex;
|
||||
return ER;
|
||||
}
|
||||
static RValue getAggregate(llvm::Value *V) {
|
||||
RValue ER;
|
||||
ER.V1 = V;
|
||||
ER.Flavor = Aggregate;
|
||||
return ER;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// LValue - This represents an lvalue references. Because C/C++ allow
|
||||
/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
|
||||
/// bitrange.
|
||||
class LValue {
|
||||
// FIXME: Volatility. Restrict?
|
||||
// alignment?
|
||||
|
||||
enum {
|
||||
Simple, // This is a normal l-value, use getAddress().
|
||||
VectorElt, // This is a vector element l-value (V[i]), use getVector*
|
||||
BitField, // This is a bitfield l-value, use getBitfield*.
|
||||
OCUVectorElt // This is an ocu vector subset, use getOCUVectorComp
|
||||
} LVType;
|
||||
|
||||
llvm::Value *V;
|
||||
|
||||
union {
|
||||
llvm::Value *VectorIdx; // Index into a vector subscript: V[i]
|
||||
unsigned VectorElts; // Encoded OCUVector element subset: V.xyx
|
||||
};
|
||||
public:
|
||||
bool isSimple() const { return LVType == Simple; }
|
||||
bool isVectorElt() const { return LVType == VectorElt; }
|
||||
bool isBitfield() const { return LVType == BitField; }
|
||||
bool isOCUVectorElt() const { return LVType == OCUVectorElt; }
|
||||
|
||||
// simple lvalue
|
||||
llvm::Value *getAddress() const { assert(isSimple()); return V; }
|
||||
// vector elt lvalue
|
||||
llvm::Value *getVectorAddr() const { assert(isVectorElt()); return V; }
|
||||
llvm::Value *getVectorIdx() const { assert(isVectorElt()); return VectorIdx; }
|
||||
// ocu vector elements.
|
||||
llvm::Value *getOCUVectorAddr() const { assert(isOCUVectorElt()); return V; }
|
||||
unsigned getOCUVectorElts() const {
|
||||
assert(isOCUVectorElt());
|
||||
return VectorElts;
|
||||
}
|
||||
|
||||
|
||||
static LValue MakeAddr(llvm::Value *V) {
|
||||
LValue R;
|
||||
R.LVType = Simple;
|
||||
R.V = V;
|
||||
return R;
|
||||
}
|
||||
|
||||
static LValue MakeVectorElt(llvm::Value *Vec, llvm::Value *Idx) {
|
||||
LValue R;
|
||||
R.LVType = VectorElt;
|
||||
R.V = Vec;
|
||||
R.VectorIdx = Idx;
|
||||
return R;
|
||||
}
|
||||
|
||||
static LValue MakeOCUVectorElt(llvm::Value *Vec, unsigned Elements) {
|
||||
LValue R;
|
||||
R.LVType = OCUVectorElt;
|
||||
R.V = Vec;
|
||||
R.VectorElts = Elements;
|
||||
return R;
|
||||
}
|
||||
};
|
||||
|
||||
/// CodeGenFunction - This class organizes the per-function state that is used
|
||||
/// while generating LLVM code.
|
||||
class CodeGenFunction {
|
||||
public:
|
||||
CodeGenModule &CGM; // Per-module state.
|
||||
TargetInfo &Target;
|
||||
|
||||
typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy;
|
||||
llvm::LLVMFoldingBuilder 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;
|
||||
uint32_t LLVMPointerWidth;
|
||||
|
||||
private:
|
||||
/// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C
|
||||
/// decls.
|
||||
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
|
||||
|
||||
/// LabelMap - This keeps track of the LLVM basic block for each C label.
|
||||
llvm::DenseMap<const LabelStmt*, llvm::BasicBlock*> LabelMap;
|
||||
|
||||
// BreakContinueStack - This keeps track of where break and continue
|
||||
// statements should jump to.
|
||||
struct BreakContinue {
|
||||
BreakContinue(llvm::BasicBlock *bb, llvm::BasicBlock *cb)
|
||||
: BreakBlock(bb), ContinueBlock(cb) {}
|
||||
|
||||
llvm::BasicBlock *BreakBlock;
|
||||
llvm::BasicBlock *ContinueBlock;
|
||||
};
|
||||
llvm::SmallVector<BreakContinue, 8> BreakContinueStack;
|
||||
|
||||
/// SwitchInsn - This is nearest current switch instruction. It is null if
|
||||
/// if current context is not in a switch.
|
||||
llvm::SwitchInst *SwitchInsn;
|
||||
|
||||
/// CaseRangeBlock - This block holds if condition check for last case
|
||||
/// statement range in current switch instruction.
|
||||
llvm::BasicBlock *CaseRangeBlock;
|
||||
|
||||
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);
|
||||
|
||||
/// WarnUnsupported - Print out a warning that codegen doesn't support the
|
||||
/// specified stmt yet.
|
||||
void WarnUnsupported(const Stmt *S, const char *Type);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Helpers
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
|
||||
/// block.
|
||||
llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty,
|
||||
const char *Name = "tmp");
|
||||
|
||||
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
|
||||
/// expression and compare the result against zero, returning an Int1Ty value.
|
||||
llvm::Value *EvaluateExprAsBool(const Expr *E);
|
||||
|
||||
/// EmitAnyExpr - Emit code to compute the specified expression which can have
|
||||
/// any type. The result is returned as an RValue struct. If this is an
|
||||
/// aggregate expression, the aggloc/agglocvolatile arguments indicate where
|
||||
/// the result should be returned.
|
||||
RValue EmitAnyExpr(const Expr *E, llvm::Value *AggLoc = 0,
|
||||
bool isAggLocVolatile = false);
|
||||
|
||||
/// isDummyBlock - Return true if BB is an empty basic block
|
||||
/// with no predecessors.
|
||||
static bool isDummyBlock(const llvm::BasicBlock *BB);
|
||||
|
||||
/// StartBlock - Start new block named N. If insert block is a dummy block
|
||||
/// then reuse it.
|
||||
void StartBlock(const char *N);
|
||||
|
||||
/// getCGRecordLayout - Return record layout info.
|
||||
const CGRecordLayout *getCGRecordLayout(CodeGenTypes &CGT, QualType RTy);
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Declaration Emission
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
void EmitDecl(const Decl &D);
|
||||
void EmitEnumConstantDecl(const EnumConstantDecl &D);
|
||||
void EmitBlockVarDecl(const BlockVarDecl &D);
|
||||
void EmitLocalBlockVarDecl(const BlockVarDecl &D);
|
||||
void EmitStaticBlockVarDecl(const BlockVarDecl &D);
|
||||
void EmitParmDecl(const ParmVarDecl &D, llvm::Value *Arg);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Statement Emission
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
void EmitStmt(const Stmt *S);
|
||||
RValue EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false,
|
||||
llvm::Value *AggLoc = 0, bool isAggVol = false);
|
||||
void EmitLabelStmt(const LabelStmt &S);
|
||||
void EmitGotoStmt(const GotoStmt &S);
|
||||
void EmitIfStmt(const IfStmt &S);
|
||||
void EmitWhileStmt(const WhileStmt &S);
|
||||
void EmitDoStmt(const DoStmt &S);
|
||||
void EmitForStmt(const ForStmt &S);
|
||||
void EmitReturnStmt(const ReturnStmt &S);
|
||||
void EmitDeclStmt(const DeclStmt &S);
|
||||
void EmitBreakStmt();
|
||||
void EmitContinueStmt();
|
||||
void EmitSwitchStmt(const SwitchStmt &S);
|
||||
void EmitDefaultStmt(const DefaultStmt &S);
|
||||
void EmitCaseStmt(const CaseStmt &S);
|
||||
void EmitCaseStmtRange(const CaseStmt &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(LValue V, QualType LVType);
|
||||
RValue EmitLoadOfOCUElementLValue(LValue V, QualType LVType);
|
||||
|
||||
|
||||
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
|
||||
/// lvalue, where both are guaranteed to the have the same type, and that type
|
||||
/// is 'Ty'.
|
||||
void EmitStoreThroughLValue(RValue Src, LValue Dst, QualType Ty);
|
||||
void EmitStoreThroughOCUComponentLValue(RValue Src, LValue Dst, QualType Ty);
|
||||
|
||||
// Note: only availabe for agg return types
|
||||
LValue EmitCallExprLValue(const CallExpr *E);
|
||||
|
||||
LValue EmitDeclRefLValue(const DeclRefExpr *E);
|
||||
LValue EmitStringLiteralLValue(const StringLiteral *E);
|
||||
LValue EmitPreDefinedLValue(const PreDefinedExpr *E);
|
||||
LValue EmitUnaryOpLValue(const UnaryOperator *E);
|
||||
LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E);
|
||||
LValue EmitOCUVectorElementExpr(const OCUVectorElementExpr *E);
|
||||
LValue EmitMemberExpr(const MemberExpr *E);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Scalar Expression Emission
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
RValue EmitCallExpr(const CallExpr *E);
|
||||
RValue EmitCallExpr(llvm::Value *Callee, const CallExpr *E);
|
||||
RValue EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
|
||||
|
||||
llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
|
||||
llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
|
||||
|
||||
llvm::Value *EmitShuffleVector(llvm::Value* V1, llvm::Value *V2, ...);
|
||||
llvm::Value *EmitVector(llvm::Value * const *Vals, unsigned NumVals,
|
||||
bool isSplat = false);
|
||||
|
||||
llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Expression Emission
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
// Expressions are broken into three classes: scalar, complex, aggregate.
|
||||
|
||||
/// EmitScalarExpr - Emit the computation of the specified expression of
|
||||
/// LLVM scalar type, returning the result.
|
||||
llvm::Value *EmitScalarExpr(const Expr *E);
|
||||
|
||||
/// EmitScalarConversion - Emit a conversion from the specified type to the
|
||||
/// specified destination type, both of which are LLVM scalar types.
|
||||
llvm::Value *EmitScalarConversion(llvm::Value *Src, QualType SrcTy,
|
||||
QualType DstTy);
|
||||
|
||||
/// EmitComplexToScalarConversion - Emit a conversion from the specified
|
||||
/// complex type to the specified destination type, where the destination
|
||||
/// type is an LLVM scalar type.
|
||||
llvm::Value *EmitComplexToScalarConversion(ComplexPairTy Src, QualType SrcTy,
|
||||
QualType DstTy);
|
||||
|
||||
|
||||
/// EmitAggExpr - Emit the computation of the specified expression of
|
||||
/// aggregate type. The result is computed into DestPtr. Note that if
|
||||
/// DestPtr is null, the value of the aggregate expression is not needed.
|
||||
void EmitAggExpr(const Expr *E, llvm::Value *DestPtr, bool VolatileDest);
|
||||
|
||||
/// EmitComplexExpr - Emit the computation of the specified expression of
|
||||
/// complex type, returning the result.
|
||||
ComplexPairTy EmitComplexExpr(const Expr *E);
|
||||
|
||||
/// EmitComplexExprIntoAddr - Emit the computation of the specified expression
|
||||
/// of complex type, storing into the specified Value*.
|
||||
void EmitComplexExprIntoAddr(const Expr *E, llvm::Value *DestAddr,
|
||||
bool DestIsVolatile);
|
||||
/// LoadComplexFromAddr - Load a complex number from the specified address.
|
||||
ComplexPairTy LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile);
|
||||
};
|
||||
} // end namespace CodeGen
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,731 +0,0 @@
|
||||
//===--- CodeGenModule.cpp - Emit LLVM Code from ASTs for a Module --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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/Diagnostic.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
#include <algorithm>
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
|
||||
CodeGenModule::CodeGenModule(ASTContext &C, const LangOptions &LO,
|
||||
llvm::Module &M, const llvm::TargetData &TD,
|
||||
Diagnostic &diags)
|
||||
: Context(C), Features(LO), TheModule(M), TheTargetData(TD), Diags(diags),
|
||||
Types(C, M, TD), MemCpyFn(0), CFConstantStringClassRef(0) {}
|
||||
|
||||
/// WarnUnsupported - Print out a warning that codegen doesn't support the
|
||||
/// specified stmt yet.
|
||||
void CodeGenModule::WarnUnsupported(const Stmt *S, const char *Type) {
|
||||
unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Warning,
|
||||
"cannot codegen this %0 yet");
|
||||
SourceRange Range = S->getSourceRange();
|
||||
std::string Msg = Type;
|
||||
getDiags().Report(Context.getFullLoc(S->getLocStart()), DiagID,
|
||||
&Msg, 1, &Range, 1);
|
||||
}
|
||||
|
||||
/// WarnUnsupported - Print out a warning that codegen doesn't support the
|
||||
/// specified decl yet.
|
||||
void CodeGenModule::WarnUnsupported(const Decl *D, const char *Type) {
|
||||
unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Warning,
|
||||
"cannot codegen this %0 yet");
|
||||
std::string Msg = Type;
|
||||
getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID,
|
||||
&Msg, 1);
|
||||
}
|
||||
|
||||
/// ReplaceMapValuesWith - This is a really slow and bad function that
|
||||
/// searches for any entries in GlobalDeclMap that point to OldVal, changing
|
||||
/// them to point to NewVal. This is badbadbad, FIXME!
|
||||
void CodeGenModule::ReplaceMapValuesWith(llvm::Constant *OldVal,
|
||||
llvm::Constant *NewVal) {
|
||||
for (llvm::DenseMap<const Decl*, llvm::Constant*>::iterator
|
||||
I = GlobalDeclMap.begin(), E = GlobalDeclMap.end(); I != E; ++I)
|
||||
if (I->second == OldVal) I->second = NewVal;
|
||||
}
|
||||
|
||||
|
||||
llvm::Constant *CodeGenModule::GetAddrOfFunctionDecl(const FunctionDecl *D,
|
||||
bool isDefinition) {
|
||||
// See if it is already in the map. If so, just return it.
|
||||
llvm::Constant *&Entry = GlobalDeclMap[D];
|
||||
if (Entry) return Entry;
|
||||
|
||||
const llvm::Type *Ty = getTypes().ConvertType(D->getType());
|
||||
|
||||
// Check to see if the function already exists.
|
||||
llvm::Function *F = getModule().getFunction(D->getName());
|
||||
const llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
|
||||
|
||||
// If it doesn't already exist, just create and return an entry.
|
||||
if (F == 0) {
|
||||
// FIXME: param attributes for sext/zext etc.
|
||||
return Entry = new llvm::Function(FTy, llvm::Function::ExternalLinkage,
|
||||
D->getName(), &getModule());
|
||||
}
|
||||
|
||||
// If the pointer type matches, just return it.
|
||||
llvm::Type *PFTy = llvm::PointerType::getUnqual(Ty);
|
||||
if (PFTy == F->getType()) return Entry = F;
|
||||
|
||||
// If this isn't a definition, just return it casted to the right type.
|
||||
if (!isDefinition)
|
||||
return Entry = llvm::ConstantExpr::getBitCast(F, PFTy);
|
||||
|
||||
// Otherwise, we have a definition after a prototype with the wrong type.
|
||||
// F is the Function* for the one with the wrong type, we must make a new
|
||||
// Function* and update everything that used F (a declaration) with the new
|
||||
// Function* (which will be a definition).
|
||||
//
|
||||
// This happens if there is a prototype for a function (e.g. "int f()") and
|
||||
// then a definition of a different type (e.g. "int f(int x)"). Start by
|
||||
// making a new function of the correct type, RAUW, then steal the name.
|
||||
llvm::Function *NewFn = new llvm::Function(FTy,
|
||||
llvm::Function::ExternalLinkage,
|
||||
"", &getModule());
|
||||
NewFn->takeName(F);
|
||||
|
||||
// Replace uses of F with the Function we will endow with a body.
|
||||
llvm::Constant *NewPtrForOldDecl =
|
||||
llvm::ConstantExpr::getBitCast(NewFn, F->getType());
|
||||
F->replaceAllUsesWith(NewPtrForOldDecl);
|
||||
|
||||
// FIXME: Update the globaldeclmap for the previous decl of this name. We
|
||||
// really want a way to walk all of these, but we don't have it yet. This
|
||||
// is incredibly slow!
|
||||
ReplaceMapValuesWith(F, NewPtrForOldDecl);
|
||||
|
||||
// Ok, delete the old function now, which is dead.
|
||||
assert(F->isDeclaration() && "Shouldn't replace non-declaration");
|
||||
F->eraseFromParent();
|
||||
|
||||
// Return the new function which has the right type.
|
||||
return Entry = NewFn;
|
||||
}
|
||||
|
||||
llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
|
||||
bool isDefinition) {
|
||||
assert(D->hasGlobalStorage() && "Not a global variable");
|
||||
|
||||
// See if it is already in the map.
|
||||
llvm::Constant *&Entry = GlobalDeclMap[D];
|
||||
if (Entry) return Entry;
|
||||
|
||||
const llvm::Type *Ty = getTypes().ConvertTypeForMem(D->getType());
|
||||
|
||||
// Check to see if the global already exists.
|
||||
llvm::GlobalVariable *GV = getModule().getGlobalVariable(D->getName());
|
||||
|
||||
// If it doesn't already exist, just create and return an entry.
|
||||
if (GV == 0) {
|
||||
return Entry = new llvm::GlobalVariable(Ty, false,
|
||||
llvm::GlobalValue::ExternalLinkage,
|
||||
0, D->getName(), &getModule());
|
||||
}
|
||||
|
||||
// If the pointer type matches, just return it.
|
||||
llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
|
||||
if (PTy == GV->getType()) return Entry = GV;
|
||||
|
||||
// If this isn't a definition, just return it casted to the right type.
|
||||
if (!isDefinition)
|
||||
return Entry = llvm::ConstantExpr::getBitCast(GV, PTy);
|
||||
|
||||
|
||||
// Otherwise, we have a definition after a prototype with the wrong type.
|
||||
// GV is the GlobalVariable* for the one with the wrong type, we must make a
|
||||
/// new GlobalVariable* and update everything that used GV (a declaration)
|
||||
// with the new GlobalVariable* (which will be a definition).
|
||||
//
|
||||
// This happens if there is a prototype for a global (e.g. "extern int x[];")
|
||||
// and then a definition of a different type (e.g. "int x[10];"). Start by
|
||||
// making a new global of the correct type, RAUW, then steal the name.
|
||||
llvm::GlobalVariable *NewGV =
|
||||
new llvm::GlobalVariable(Ty, false, llvm::GlobalValue::ExternalLinkage,
|
||||
0, D->getName(), &getModule());
|
||||
NewGV->takeName(GV);
|
||||
|
||||
// Replace uses of GV with the globalvalue we will endow with a body.
|
||||
llvm::Constant *NewPtrForOldDecl =
|
||||
llvm::ConstantExpr::getBitCast(NewGV, GV->getType());
|
||||
GV->replaceAllUsesWith(NewPtrForOldDecl);
|
||||
|
||||
// FIXME: Update the globaldeclmap for the previous decl of this name. We
|
||||
// really want a way to walk all of these, but we don't have it yet. This
|
||||
// is incredibly slow!
|
||||
ReplaceMapValuesWith(GV, NewPtrForOldDecl);
|
||||
|
||||
// Ok, delete the old global now, which is dead.
|
||||
assert(GV->isDeclaration() && "Shouldn't replace non-declaration");
|
||||
GV->eraseFromParent();
|
||||
|
||||
// Return the new global which has the right type.
|
||||
return Entry = NewGV;
|
||||
}
|
||||
|
||||
|
||||
void CodeGenModule::EmitFunction(const FunctionDecl *FD) {
|
||||
// If this is not a prototype, emit the body.
|
||||
if (FD->getBody())
|
||||
CodeGenFunction(*this).GenerateCode(FD);
|
||||
}
|
||||
|
||||
static llvm::Constant *GenerateConstantExpr(const Expr *Expression,
|
||||
CodeGenModule &CGM);
|
||||
|
||||
/// GenerateConversionToBool - Generate comparison to zero for conversion to
|
||||
/// bool
|
||||
static llvm::Constant *GenerateConversionToBool(llvm::Constant *Expression,
|
||||
QualType Source) {
|
||||
if (Source->isRealFloatingType()) {
|
||||
// Compare against 0.0 for fp scalars.
|
||||
llvm::Constant *Zero = llvm::Constant::getNullValue(Expression->getType());
|
||||
return llvm::ConstantExpr::getFCmp(llvm::FCmpInst::FCMP_UNE, Expression,
|
||||
Zero);
|
||||
}
|
||||
|
||||
assert((Source->isIntegerType() || Source->isPointerType()) &&
|
||||
"Unknown scalar type to convert");
|
||||
|
||||
// Compare against an integer or pointer null.
|
||||
llvm::Constant *Zero = llvm::Constant::getNullValue(Expression->getType());
|
||||
return llvm::ConstantExpr::getICmp(llvm::ICmpInst::ICMP_NE, Expression, Zero);
|
||||
}
|
||||
|
||||
/// GenerateConstantCast - Generates a constant cast to convert the Expression
|
||||
/// into the Target type.
|
||||
static llvm::Constant *GenerateConstantCast(const Expr *Expression,
|
||||
QualType Target,
|
||||
CodeGenModule &CGM) {
|
||||
CodeGenTypes& Types = CGM.getTypes();
|
||||
QualType Source = Expression->getType().getCanonicalType();
|
||||
Target = Target.getCanonicalType();
|
||||
|
||||
assert (!Target->isVoidType());
|
||||
|
||||
llvm::Constant *SubExpr = GenerateConstantExpr(Expression, CGM);
|
||||
|
||||
if (Source == Target)
|
||||
return SubExpr;
|
||||
|
||||
// Handle conversions to bool first, they are special: comparisons against 0.
|
||||
if (Target->isBooleanType())
|
||||
return GenerateConversionToBool(SubExpr, Source);
|
||||
|
||||
const llvm::Type *SourceType = Types.ConvertType(Source);
|
||||
const llvm::Type *TargetType = Types.ConvertType(Target);
|
||||
|
||||
// Ignore conversions like int -> uint.
|
||||
if (SubExpr->getType() == TargetType)
|
||||
return SubExpr;
|
||||
|
||||
// Handle pointer conversions next: pointers can only be converted to/from
|
||||
// other pointers and integers.
|
||||
if (isa<llvm::PointerType>(TargetType)) {
|
||||
// The source value may be an integer, or a pointer.
|
||||
if (isa<llvm::PointerType>(SubExpr->getType()))
|
||||
return llvm::ConstantExpr::getBitCast(SubExpr, TargetType);
|
||||
assert(Source->isIntegerType() && "Not ptr->ptr or int->ptr conversion?");
|
||||
return llvm::ConstantExpr::getIntToPtr(SubExpr, TargetType);
|
||||
}
|
||||
|
||||
if (isa<llvm::PointerType>(SourceType)) {
|
||||
// Must be an ptr to int cast.
|
||||
assert(isa<llvm::IntegerType>(TargetType) && "not ptr->int?");
|
||||
return llvm::ConstantExpr::getPtrToInt(SubExpr, TargetType);
|
||||
}
|
||||
|
||||
if (Source->isRealFloatingType() && Target->isRealFloatingType()) {
|
||||
return llvm::ConstantExpr::getFPCast(SubExpr, TargetType);
|
||||
}
|
||||
|
||||
// Finally, we have the arithmetic types: real int/float.
|
||||
if (isa<llvm::IntegerType>(SourceType)) {
|
||||
bool InputSigned = Source->isSignedIntegerType();
|
||||
if (isa<llvm::IntegerType>(TargetType))
|
||||
return llvm::ConstantExpr::getIntegerCast(SubExpr, TargetType,
|
||||
InputSigned);
|
||||
else if (InputSigned)
|
||||
return llvm::ConstantExpr::getSIToFP(SubExpr, TargetType);
|
||||
else
|
||||
return llvm::ConstantExpr::getUIToFP(SubExpr, TargetType);
|
||||
}
|
||||
|
||||
assert(SubExpr->getType()->isFloatingPoint() && "Unknown real conversion");
|
||||
if (isa<llvm::IntegerType>(TargetType)) {
|
||||
if (Target->isSignedIntegerType())
|
||||
return llvm::ConstantExpr::getFPToSI(SubExpr, TargetType);
|
||||
else
|
||||
return llvm::ConstantExpr::getFPToUI(SubExpr, TargetType);
|
||||
}
|
||||
|
||||
assert(TargetType->isFloatingPoint() && "Unknown real conversion");
|
||||
if (TargetType->getTypeID() < SubExpr->getType()->getTypeID())
|
||||
return llvm::ConstantExpr::getFPTrunc(SubExpr, TargetType);
|
||||
else
|
||||
return llvm::ConstantExpr::getFPExtend(SubExpr, TargetType);
|
||||
|
||||
assert (!"Unsupported cast type in global intialiser.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// GenerateAggregateInit - Generate a Constant initaliser for global array or
|
||||
/// struct typed variables.
|
||||
static llvm::Constant *GenerateAggregateInit(const InitListExpr *ILE,
|
||||
CodeGenModule &CGM) {
|
||||
if (ILE->getType()->isVoidType()) {
|
||||
// FIXME: Remove this when sema of initializers is finished (and the code
|
||||
// below).
|
||||
CGM.WarnUnsupported(ILE, "initializer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert((ILE->getType()->isArrayType() || ILE->getType()->isStructureType()) &&
|
||||
"Bad type for init list!");
|
||||
CodeGenTypes& Types = CGM.getTypes();
|
||||
|
||||
unsigned NumInitElements = ILE->getNumInits();
|
||||
unsigned NumInitableElts = NumInitElements;
|
||||
|
||||
const llvm::CompositeType *CType =
|
||||
cast<llvm::CompositeType>(Types.ConvertType(ILE->getType()));
|
||||
assert(CType);
|
||||
std::vector<llvm::Constant*> Elts;
|
||||
|
||||
// Initialising an array requires us to automatically initialise any
|
||||
// elements that have not been initialised explicitly
|
||||
const llvm::ArrayType *AType = 0;
|
||||
const llvm::Type *AElemTy = 0;
|
||||
unsigned NumArrayElements = 0;
|
||||
|
||||
// If this is an array, we may have to truncate the initializer
|
||||
if ((AType = dyn_cast<llvm::ArrayType>(CType))) {
|
||||
NumArrayElements = AType->getNumElements();
|
||||
AElemTy = AType->getElementType();
|
||||
NumInitableElts = std::min(NumInitableElts, NumArrayElements);
|
||||
}
|
||||
|
||||
// Copy initializer elements.
|
||||
unsigned i = 0;
|
||||
for (i = 0; i < NumInitableElts; ++i) {
|
||||
llvm::Constant *C = GenerateConstantExpr(ILE->getInit(i), CGM);
|
||||
// FIXME: Remove this when sema of initializers is finished (and the code
|
||||
// above).
|
||||
if (C == 0 && ILE->getInit(i)->getType()->isVoidType()) {
|
||||
if (ILE->getType()->isVoidType()) return 0;
|
||||
return llvm::UndefValue::get(CType);
|
||||
}
|
||||
assert (C && "Failed to create initialiser expression");
|
||||
Elts.push_back(C);
|
||||
}
|
||||
|
||||
if (ILE->getType()->isStructureType())
|
||||
return llvm::ConstantStruct::get(cast<llvm::StructType>(CType), Elts);
|
||||
|
||||
// Make sure we have an array at this point
|
||||
assert(AType);
|
||||
|
||||
// Initialize remaining array elements.
|
||||
for (; i < NumArrayElements; ++i)
|
||||
Elts.push_back(llvm::Constant::getNullValue(AElemTy));
|
||||
|
||||
return llvm::ConstantArray::get(AType, Elts);
|
||||
}
|
||||
|
||||
/// GenerateConstantExpr - Recursively builds a constant initialiser for the
|
||||
/// given expression.
|
||||
static llvm::Constant *GenerateConstantExpr(const Expr *Expression,
|
||||
CodeGenModule &CGM) {
|
||||
CodeGenTypes& Types = CGM.getTypes();
|
||||
ASTContext& Context = CGM.getContext();
|
||||
assert ((Expression->isConstantExpr(Context, 0) ||
|
||||
Expression->getStmtClass() == Stmt::InitListExprClass) &&
|
||||
"Only constant global initialisers are supported.");
|
||||
|
||||
QualType type = Expression->getType().getCanonicalType();
|
||||
|
||||
if (type->isIntegerType()) {
|
||||
llvm::APSInt
|
||||
Value(static_cast<uint32_t>(Context.getTypeSize(type, SourceLocation())));
|
||||
if (Expression->isIntegerConstantExpr(Value, Context)) {
|
||||
return llvm::ConstantInt::get(Value);
|
||||
}
|
||||
}
|
||||
|
||||
switch (Expression->getStmtClass()) {
|
||||
default: break; // default emits a warning and returns bogus value.
|
||||
case Stmt::DeclRefExprClass: {
|
||||
const ValueDecl *Decl = cast<DeclRefExpr>(Expression)->getDecl();
|
||||
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl))
|
||||
return CGM.GetAddrOfFunctionDecl(FD, false);
|
||||
break;
|
||||
}
|
||||
|
||||
// Generate constant for floating point literal values.
|
||||
case Stmt::FloatingLiteralClass: {
|
||||
const FloatingLiteral *FLiteral = cast<FloatingLiteral>(Expression);
|
||||
return llvm::ConstantFP::get(Types.ConvertType(type), FLiteral->getValue());
|
||||
}
|
||||
|
||||
// Generate constant for string literal values.
|
||||
case Stmt::StringLiteralClass: {
|
||||
const StringLiteral *String = cast<StringLiteral>(Expression);
|
||||
const char *StrData = String->getStrData();
|
||||
unsigned Len = String->getByteLength();
|
||||
|
||||
// If the string has a pointer type, emit it as a global and use the pointer
|
||||
// to the global as its value.
|
||||
if (String->getType()->isPointerType())
|
||||
return CGM.GetAddrOfConstantString(std::string(StrData, StrData + Len));
|
||||
|
||||
// Otherwise this must be a string initializing an array in a static
|
||||
// initializer. Don't emit it as the address of the string, emit the string
|
||||
// data itself as an inline array.
|
||||
const ConstantArrayType *CAT = String->getType()->getAsConstantArrayType();
|
||||
assert(CAT && "String isn't pointer or array!");
|
||||
|
||||
std::string Str(StrData, StrData + Len);
|
||||
// Null terminate the string before potentially truncating it.
|
||||
// FIXME: What about wchar_t strings?
|
||||
Str.push_back(0);
|
||||
|
||||
uint64_t RealLen = CAT->getSize().getZExtValue();
|
||||
// String or grow the initializer to the required size.
|
||||
if (RealLen != Str.size())
|
||||
Str.resize(RealLen);
|
||||
|
||||
return llvm::ConstantArray::get(Str, false);
|
||||
}
|
||||
|
||||
// Elide parenthesis.
|
||||
case Stmt::ParenExprClass:
|
||||
return GenerateConstantExpr(cast<ParenExpr>(Expression)->getSubExpr(), CGM);
|
||||
|
||||
// Generate constant for sizeof operator.
|
||||
// FIXME: Need to support AlignOf
|
||||
case Stmt::SizeOfAlignOfTypeExprClass: {
|
||||
const SizeOfAlignOfTypeExpr *SOExpr =
|
||||
cast<SizeOfAlignOfTypeExpr>(Expression);
|
||||
assert (SOExpr->isSizeOf());
|
||||
return llvm::ConstantExpr::getSizeOf(Types.ConvertType(type));
|
||||
}
|
||||
|
||||
// Generate constant cast expressions.
|
||||
case Stmt::CastExprClass:
|
||||
return GenerateConstantCast(cast<CastExpr>(Expression)->getSubExpr(), type,
|
||||
CGM);
|
||||
case Stmt::UnaryOperatorClass: {
|
||||
const UnaryOperator *Op = cast<UnaryOperator>(Expression);
|
||||
llvm::Constant *SubExpr = GenerateConstantExpr(Op->getSubExpr(), CGM);
|
||||
// FIXME: These aren't right for complex.
|
||||
switch (Op->getOpcode()) {
|
||||
default: break;
|
||||
case UnaryOperator::Plus:
|
||||
case UnaryOperator::Extension:
|
||||
return SubExpr;
|
||||
case UnaryOperator::Minus:
|
||||
return llvm::ConstantExpr::getNeg(SubExpr);
|
||||
case UnaryOperator::Not:
|
||||
return llvm::ConstantExpr::getNot(SubExpr);
|
||||
case UnaryOperator::LNot:
|
||||
if (Op->getSubExpr()->getType()->isRealFloatingType()) {
|
||||
// Compare against 0.0 for fp scalars.
|
||||
llvm::Constant *Zero = llvm::Constant::getNullValue(SubExpr->getType());
|
||||
SubExpr = llvm::ConstantExpr::getFCmp(llvm::FCmpInst::FCMP_UNE, SubExpr,
|
||||
Zero);
|
||||
} else {
|
||||
assert((Op->getSubExpr()->getType()->isIntegerType() ||
|
||||
Op->getSubExpr()->getType()->isPointerType()) &&
|
||||
"Unknown scalar type to convert");
|
||||
// Compare against an integer or pointer null.
|
||||
llvm::Constant *Zero = llvm::Constant::getNullValue(SubExpr->getType());
|
||||
SubExpr = llvm::ConstantExpr::getICmp(llvm::ICmpInst::ICMP_NE, SubExpr,
|
||||
Zero);
|
||||
}
|
||||
|
||||
return llvm::ConstantExpr::getZExt(SubExpr, Types.ConvertType(type));
|
||||
//SizeOf, AlignOf, // [C99 6.5.3.4] Sizeof (expr, not type) operator.
|
||||
//Real, Imag, // "__real expr"/"__imag expr" Extension.
|
||||
//OffsetOf // __builtin_offsetof
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Stmt::ImplicitCastExprClass: {
|
||||
const ImplicitCastExpr *ICExpr = cast<ImplicitCastExpr>(Expression);
|
||||
|
||||
// If this is due to array->pointer conversion, emit the array expression as
|
||||
// an l-value.
|
||||
if (ICExpr->getSubExpr()->getType()->isArrayType()) {
|
||||
// Note that VLAs can't exist for global variables.
|
||||
// The only thing that can have array type like this is a
|
||||
// DeclRefExpr(FileVarDecl)?
|
||||
const DeclRefExpr *DRE = cast<DeclRefExpr>(ICExpr->getSubExpr());
|
||||
const VarDecl *VD = cast<VarDecl>(DRE->getDecl());
|
||||
llvm::Constant *C = CGM.GetAddrOfGlobalVar(VD, false);
|
||||
assert(isa<llvm::PointerType>(C->getType()) &&
|
||||
isa<llvm::ArrayType>(cast<llvm::PointerType>(C->getType())
|
||||
->getElementType()));
|
||||
llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
|
||||
|
||||
llvm::Constant *Ops[] = {Idx0, Idx0};
|
||||
C = llvm::ConstantExpr::getGetElementPtr(C, Ops, 2);
|
||||
|
||||
// The resultant pointer type can be implicitly casted to other pointer
|
||||
// types as well, for example void*.
|
||||
const llvm::Type *DestPTy = Types.ConvertType(type);
|
||||
assert(isa<llvm::PointerType>(DestPTy) &&
|
||||
"Only expect implicit cast to pointer");
|
||||
return llvm::ConstantExpr::getBitCast(C, DestPTy);
|
||||
}
|
||||
|
||||
return GenerateConstantCast(ICExpr->getSubExpr(), type, CGM);
|
||||
}
|
||||
|
||||
// Generate a constant array access expression
|
||||
// FIXME: Clang's semantic analysis incorrectly prevents array access in
|
||||
// global initialisers, preventing us from testing this.
|
||||
case Stmt::ArraySubscriptExprClass: {
|
||||
const ArraySubscriptExpr* ASExpr = cast<ArraySubscriptExpr>(Expression);
|
||||
llvm::Constant *Base = GenerateConstantExpr(ASExpr->getBase(), CGM);
|
||||
llvm::Constant *Index = GenerateConstantExpr(ASExpr->getIdx(), CGM);
|
||||
return llvm::ConstantExpr::getExtractElement(Base, Index);
|
||||
}
|
||||
|
||||
// Generate a constant expression to initialise an aggregate type, such as
|
||||
// an array or struct.
|
||||
case Stmt::InitListExprClass:
|
||||
return GenerateAggregateInit(cast<InitListExpr>(Expression), CGM);
|
||||
}
|
||||
|
||||
CGM.WarnUnsupported(Expression, "initializer");
|
||||
return llvm::UndefValue::get(Types.ConvertType(type));
|
||||
}
|
||||
|
||||
llvm::Constant *CodeGenModule::EmitGlobalInit(const Expr *Expression) {
|
||||
return GenerateConstantExpr(Expression, *this);
|
||||
}
|
||||
|
||||
void CodeGenModule::EmitGlobalVar(const FileVarDecl *D) {
|
||||
// If this is just a forward declaration of the variable, don't emit it now,
|
||||
// allow it to be emitted lazily on its first use.
|
||||
if (D->getStorageClass() == VarDecl::Extern && D->getInit() == 0)
|
||||
return;
|
||||
|
||||
// Get the global, forcing it to be a direct reference.
|
||||
llvm::GlobalVariable *GV =
|
||||
cast<llvm::GlobalVariable>(GetAddrOfGlobalVar(D, true));
|
||||
|
||||
// Convert the initializer, or use zero if appropriate.
|
||||
llvm::Constant *Init = 0;
|
||||
if (D->getInit() == 0) {
|
||||
Init = llvm::Constant::getNullValue(GV->getType()->getElementType());
|
||||
} else if (D->getType()->isIntegerType()) {
|
||||
llvm::APSInt Value(static_cast<uint32_t>(
|
||||
getContext().getTypeSize(D->getInit()->getType(), SourceLocation())));
|
||||
if (D->getInit()->isIntegerConstantExpr(Value, Context))
|
||||
Init = llvm::ConstantInt::get(Value);
|
||||
}
|
||||
|
||||
if (!Init)
|
||||
Init = EmitGlobalInit(D->getInit());
|
||||
|
||||
assert(GV->getType()->getElementType() == Init->getType() &&
|
||||
"Initializer codegen type mismatch!");
|
||||
GV->setInitializer(Init);
|
||||
|
||||
// Set the llvm linkage type as appropriate.
|
||||
// FIXME: This isn't right. This should handle common linkage and other
|
||||
// stuff.
|
||||
switch (D->getStorageClass()) {
|
||||
case VarDecl::Auto:
|
||||
case VarDecl::Register:
|
||||
assert(0 && "Can't have auto or register globals");
|
||||
case VarDecl::None:
|
||||
case VarDecl::Extern:
|
||||
// todo: common
|
||||
break;
|
||||
case VarDecl::Static:
|
||||
GV->setLinkage(llvm::GlobalVariable::InternalLinkage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// EmitGlobalVarDeclarator - Emit all the global vars attached to the specified
|
||||
/// declarator chain.
|
||||
void CodeGenModule::EmitGlobalVarDeclarator(const FileVarDecl *D) {
|
||||
for (; D; D = cast_or_null<FileVarDecl>(D->getNextDeclarator()))
|
||||
EmitGlobalVar(D);
|
||||
}
|
||||
|
||||
/// getBuiltinLibFunction
|
||||
llvm::Function *CodeGenModule::getBuiltinLibFunction(unsigned BuiltinID) {
|
||||
if (BuiltinID > BuiltinFunctions.size())
|
||||
BuiltinFunctions.resize(BuiltinID);
|
||||
|
||||
// Cache looked up functions. Since builtin id #0 is invalid we don't reserve
|
||||
// a slot for it.
|
||||
assert(BuiltinID && "Invalid Builtin ID");
|
||||
llvm::Function *&FunctionSlot = BuiltinFunctions[BuiltinID-1];
|
||||
if (FunctionSlot)
|
||||
return FunctionSlot;
|
||||
|
||||
assert(Context.BuiltinInfo.isLibFunction(BuiltinID) && "isn't a lib fn");
|
||||
|
||||
// Get the name, skip over the __builtin_ prefix.
|
||||
const char *Name = Context.BuiltinInfo.GetName(BuiltinID)+10;
|
||||
|
||||
// Get the type for the builtin.
|
||||
QualType Type = Context.BuiltinInfo.GetBuiltinType(BuiltinID, Context);
|
||||
const llvm::FunctionType *Ty =
|
||||
cast<llvm::FunctionType>(getTypes().ConvertType(Type));
|
||||
|
||||
// FIXME: This has a serious problem with code like this:
|
||||
// void abs() {}
|
||||
// ... __builtin_abs(x);
|
||||
// The two versions of abs will collide. The fix is for the builtin to win,
|
||||
// and for the existing one to be turned into a constantexpr cast of the
|
||||
// builtin. In the case where the existing one is a static function, it
|
||||
// should just be renamed.
|
||||
if (llvm::Function *Existing = getModule().getFunction(Name)) {
|
||||
if (Existing->getFunctionType() == Ty && Existing->hasExternalLinkage())
|
||||
return FunctionSlot = Existing;
|
||||
assert(Existing == 0 && "FIXME: Name collision");
|
||||
}
|
||||
|
||||
// FIXME: param attributes for sext/zext etc.
|
||||
return FunctionSlot = new llvm::Function(Ty, llvm::Function::ExternalLinkage,
|
||||
Name, &getModule());
|
||||
}
|
||||
|
||||
llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,const llvm::Type **Tys,
|
||||
unsigned NumTys) {
|
||||
return llvm::Intrinsic::getDeclaration(&getModule(),
|
||||
(llvm::Intrinsic::ID)IID, Tys, NumTys);
|
||||
}
|
||||
|
||||
llvm::Function *CodeGenModule::getMemCpyFn() {
|
||||
if (MemCpyFn) return MemCpyFn;
|
||||
llvm::Intrinsic::ID IID;
|
||||
uint64_t Size; unsigned Align;
|
||||
Context.Target.getPointerInfo(Size, Align, FullSourceLoc());
|
||||
switch (Size) {
|
||||
default: assert(0 && "Unknown ptr width");
|
||||
case 32: IID = llvm::Intrinsic::memcpy_i32; break;
|
||||
case 64: IID = llvm::Intrinsic::memcpy_i64; break;
|
||||
}
|
||||
return MemCpyFn = getIntrinsic(IID);
|
||||
}
|
||||
|
||||
|
||||
llvm::Constant *CodeGenModule::
|
||||
GetAddrOfConstantCFString(const std::string &str) {
|
||||
llvm::StringMapEntry<llvm::Constant *> &Entry =
|
||||
CFConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]);
|
||||
|
||||
if (Entry.getValue())
|
||||
return Entry.getValue();
|
||||
|
||||
std::vector<llvm::Constant*> Fields;
|
||||
|
||||
if (!CFConstantStringClassRef) {
|
||||
const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
|
||||
Ty = llvm::ArrayType::get(Ty, 0);
|
||||
|
||||
CFConstantStringClassRef =
|
||||
new llvm::GlobalVariable(Ty, false,
|
||||
llvm::GlobalVariable::ExternalLinkage, 0,
|
||||
"__CFConstantStringClassReference",
|
||||
&getModule());
|
||||
}
|
||||
|
||||
// Class pointer.
|
||||
llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
|
||||
llvm::Constant *Zeros[] = { Zero, Zero };
|
||||
llvm::Constant *C =
|
||||
llvm::ConstantExpr::getGetElementPtr(CFConstantStringClassRef, Zeros, 2);
|
||||
Fields.push_back(C);
|
||||
|
||||
// Flags.
|
||||
const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
|
||||
Fields.push_back(llvm::ConstantInt::get(Ty, 1992));
|
||||
|
||||
// String pointer.
|
||||
C = llvm::ConstantArray::get(str);
|
||||
C = new llvm::GlobalVariable(C->getType(), true,
|
||||
llvm::GlobalValue::InternalLinkage,
|
||||
C, ".str", &getModule());
|
||||
|
||||
C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2);
|
||||
Fields.push_back(C);
|
||||
|
||||
// String length.
|
||||
Ty = getTypes().ConvertType(getContext().LongTy);
|
||||
Fields.push_back(llvm::ConstantInt::get(Ty, str.length()));
|
||||
|
||||
// The struct.
|
||||
Ty = getTypes().ConvertType(getContext().getCFConstantStringType());
|
||||
C = llvm::ConstantStruct::get(cast<llvm::StructType>(Ty), Fields);
|
||||
llvm::GlobalVariable *GV =
|
||||
new llvm::GlobalVariable(C->getType(), true,
|
||||
llvm::GlobalVariable::InternalLinkage,
|
||||
C, "", &getModule());
|
||||
GV->setSection("__DATA,__cfstring");
|
||||
Entry.setValue(GV);
|
||||
return GV;
|
||||
}
|
||||
|
||||
/// GenerateWritableString -- Creates storage for a string literal
|
||||
static llvm::Constant *GenerateStringLiteral(const std::string &str,
|
||||
bool constant,
|
||||
CodeGenModule &CGM) {
|
||||
// Create Constant for this string literal
|
||||
llvm::Constant *C=llvm::ConstantArray::get(str);
|
||||
|
||||
// Create a global variable for this string
|
||||
C = new llvm::GlobalVariable(C->getType(), constant,
|
||||
llvm::GlobalValue::InternalLinkage,
|
||||
C, ".str", &CGM.getModule());
|
||||
llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
|
||||
llvm::Constant *Zeros[] = { Zero, Zero };
|
||||
C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2);
|
||||
return C;
|
||||
}
|
||||
|
||||
/// CodeGenModule::GetAddrOfConstantString -- returns a pointer to the first
|
||||
/// element of a character array containing the literal.
|
||||
llvm::Constant *CodeGenModule::GetAddrOfConstantString(const std::string &str) {
|
||||
// Don't share any string literals if writable-strings is turned on.
|
||||
if (Features.WritableStrings)
|
||||
return GenerateStringLiteral(str, false, *this);
|
||||
|
||||
llvm::StringMapEntry<llvm::Constant *> &Entry =
|
||||
ConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]);
|
||||
|
||||
if (Entry.getValue())
|
||||
return Entry.getValue();
|
||||
|
||||
// Create a global variable for this.
|
||||
llvm::Constant *C = GenerateStringLiteral(str, true, *this);
|
||||
Entry.setValue(C);
|
||||
return C;
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
//===--- CodeGenModule.h - Per-Module state for LLVM CodeGen --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the internal per-translation-unit state used for llvm translation.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CODEGEN_CODEGENMODULE_H
|
||||
#define CODEGEN_CODEGENMODULE_H
|
||||
|
||||
#include "CodeGenTypes.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
class Constant;
|
||||
class Function;
|
||||
class GlobalVariable;
|
||||
class TargetData;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class FunctionDecl;
|
||||
class Decl;
|
||||
class Expr;
|
||||
class Stmt;
|
||||
class ValueDecl;
|
||||
class VarDecl;
|
||||
class FileVarDecl;
|
||||
struct LangOptions;
|
||||
class Diagnostic;
|
||||
|
||||
namespace CodeGen {
|
||||
|
||||
/// CodeGenModule - This class organizes the cross-module state that is used
|
||||
/// while generating LLVM code.
|
||||
class CodeGenModule {
|
||||
ASTContext &Context;
|
||||
const LangOptions &Features;
|
||||
llvm::Module &TheModule;
|
||||
const llvm::TargetData &TheTargetData;
|
||||
Diagnostic &Diags;
|
||||
CodeGenTypes Types;
|
||||
|
||||
llvm::Function *MemCpyFn;
|
||||
llvm::DenseMap<const Decl*, llvm::Constant*> GlobalDeclMap;
|
||||
|
||||
llvm::StringMap<llvm::Constant*> CFConstantStringMap;
|
||||
llvm::StringMap<llvm::Constant*> ConstantStringMap;
|
||||
llvm::Constant *CFConstantStringClassRef;
|
||||
|
||||
std::vector<llvm::Function *> BuiltinFunctions;
|
||||
public:
|
||||
CodeGenModule(ASTContext &C, const LangOptions &Features, llvm::Module &M,
|
||||
const llvm::TargetData &TD, Diagnostic &Diags);
|
||||
|
||||
ASTContext &getContext() const { return Context; }
|
||||
const LangOptions &getLangOptions() const { return Features; }
|
||||
llvm::Module &getModule() const { return TheModule; }
|
||||
CodeGenTypes &getTypes() { return Types; }
|
||||
Diagnostic &getDiags() const { return Diags; }
|
||||
const llvm::TargetData &getTargetData() const { return TheTargetData; }
|
||||
|
||||
llvm::Constant *GetAddrOfFunctionDecl(const FunctionDecl *D,
|
||||
bool isDefinition);
|
||||
llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D, bool isDefinition);
|
||||
|
||||
|
||||
/// getBuiltinLibFunction - Given a builtin id for a function like
|
||||
/// "__builtin_fabsf", return a Function* for "fabsf".
|
||||
///
|
||||
llvm::Function *getBuiltinLibFunction(unsigned BuiltinID);
|
||||
llvm::Constant *GetAddrOfConstantCFString(const std::string& str);
|
||||
llvm::Constant *GetAddrOfConstantString(const std::string& str);
|
||||
llvm::Function *getMemCpyFn();
|
||||
llvm::Function *getIntrinsic(unsigned IID, const llvm::Type **Tys = 0,
|
||||
unsigned NumTys = 0);
|
||||
|
||||
void EmitFunction(const FunctionDecl *FD);
|
||||
void EmitGlobalVar(const FileVarDecl *D);
|
||||
void EmitGlobalVarDeclarator(const FileVarDecl *D);
|
||||
llvm::Constant *EmitGlobalInit(const Expr *Expression);
|
||||
|
||||
void PrintStats() {}
|
||||
|
||||
/// WarnUnsupported - Print out a warning that codegen doesn't support the
|
||||
/// specified stmt yet.
|
||||
void WarnUnsupported(const Stmt *S, const char *Type);
|
||||
|
||||
/// WarnUnsupported - Print out a warning that codegen doesn't support the
|
||||
/// specified decl yet.
|
||||
void WarnUnsupported(const Decl *D, const char *Type);
|
||||
|
||||
private:
|
||||
/// ReplaceMapValuesWith - This is a really slow and bad function that
|
||||
/// searches for any entries in GlobalDeclMap that point to OldVal, changing
|
||||
/// them to point to NewVal. This is badbadbad, FIXME!
|
||||
void ReplaceMapValuesWith(llvm::Constant *OldVal, llvm::Constant *NewVal);
|
||||
|
||||
};
|
||||
} // end namespace CodeGen
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,680 +0,0 @@
|
||||
//===--- CodeGenTypes.cpp - Type translation for LLVM CodeGen -------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the code that handles AST -> LLVM type lowering.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CodeGenTypes.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
namespace {
|
||||
/// RecordOrganizer - This helper class, used by CGRecordLayout, layouts
|
||||
/// structs and unions. It manages transient information used during layout.
|
||||
/// FIXME : At the moment assume
|
||||
/// - one to one mapping between AST FieldDecls and
|
||||
/// llvm::StructType elements.
|
||||
/// - Ignore bit fields
|
||||
/// - Ignore field aligments
|
||||
/// - Ignore packed structs
|
||||
class RecordOrganizer {
|
||||
public:
|
||||
explicit RecordOrganizer(CodeGenTypes &Types) :
|
||||
CGT(Types), STy(NULL), FieldNo(0), Cursor(0), ExtraBits(0),
|
||||
CurrentFieldStart(0), llvmSize(0) {}
|
||||
|
||||
/// addField - Add new field.
|
||||
void addField(const FieldDecl *FD);
|
||||
|
||||
/// addLLVMField - Add llvm struct field that corresponds to llvm type Ty.
|
||||
/// Update cursor and increment field count.
|
||||
void addLLVMField(const llvm::Type *Ty, uint64_t Size,
|
||||
const FieldDecl *FD = NULL, unsigned Begin = 0,
|
||||
unsigned End = 0);
|
||||
|
||||
/// addPaddingFields - Current cursor is not suitable place to add next
|
||||
/// field. Add required padding fields.
|
||||
void addPaddingFields(unsigned WaterMark);
|
||||
|
||||
/// layoutStructFields - Do the actual work and lay out all fields. Create
|
||||
/// corresponding llvm struct type. This should be invoked only after
|
||||
/// all fields are added.
|
||||
void layoutStructFields(const ASTRecordLayout &RL);
|
||||
|
||||
/// layoutUnionFields - Do the actual work and lay out all fields. Create
|
||||
/// corresponding llvm struct type. This should be invoked only after
|
||||
/// all fields are added.
|
||||
void layoutUnionFields();
|
||||
|
||||
/// getLLVMType - Return associated llvm struct type. This may be NULL
|
||||
/// if fields are not laid out.
|
||||
llvm::Type *getLLVMType() const {
|
||||
return STy;
|
||||
}
|
||||
|
||||
/// fixCursorPosition - When bit-field is followed by a normal field
|
||||
/// cursor position may require some adjustments.
|
||||
///
|
||||
/// For example, struct { char a; short b:2; char c; };
|
||||
///
|
||||
/// At the beginning of field 'c' layout, cursor position is 10.
|
||||
/// However, only llvm struct field allocated so far is of type i8.
|
||||
/// This happens because 'b' shares llvm field with 'a'. Add padding
|
||||
/// field of i8 type and reposition cursor to point at 16. This
|
||||
/// should be done only if next field (i.e. 'c' here) is not a bit-field
|
||||
/// or last record field is a bit-field.
|
||||
void fixCursorPosition(const ASTRecordLayout &RL);
|
||||
|
||||
/// placeBitField - Find a place for FD, which is a bit-field.
|
||||
void placeBitField(const FieldDecl *FD);
|
||||
|
||||
private:
|
||||
CodeGenTypes &CGT;
|
||||
llvm::Type *STy;
|
||||
unsigned FieldNo;
|
||||
uint64_t Cursor;
|
||||
/* If last field is a bitfield then it may not have occupied all allocated
|
||||
bits. Use remaining bits for next field if it also a bitfield. */
|
||||
uint64_t ExtraBits;
|
||||
/* CurrentFieldStart - Indicates starting offset for current llvm field.
|
||||
When current llvm field is shared by multiple bitfields, this is
|
||||
used find starting bit offset for the bitfield from the beginning of
|
||||
llvm field. */
|
||||
uint64_t CurrentFieldStart;
|
||||
uint64_t llvmSize;
|
||||
llvm::SmallVector<const FieldDecl *, 8> FieldDecls;
|
||||
std::vector<const llvm::Type*> LLVMFields;
|
||||
llvm::SmallVector<uint64_t, 8> Offsets;
|
||||
};
|
||||
}
|
||||
|
||||
CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M,
|
||||
const llvm::TargetData &TD)
|
||||
: Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD) {
|
||||
}
|
||||
|
||||
CodeGenTypes::~CodeGenTypes() {
|
||||
for(llvm::DenseMap<const llvm::Type *, CGRecordLayout *>::iterator
|
||||
I = CGRecordLayouts.begin(), E = CGRecordLayouts.end();
|
||||
I != E; ++I)
|
||||
delete I->second;
|
||||
CGRecordLayouts.clear();
|
||||
}
|
||||
|
||||
/// isOpaqueTypeDefinition - Return true if LT is a llvm::OpaqueType
|
||||
/// and T is tag definition. This helper routine does not check
|
||||
/// relationship between T and LT.
|
||||
static bool isOpaqueTypeDefinition(QualType T, llvm::Type *LT) {
|
||||
|
||||
if (!isa<llvm::OpaqueType>(LT))
|
||||
return false;
|
||||
|
||||
const clang::Type &Ty = *T.getCanonicalType();
|
||||
if (Ty.getTypeClass() == Type::Tagged) {
|
||||
const TagType &TT = cast<TagType>(Ty);
|
||||
const TagDecl *TD = TT.getDecl();
|
||||
if (TD->isDefinition())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// ConvertType - Convert the specified type to its LLVM form.
|
||||
const llvm::Type *CodeGenTypes::ConvertType(QualType T) {
|
||||
// See if type is already cached.
|
||||
llvm::DenseMap<Type *, llvm::PATypeHolder>::iterator
|
||||
I = TypeHolderMap.find(T.getTypePtr());
|
||||
// If type is found in map and this is not a definition for a opaque
|
||||
// place holder type then use it. Otherwise convert type T.
|
||||
if (I != TypeHolderMap.end() && !isOpaqueTypeDefinition(T, I->second.get()))
|
||||
return I->second.get();
|
||||
|
||||
const llvm::Type *ResultType = ConvertNewType(T);
|
||||
TypeHolderMap.insert(std::make_pair(T.getTypePtr(),
|
||||
llvm::PATypeHolder(ResultType)));
|
||||
return ResultType;
|
||||
}
|
||||
|
||||
/// ConvertTypeForMem - Convert type T into a llvm::Type. Maintain and use
|
||||
/// type cache through TypeHolderMap. This differs from ConvertType in that
|
||||
/// it is used to convert to the memory representation for a type. For
|
||||
/// example, the scalar representation for _Bool is i1, but the memory
|
||||
/// representation is usually i8 or i32, depending on the target.
|
||||
const llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) {
|
||||
const llvm::Type *R = ConvertType(T);
|
||||
|
||||
// If this is a non-bool type, don't map it.
|
||||
if (R != llvm::Type::Int1Ty)
|
||||
return R;
|
||||
|
||||
// Otherwise, return an integer of the target-specified size.
|
||||
unsigned BoolWidth = (unsigned)Context.getTypeSize(T, SourceLocation());
|
||||
return llvm::IntegerType::get(BoolWidth);
|
||||
|
||||
}
|
||||
|
||||
|
||||
const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
|
||||
const clang::Type &Ty = *T.getCanonicalType();
|
||||
|
||||
switch (Ty.getTypeClass()) {
|
||||
case Type::TypeName: // typedef isn't canonical.
|
||||
case Type::TypeOfExp: // typeof isn't canonical.
|
||||
case Type::TypeOfTyp: // typeof isn't canonical.
|
||||
assert(0 && "Non-canonical type, shouldn't happen");
|
||||
case Type::Builtin: {
|
||||
switch (cast<BuiltinType>(Ty).getKind()) {
|
||||
case BuiltinType::Void:
|
||||
// LLVM void type can only be used as the result of a function call. Just
|
||||
// map to the same as char.
|
||||
return llvm::IntegerType::get(8);
|
||||
|
||||
case BuiltinType::Bool:
|
||||
// Note that we always return bool as i1 for use as a scalar type.
|
||||
return llvm::Type::Int1Ty;
|
||||
|
||||
case BuiltinType::Char_S:
|
||||
case BuiltinType::Char_U:
|
||||
case BuiltinType::SChar:
|
||||
case BuiltinType::UChar:
|
||||
case BuiltinType::Short:
|
||||
case BuiltinType::UShort:
|
||||
case BuiltinType::Int:
|
||||
case BuiltinType::UInt:
|
||||
case BuiltinType::Long:
|
||||
case BuiltinType::ULong:
|
||||
case BuiltinType::LongLong:
|
||||
case BuiltinType::ULongLong:
|
||||
return llvm::IntegerType::get(
|
||||
static_cast<unsigned>(Context.getTypeSize(T, SourceLocation())));
|
||||
|
||||
case BuiltinType::Float: return llvm::Type::FloatTy;
|
||||
case BuiltinType::Double: return llvm::Type::DoubleTy;
|
||||
case BuiltinType::LongDouble:
|
||||
// FIXME: mapping long double onto double.
|
||||
return llvm::Type::DoubleTy;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::Complex: {
|
||||
std::vector<const llvm::Type*> Elts;
|
||||
Elts.push_back(ConvertType(cast<ComplexType>(Ty).getElementType()));
|
||||
Elts.push_back(Elts[0]);
|
||||
return llvm::StructType::get(Elts);
|
||||
}
|
||||
case Type::Pointer: {
|
||||
const PointerType &P = cast<PointerType>(Ty);
|
||||
return llvm::PointerType::getUnqual(ConvertType(P.getPointeeType()));
|
||||
}
|
||||
case Type::Reference: {
|
||||
const ReferenceType &R = cast<ReferenceType>(Ty);
|
||||
return llvm::PointerType::getUnqual(ConvertType(R.getReferenceeType()));
|
||||
}
|
||||
|
||||
case Type::VariableArray: {
|
||||
const VariableArrayType &A = cast<VariableArrayType>(Ty);
|
||||
assert(A.getSizeModifier() == ArrayType::Normal &&
|
||||
A.getIndexTypeQualifier() == 0 &&
|
||||
"FIXME: We only handle trivial array types so far!");
|
||||
if (A.getSizeExpr() == 0) {
|
||||
// int X[] -> [0 x int]
|
||||
return llvm::ArrayType::get(ConvertType(A.getElementType()), 0);
|
||||
} else {
|
||||
assert(0 && "FIXME: VLAs not implemented yet!");
|
||||
}
|
||||
}
|
||||
case Type::ConstantArray: {
|
||||
const ConstantArrayType &A = cast<ConstantArrayType>(Ty);
|
||||
const llvm::Type *EltTy = ConvertType(A.getElementType());
|
||||
return llvm::ArrayType::get(EltTy, A.getSize().getZExtValue());
|
||||
}
|
||||
case Type::OCUVector:
|
||||
case Type::Vector: {
|
||||
const VectorType &VT = cast<VectorType>(Ty);
|
||||
return llvm::VectorType::get(ConvertType(VT.getElementType()),
|
||||
VT.getNumElements());
|
||||
}
|
||||
case Type::FunctionNoProto:
|
||||
case Type::FunctionProto: {
|
||||
const FunctionType &FP = cast<FunctionType>(Ty);
|
||||
const llvm::Type *ResultType;
|
||||
|
||||
if (FP.getResultType()->isVoidType())
|
||||
ResultType = llvm::Type::VoidTy; // Result of function uses llvm void.
|
||||
else
|
||||
ResultType = ConvertType(FP.getResultType());
|
||||
|
||||
// FIXME: Convert argument types.
|
||||
bool isVarArg;
|
||||
std::vector<const llvm::Type*> ArgTys;
|
||||
|
||||
// Struct return passes the struct byref.
|
||||
if (!ResultType->isFirstClassType() && ResultType != llvm::Type::VoidTy) {
|
||||
const llvm::Type *RType = llvm::PointerType::getUnqual(ResultType);
|
||||
QualType RTy = Context.getPointerType(FP.getResultType());
|
||||
TypeHolderMap.insert(std::make_pair(RTy.getTypePtr(),
|
||||
llvm::PATypeHolder(RType)));
|
||||
|
||||
ArgTys.push_back(RType);
|
||||
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);
|
||||
}
|
||||
|
||||
case Type::ObjCInterface:
|
||||
assert(0 && "FIXME: add missing functionality here");
|
||||
break;
|
||||
|
||||
case Type::ObjCQualifiedInterface:
|
||||
assert(0 && "FIXME: add missing functionality here");
|
||||
break;
|
||||
|
||||
case Type::ObjCQualifiedId:
|
||||
assert(0 && "FIXME: add missing functionality here");
|
||||
break;
|
||||
|
||||
case Type::Tagged:
|
||||
const TagType &TT = cast<TagType>(Ty);
|
||||
const TagDecl *TD = TT.getDecl();
|
||||
llvm::Type *&ResultType = TagDeclTypes[TD];
|
||||
|
||||
// If corresponding llvm type is not a opaque struct type
|
||||
// then use it.
|
||||
if (ResultType && !isOpaqueTypeDefinition(T, ResultType))
|
||||
return ResultType;
|
||||
|
||||
if (!TD->isDefinition()) {
|
||||
ResultType = llvm::OpaqueType::get();
|
||||
} else if (TD->getKind() == Decl::Enum) {
|
||||
return ConvertType(cast<EnumDecl>(TD)->getIntegerType());
|
||||
} else if (TD->getKind() == Decl::Struct) {
|
||||
const RecordDecl *RD = cast<const RecordDecl>(TD);
|
||||
|
||||
// If this is nested record and this RecordDecl is already under
|
||||
// process then return associated OpaqueType for now.
|
||||
llvm::DenseMap<const RecordDecl *, llvm::Type *>::iterator
|
||||
OpaqueI = RecordTypesToResolve.find(RD);
|
||||
if (OpaqueI != RecordTypesToResolve.end())
|
||||
return OpaqueI->second;
|
||||
|
||||
llvm::OpaqueType *OpaqueTy = NULL;
|
||||
if (ResultType)
|
||||
OpaqueTy = dyn_cast<llvm::OpaqueType>(ResultType);
|
||||
if (!OpaqueTy) {
|
||||
// Create new OpaqueType now for later use.
|
||||
// FIXME: This creates a lot of opaque types, most of them are not
|
||||
// needed. Reevaluate this when performance analyis finds tons of
|
||||
// opaque types.
|
||||
OpaqueTy = llvm::OpaqueType::get();
|
||||
TypeHolderMap.insert(std::make_pair(T.getTypePtr(),
|
||||
llvm::PATypeHolder(OpaqueTy)));
|
||||
}
|
||||
RecordTypesToResolve[RD] = OpaqueTy;
|
||||
|
||||
// Layout fields.
|
||||
RecordOrganizer RO(*this);
|
||||
for (unsigned i = 0, e = RD->getNumMembers(); i != e; ++i)
|
||||
RO.addField(RD->getMember(i));
|
||||
const ASTRecordLayout &RL = Context.getASTRecordLayout(RD,
|
||||
SourceLocation());
|
||||
RO.layoutStructFields(RL);
|
||||
|
||||
// Get llvm::StructType.
|
||||
CGRecordLayout *RLI = new CGRecordLayout(RO.getLLVMType());
|
||||
ResultType = RLI->getLLVMType();
|
||||
CGRecordLayouts[ResultType] = RLI;
|
||||
|
||||
// Refine any OpaqueType associated with this RecordDecl.
|
||||
OpaqueTy->refineAbstractTypeTo(ResultType);
|
||||
OpaqueI = RecordTypesToResolve.find(RD);
|
||||
assert (OpaqueI != RecordTypesToResolve.end()
|
||||
&& "Expected RecordDecl in RecordTypesToResolve");
|
||||
RecordTypesToResolve.erase(OpaqueI);
|
||||
|
||||
} else if (TD->getKind() == Decl::Union) {
|
||||
const RecordDecl *RD = cast<const RecordDecl>(TD);
|
||||
// Just use the largest element of the union, breaking ties with the
|
||||
// highest aligned member.
|
||||
|
||||
if (RD->getNumMembers() != 0) {
|
||||
RecordOrganizer RO(*this);
|
||||
for (unsigned i = 0, e = RD->getNumMembers(); i != e; ++i)
|
||||
RO.addField(RD->getMember(i));
|
||||
RO.layoutUnionFields();
|
||||
|
||||
// Get llvm::StructType.
|
||||
CGRecordLayout *RLI = new CGRecordLayout(RO.getLLVMType());
|
||||
ResultType = RLI->getLLVMType();
|
||||
CGRecordLayouts[ResultType] = RLI;
|
||||
} else {
|
||||
std::vector<const llvm::Type*> Fields;
|
||||
ResultType = llvm::StructType::get(Fields);
|
||||
}
|
||||
} else {
|
||||
assert(0 && "FIXME: Implement tag decl kind!");
|
||||
}
|
||||
|
||||
std::string TypeName(TD->getKindName());
|
||||
TypeName += '.';
|
||||
|
||||
// Name the codegen type after the typedef name
|
||||
// if there is no tag type name available
|
||||
if (TD->getIdentifier() == 0) {
|
||||
if (T->getTypeClass() == Type::TypeName) {
|
||||
const TypedefType *TdT = cast<TypedefType>(T);
|
||||
TypeName += TdT->getDecl()->getName();
|
||||
} else
|
||||
TypeName += "anon";
|
||||
} else
|
||||
TypeName += TD->getName();
|
||||
|
||||
TheModule.addTypeName(TypeName, ResultType);
|
||||
return ResultType;
|
||||
}
|
||||
|
||||
// FIXME: implement.
|
||||
return llvm::OpaqueType::get();
|
||||
}
|
||||
|
||||
void CodeGenTypes::DecodeArgumentTypes(const FunctionTypeProto &FTP,
|
||||
std::vector<const llvm::Type*> &ArgTys) {
|
||||
for (unsigned i = 0, e = FTP.getNumArgs(); i != e; ++i) {
|
||||
const llvm::Type *Ty = ConvertType(FTP.getArgType(i));
|
||||
if (Ty->isFirstClassType())
|
||||
ArgTys.push_back(Ty);
|
||||
else {
|
||||
QualType PTy = Context.getPointerType(FTP.getArgType(i));
|
||||
const llvm::Type *PtrTy = llvm::PointerType::getUnqual(Ty);
|
||||
TypeHolderMap.insert(std::make_pair(PTy.getTypePtr(),
|
||||
llvm::PATypeHolder(PtrTy)));
|
||||
|
||||
ArgTys.push_back(PtrTy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// getLLVMFieldNo - Return llvm::StructType element number
|
||||
/// that corresponds to the field FD.
|
||||
unsigned CodeGenTypes::getLLVMFieldNo(const FieldDecl *FD) {
|
||||
// FIXME : Check bit fields also
|
||||
llvm::DenseMap<const FieldDecl *, unsigned>::iterator
|
||||
I = FieldInfo.find(FD);
|
||||
assert (I != FieldInfo.end() && "Unable to find field info");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
/// addFieldInfo - Assign field number to field FD.
|
||||
void CodeGenTypes::addFieldInfo(const FieldDecl *FD, unsigned No,
|
||||
unsigned Begin, unsigned End) {
|
||||
if (Begin == 0 && End == 0)
|
||||
FieldInfo[FD] = No;
|
||||
else
|
||||
// FD is a bit field
|
||||
BitFields.insert(std::make_pair(FD, BitFieldInfo(No, Begin, End)));
|
||||
}
|
||||
|
||||
/// getCGRecordLayout - Return record layout info for the given llvm::Type.
|
||||
const CGRecordLayout *
|
||||
CodeGenTypes::getCGRecordLayout(const llvm::Type* Ty) const {
|
||||
llvm::DenseMap<const llvm::Type*, CGRecordLayout *>::iterator I
|
||||
= CGRecordLayouts.find(Ty);
|
||||
assert (I != CGRecordLayouts.end()
|
||||
&& "Unable to find record layout information for type");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
/// addField - Add new field.
|
||||
void RecordOrganizer::addField(const FieldDecl *FD) {
|
||||
assert (!STy && "Record fields are already laid out");
|
||||
FieldDecls.push_back(FD);
|
||||
}
|
||||
|
||||
/// layoutStructFields - Do the actual work and lay out all fields. Create
|
||||
/// corresponding llvm struct type. This should be invoked only after
|
||||
/// all fields are added.
|
||||
/// FIXME : At the moment assume
|
||||
/// - one to one mapping between AST FieldDecls and
|
||||
/// llvm::StructType elements.
|
||||
/// - Ignore bit fields
|
||||
/// - Ignore field aligments
|
||||
/// - Ignore packed structs
|
||||
void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) {
|
||||
// FIXME : Use SmallVector
|
||||
Cursor = 0;
|
||||
FieldNo = 0;
|
||||
LLVMFields.clear();
|
||||
for (llvm::SmallVector<const FieldDecl *, 8>::iterator I = FieldDecls.begin(),
|
||||
E = FieldDecls.end(); I != E; ++I) {
|
||||
const FieldDecl *FD = *I;
|
||||
|
||||
if (FD->isBitField())
|
||||
placeBitField(FD);
|
||||
else {
|
||||
ExtraBits = 0;
|
||||
// FD is not a bitfield. If prev field was a bit field then it may have
|
||||
// positioned cursor such that it needs adjustment now.
|
||||
if (Cursor % 8 != 0)
|
||||
fixCursorPosition(RL);
|
||||
|
||||
const llvm::Type *Ty = CGT.ConvertType(FD->getType());
|
||||
addLLVMField(Ty, CGT.getTargetData().getABITypeSizeInBits(Ty), FD, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// At the end of structure, cursor should point to end of the strucutre.
|
||||
// This may not happen automatically if last field is a bit-field.
|
||||
fixCursorPosition(RL);
|
||||
|
||||
STy = llvm::StructType::get(LLVMFields);
|
||||
}
|
||||
|
||||
/// addPaddingFields - Current cursor is not suitable place to add next field.
|
||||
/// Add required padding fields.
|
||||
void RecordOrganizer::addPaddingFields(unsigned WaterMark) {
|
||||
unsigned RequiredBits = WaterMark - Cursor;
|
||||
assert ((RequiredBits % 8) == 0 && "FIXME Invalid struct layout");
|
||||
unsigned RequiredBytes = RequiredBits / 8;
|
||||
for (unsigned i = 0; i != RequiredBytes; ++i)
|
||||
addLLVMField(llvm::Type::Int8Ty,
|
||||
CGT.getTargetData().getABITypeSizeInBits(llvm::Type::Int8Ty));
|
||||
}
|
||||
|
||||
/// addLLVMField - Add llvm struct field that corresponds to llvm type Ty.
|
||||
/// Update cursor and increment field count. If field decl FD is available than
|
||||
/// update field info at CodeGenTypes level.
|
||||
void RecordOrganizer::addLLVMField(const llvm::Type *Ty, uint64_t Size,
|
||||
const FieldDecl *FD, unsigned Begin,
|
||||
unsigned End) {
|
||||
|
||||
unsigned AlignmentInBits = CGT.getTargetData().getABITypeAlignment(Ty) * 8;
|
||||
unsigned WaterMark = Cursor + (Cursor % AlignmentInBits);
|
||||
if (Cursor != WaterMark)
|
||||
// At the moment, insert padding fields even if target specific llvm
|
||||
// type alignment enforces implict padding fields for FD. Later on,
|
||||
// optimize llvm fields by removing implicit padding fields and
|
||||
// combining consequetive padding fields.
|
||||
addPaddingFields(WaterMark);
|
||||
|
||||
Offsets.push_back(Cursor);
|
||||
CurrentFieldStart = Cursor;
|
||||
Cursor += Size;
|
||||
llvmSize += Size;
|
||||
LLVMFields.push_back(Ty);
|
||||
if (FD)
|
||||
CGT.addFieldInfo(FD, FieldNo, Begin, End);
|
||||
++FieldNo;
|
||||
}
|
||||
|
||||
/// layoutUnionFields - Do the actual work and lay out all fields. Create
|
||||
/// corresponding llvm struct type. This should be invoked only after
|
||||
/// all fields are added.
|
||||
void RecordOrganizer::layoutUnionFields() {
|
||||
|
||||
unsigned PrimaryEltNo = 0;
|
||||
std::pair<uint64_t, unsigned> PrimaryElt =
|
||||
CGT.getContext().getTypeInfo(FieldDecls[0]->getType(), SourceLocation());
|
||||
CGT.addFieldInfo(FieldDecls[0], 0, 0, 0);
|
||||
|
||||
unsigned Size = FieldDecls.size();
|
||||
for(unsigned i = 1; i != Size; ++i) {
|
||||
const FieldDecl *FD = FieldDecls[i];
|
||||
assert (!FD->isBitField() && "Bit fields are not yet supported");
|
||||
std::pair<uint64_t, unsigned> EltInfo =
|
||||
CGT.getContext().getTypeInfo(FD->getType(), SourceLocation());
|
||||
|
||||
// Use largest element, breaking ties with the hightest aligned member.
|
||||
if (EltInfo.first > PrimaryElt.first ||
|
||||
(EltInfo.first == PrimaryElt.first &&
|
||||
EltInfo.second > PrimaryElt.second)) {
|
||||
PrimaryElt = EltInfo;
|
||||
PrimaryEltNo = i;
|
||||
}
|
||||
|
||||
// In union, each field gets first slot.
|
||||
CGT.addFieldInfo(FD, 0, 0, 0);
|
||||
}
|
||||
|
||||
std::vector<const llvm::Type*> Fields;
|
||||
const llvm::Type *Ty = CGT.ConvertType(FieldDecls[PrimaryEltNo]->getType());
|
||||
Fields.push_back(Ty);
|
||||
STy = llvm::StructType::get(Fields);
|
||||
}
|
||||
|
||||
/// fixCursorPosition - When bit-field is followed by a normal field
|
||||
/// cursor position may require some adjustments.
|
||||
///
|
||||
/// For example, struct { char a; short b:2; char c; };
|
||||
///
|
||||
/// At the beginning of field 'c' layout, cursor position is 10.
|
||||
/// However, only llvm struct field allocated so far is of type i8.
|
||||
/// This happens because 'b' shares llvm field with 'a'. Add padding
|
||||
/// field of i8 type and reposition cursor to point at 16. This
|
||||
/// should be done only if next field (i.e. 'c' here) is not a bit-field
|
||||
/// or last record field is a bit-field.
|
||||
void RecordOrganizer::fixCursorPosition(const ASTRecordLayout &RL) {
|
||||
Cursor = llvmSize;
|
||||
unsigned llvmSizeBytes = llvmSize/8;
|
||||
unsigned StructAlign = RL.getAlignment() / 8;
|
||||
if (llvmSizeBytes % StructAlign) {
|
||||
unsigned StructPadding = StructAlign - (llvmSizeBytes % StructAlign);
|
||||
addPaddingFields(Cursor + StructPadding*8);
|
||||
}
|
||||
}
|
||||
|
||||
/// placeBitField - Find a place for FD, which is a bit-field.
|
||||
/// There are three separate cases to handle
|
||||
/// 1) Cursor starts at byte boundry and there are no extra
|
||||
/// bits are available in last llvm struct field.
|
||||
/// 2) Extra bits from previous last llvm struct field are
|
||||
/// available and have enough space to hold entire FD.
|
||||
/// 3) Extra bits from previous last llvm struct field are
|
||||
/// available but they are not enough to hold FD entirly.
|
||||
void RecordOrganizer::placeBitField(const FieldDecl *FD) {
|
||||
|
||||
assert (FD->isBitField() && "FD is not a bit-field");
|
||||
Expr *BitWidth = FD->getBitWidth();
|
||||
llvm::APSInt FieldSize(32);
|
||||
bool isBitField =
|
||||
BitWidth->isIntegerConstantExpr(FieldSize, CGT.getContext());
|
||||
assert (isBitField && "Invalid BitField size expression");
|
||||
uint64_t BitFieldSize = FieldSize.getZExtValue();
|
||||
if (ExtraBits == 0) {
|
||||
// CurrentField is a bit-field and structure is in one of the
|
||||
// following form.
|
||||
// struct { char CurrentField:2; char B:4; }
|
||||
// struct { char A; char CurrentField:2; };
|
||||
// struct { char A; short CurrentField:2; };
|
||||
const llvm::Type *Ty = CGT.ConvertType(FD->getType());
|
||||
// Calculate extra bits available in this bitfield.
|
||||
ExtraBits = CGT.getTargetData().getABITypeSizeInBits(Ty) - BitFieldSize;
|
||||
|
||||
if (LLVMFields.empty())
|
||||
// Ths is - struct { char CurrentField:2; char B:4; }
|
||||
addLLVMField(Ty, BitFieldSize, FD, 0, ExtraBits);
|
||||
else {
|
||||
const llvm::Type *PrevTy = LLVMFields.back();
|
||||
if (CGT.getTargetData().getABITypeSizeInBits(PrevTy) >=
|
||||
CGT.getTargetData().getABITypeSizeInBits(Ty))
|
||||
// This is - struct { char A; char CurrentField:2; };
|
||||
addLLVMField(Ty, BitFieldSize, FD, 0, ExtraBits);
|
||||
else {
|
||||
// This is - struct { char A; short CurrentField:2; };
|
||||
// Use one of the previous filed to access current field.
|
||||
bool FoundPrevField = false;
|
||||
unsigned TotalOffsets = Offsets.size();
|
||||
uint64_t TySize = CGT.getTargetData().getABITypeSizeInBits(Ty);
|
||||
for (unsigned i = TotalOffsets; i != 0; --i) {
|
||||
uint64_t O = Offsets[i - 1];
|
||||
if (O % TySize == 0) {
|
||||
// This is appropriate llvm field to share access.
|
||||
FoundPrevField = true;
|
||||
CurrentFieldStart = O % TySize;
|
||||
unsigned FieldBegin = Cursor - (O % TySize);
|
||||
unsigned FieldEnd = TySize - (FieldBegin + BitFieldSize);
|
||||
Cursor += BitFieldSize;
|
||||
CGT.addFieldInfo(FD, i, FieldBegin, FieldEnd);
|
||||
}
|
||||
}
|
||||
assert(FoundPrevField &&
|
||||
"Unable to find a place for bitfield in struct layout");
|
||||
}
|
||||
}
|
||||
} else if (ExtraBits >= BitFieldSize) {
|
||||
const llvm::Type *Ty = CGT.ConvertType(FD->getType());
|
||||
uint64_t TySize = CGT.getTargetData().getABITypeSizeInBits(Ty);
|
||||
if (Cursor - CurrentFieldStart + BitFieldSize > TySize) {
|
||||
// This is : struct { char a; int b:10; int c:18; };
|
||||
// where 'b' shares first field with 'a'. However 'c' needs
|
||||
// new llvm field.
|
||||
|
||||
//unsigned ExtraBitsInCurrentByte = 8 - (Cursor % 8);
|
||||
//Cursor = Cursor + ExtraBitsInCurrentByte;
|
||||
//ExtraBits = 0;
|
||||
Cursor = llvmSize;
|
||||
unsigned EndOfCurrentType = CurrentFieldStart + TySize;
|
||||
addPaddingFields(EndOfCurrentType);
|
||||
addLLVMField(Ty, TySize, FD, 0, BitFieldSize);
|
||||
} else {
|
||||
// Reuse existing llvm field
|
||||
ExtraBits = ExtraBits - BitFieldSize;
|
||||
CGT.addFieldInfo(FD, FieldNo, Cursor - CurrentFieldStart, ExtraBits);
|
||||
Cursor = Cursor + BitFieldSize;
|
||||
++FieldNo;
|
||||
}
|
||||
} else {
|
||||
//ExtraBits are not enough to hold entire FD.
|
||||
const llvm::Type *Ty = CGT.ConvertType(FD->getType());
|
||||
const llvm::Type *PrevTy = LLVMFields.back();
|
||||
uint64_t TySize = CGT.getTargetData().getABITypeSizeInBits(Ty);
|
||||
assert (CGT.getTargetData().getABITypeSizeInBits(PrevTy) >= TySize
|
||||
&& "Unable to handle bit field");
|
||||
|
||||
// Previous field does not allow sharing of ExtraBits. Use new field.
|
||||
// struct { char a; char b:5; char c:4; } where c is current FD.
|
||||
Cursor += ExtraBits;
|
||||
ExtraBits = 0;
|
||||
addLLVMField(Ty, TySize, FD, 0, BitFieldSize);
|
||||
}
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
//===--- CodeGenTypes.h - Type translation for LLVM CodeGen -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the code that handles AST -> LLVM type lowering.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CODEGEN_CODEGENTYPES_H
|
||||
#define CODEGEN_CODEGENTYPES_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
class Type;
|
||||
class PATypeHolder;
|
||||
class TargetData;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class TagDecl;
|
||||
class TargetInfo;
|
||||
class QualType;
|
||||
class Type;
|
||||
class FunctionTypeProto;
|
||||
class FieldDecl;
|
||||
class RecordDecl;
|
||||
|
||||
namespace CodeGen {
|
||||
class CodeGenTypes;
|
||||
|
||||
/// CGRecordLayout - This class handles struct and union layout info while
|
||||
/// lowering AST types to LLVM types.
|
||||
class CGRecordLayout {
|
||||
CGRecordLayout(); // DO NOT IMPLEMENT
|
||||
public:
|
||||
CGRecordLayout(llvm::Type *T) : STy(T) {
|
||||
// FIXME : Collect info about fields that requires adjustments
|
||||
// (i.e. fields that do not directly map to llvm struct fields.)
|
||||
}
|
||||
|
||||
/// getLLVMType - Return llvm type associated with this record.
|
||||
llvm::Type *getLLVMType() const {
|
||||
return STy;
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::Type *STy;
|
||||
};
|
||||
|
||||
/// CodeGenTypes - This class organizes the cross-module state that is used
|
||||
/// while lowering AST types to LLVM types.
|
||||
class CodeGenTypes {
|
||||
ASTContext &Context;
|
||||
TargetInfo &Target;
|
||||
llvm::Module& TheModule;
|
||||
const llvm::TargetData& TheTargetData;
|
||||
|
||||
llvm::DenseMap<const TagDecl*, llvm::Type*> TagDeclTypes;
|
||||
|
||||
/// CGRecordLayouts - This maps llvm struct type with corresponding
|
||||
/// record layout info.
|
||||
/// FIXME : If CGRecordLayout is less than 16 bytes then use
|
||||
/// inline it in the map.
|
||||
llvm::DenseMap<const llvm::Type*, CGRecordLayout *> CGRecordLayouts;
|
||||
|
||||
/// FieldInfo - This maps struct field with corresponding llvm struct type
|
||||
/// field no. This info is populated by record organizer.
|
||||
llvm::DenseMap<const FieldDecl *, unsigned> FieldInfo;
|
||||
|
||||
class BitFieldInfo {
|
||||
public:
|
||||
explicit BitFieldInfo(unsigned N, unsigned B, unsigned E)
|
||||
: No(N), Begin(B), End(E) {}
|
||||
private:
|
||||
// No - llvm struct field number that is used to
|
||||
// access this field. It may be not same as struct field number.
|
||||
// For example,
|
||||
// struct S { char a; short b:2; }
|
||||
// Here field 'b' is second field however it is accessed as
|
||||
// 9th and 10th bitfield of first field whose type is short.
|
||||
unsigned No;
|
||||
unsigned Begin;
|
||||
unsigned End;
|
||||
};
|
||||
llvm::DenseMap<const FieldDecl *, BitFieldInfo> BitFields;
|
||||
|
||||
/// RecordTypesToResolve - This keeps track of record types that are not
|
||||
/// yet incomplete. One llvm::OpaqueType is associated with each incomplete
|
||||
/// record.
|
||||
llvm::DenseMap<const RecordDecl *, llvm::Type *> RecordTypesToResolve;
|
||||
|
||||
/// TypeHolderMap - This map keeps cache of llvm::Types (through PATypeHolder)
|
||||
/// and maps llvm::Types to corresponding clang::Type. llvm::PATypeHolder is
|
||||
/// used instead of llvm::Type because it allows us to bypass potential
|
||||
/// dangling type pointers due to type refinement on llvm side.
|
||||
llvm::DenseMap<Type *, llvm::PATypeHolder> TypeHolderMap;
|
||||
|
||||
/// ConvertNewType - Convert type T into a llvm::Type. Do not use this
|
||||
/// method directly because it does not do any type caching. This method
|
||||
/// is available only for ConvertType(). CovertType() is preferred
|
||||
/// interface to convert type T into a llvm::Type.
|
||||
const llvm::Type *ConvertNewType(QualType T);
|
||||
public:
|
||||
CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD);
|
||||
~CodeGenTypes();
|
||||
|
||||
const llvm::TargetData &getTargetData() const { return TheTargetData; }
|
||||
TargetInfo &getTarget() const { return Target; }
|
||||
ASTContext &getContext() const { return Context; }
|
||||
|
||||
/// ConvertType - Convert type T into a llvm::Type. Maintain and use
|
||||
/// type cache through TypeHolderMap.
|
||||
const llvm::Type *ConvertType(QualType T);
|
||||
|
||||
/// ConvertTypeForMem - Convert type T into a llvm::Type. Maintain and use
|
||||
/// type cache through TypeHolderMap. This differs from ConvertType in that
|
||||
/// it is used to convert to the memory representation for a type. For
|
||||
/// example, the scalar representation for _Bool is i1, but the memory
|
||||
/// representation is usually i8 or i32, depending on the target.
|
||||
const llvm::Type *ConvertTypeForMem(QualType T);
|
||||
|
||||
|
||||
const CGRecordLayout *getCGRecordLayout(const llvm::Type*) const;
|
||||
|
||||
/// getLLVMFieldNo - Return llvm::StructType element number
|
||||
/// that corresponds to the field FD.
|
||||
unsigned getLLVMFieldNo(const FieldDecl *FD);
|
||||
|
||||
public: // These are internal details of CGT that shouldn't be used externally.
|
||||
void DecodeArgumentTypes(const FunctionTypeProto &FTP,
|
||||
std::vector<const llvm::Type*> &ArgTys);
|
||||
|
||||
/// addFieldInfo - Assign field number to field FD.
|
||||
void addFieldInfo(const FieldDecl *FD, unsigned No, unsigned Begin,
|
||||
unsigned End);
|
||||
};
|
||||
|
||||
} // end namespace CodeGen
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,23 +0,0 @@
|
||||
##===- clang/CodeGen/Makefile ------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# This implements the AST -> LLVM code generation library for the
|
||||
# C-Language front-end.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../..
|
||||
LIBRARYNAME := clangCodeGen
|
||||
BUILD_ARCHIVE = 1
|
||||
CXXFLAGS = -fno-rtti
|
||||
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
//===--- ModuleBuilder.cpp - Emit LLVM Code from ASTs ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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"
|
||||
#include "clang/AST/Decl.h"
|
||||
using namespace clang;
|
||||
|
||||
|
||||
/// Init - Create an ModuleBuilder with the specified ASTContext.
|
||||
clang::CodeGen::CodeGenModule *
|
||||
clang::CodeGen::Init(ASTContext &Context, const LangOptions &Features,
|
||||
llvm::Module &M, const llvm::TargetData &TD,
|
||||
Diagnostic &Diags) {
|
||||
return new CodeGenModule(Context, Features, M, TD, Diags);
|
||||
}
|
||||
|
||||
void clang::CodeGen::Terminate(CodeGenModule *B) {
|
||||
delete B;
|
||||
}
|
||||
|
||||
/// CodeGenFunction - Convert the AST node for a FunctionDecl into LLVM.
|
||||
///
|
||||
void clang::CodeGen::CodeGenFunction(CodeGenModule *B, FunctionDecl *D) {
|
||||
B->EmitFunction(D);
|
||||
}
|
||||
|
||||
/// CodeGenLinkageSpec - Emit the specified linkage space to LLVM.
|
||||
void clang::CodeGen::CodeGenLinkageSpec(CodeGenModule *Builder,
|
||||
LinkageSpecDecl *LS) {
|
||||
if (LS->getLanguage() == LinkageSpecDecl::lang_cxx)
|
||||
Builder->WarnUnsupported(LS, "linkage spec");
|
||||
|
||||
// FIXME: implement C++ linkage, C linkage works mostly by C
|
||||
// language reuse already.
|
||||
}
|
||||
|
||||
/// CodeGenGlobalVar - Emit the specified global variable to LLVM.
|
||||
void clang::CodeGen::CodeGenGlobalVar(CodeGenModule *Builder, FileVarDecl *D) {
|
||||
Builder->EmitGlobalVarDeclarator(D);
|
||||
}
|
||||
|
||||
|
||||
/// PrintStats - Emit statistic information to stderr.
|
||||
///
|
||||
void clang::CodeGen::PrintStats(CodeGenModule *B) {
|
||||
B->PrintStats();
|
||||
}
|
||||
@@ -1,828 +0,0 @@
|
||||
//===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// AST Consumer Implementations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ASTConsumers.h"
|
||||
#include "clang/AST/TranslationUnit.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
#include "clang/Analysis/Analyses/GRConstants.h"
|
||||
#include "clang/Analysis/LocalCheckers.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include <fstream>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DeclPrinter - Utility class for printing top-level decls.
|
||||
|
||||
namespace {
|
||||
class DeclPrinter {
|
||||
public:
|
||||
std::ostream& Out;
|
||||
|
||||
DeclPrinter(std::ostream* out) : Out(out ? *out : *llvm::cerr.stream()) {}
|
||||
DeclPrinter() : Out(*llvm::cerr.stream()) {}
|
||||
|
||||
void PrintDecl(Decl *D);
|
||||
void PrintFunctionDeclStart(FunctionDecl *FD);
|
||||
void PrintTypeDefDecl(TypedefDecl *TD);
|
||||
void PrintLinkageSpec(LinkageSpecDecl *LS);
|
||||
void PrintObjCMethodDecl(ObjCMethodDecl *OMD);
|
||||
void PrintObjCImplementationDecl(ObjCImplementationDecl *OID);
|
||||
void PrintObjCInterfaceDecl(ObjCInterfaceDecl *OID);
|
||||
void PrintObjCProtocolDecl(ObjCProtocolDecl *PID);
|
||||
void PrintObjCCategoryImplDecl(ObjCCategoryImplDecl *PID);
|
||||
void PrintObjCCategoryDecl(ObjCCategoryDecl *PID);
|
||||
void PrintObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
void DeclPrinter:: PrintDecl(Decl *D) {
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
PrintFunctionDeclStart(FD);
|
||||
|
||||
if (FD->getBody()) {
|
||||
Out << ' ';
|
||||
FD->getBody()->printPretty(Out);
|
||||
Out << '\n';
|
||||
}
|
||||
} else if (isa<ObjCMethodDecl>(D)) {
|
||||
// Do nothing, methods definitions are printed in
|
||||
// PrintObjCImplementationDecl.
|
||||
} else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
|
||||
PrintTypeDefDecl(TD);
|
||||
} else if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(D)) {
|
||||
PrintObjCInterfaceDecl(OID);
|
||||
} else if (ObjCProtocolDecl *PID = dyn_cast<ObjCProtocolDecl>(D)) {
|
||||
PrintObjCProtocolDecl(PID);
|
||||
} else if (ObjCForwardProtocolDecl *OFPD =
|
||||
dyn_cast<ObjCForwardProtocolDecl>(D)) {
|
||||
Out << "@protocol ";
|
||||
for (unsigned i = 0, e = OFPD->getNumForwardDecls(); i != e; ++i) {
|
||||
const ObjCProtocolDecl *D = OFPD->getForwardProtocolDecl(i);
|
||||
if (i) Out << ", ";
|
||||
Out << D->getName();
|
||||
}
|
||||
Out << ";\n";
|
||||
} else if (ObjCImplementationDecl *OID =
|
||||
dyn_cast<ObjCImplementationDecl>(D)) {
|
||||
PrintObjCImplementationDecl(OID);
|
||||
} else if (ObjCCategoryImplDecl *OID =
|
||||
dyn_cast<ObjCCategoryImplDecl>(D)) {
|
||||
PrintObjCCategoryImplDecl(OID);
|
||||
} else if (ObjCCategoryDecl *OID =
|
||||
dyn_cast<ObjCCategoryDecl>(D)) {
|
||||
PrintObjCCategoryDecl(OID);
|
||||
} else if (ObjCCompatibleAliasDecl *OID =
|
||||
dyn_cast<ObjCCompatibleAliasDecl>(D)) {
|
||||
PrintObjCCompatibleAliasDecl(OID);
|
||||
} else if (isa<ObjCClassDecl>(D)) {
|
||||
Out << "@class [printing todo]\n";
|
||||
} else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
|
||||
Out << "Read top-level tag decl: '" << TD->getName() << "'\n";
|
||||
} else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) {
|
||||
Out << "Read top-level variable decl: '" << SD->getName() << "'\n";
|
||||
} else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
|
||||
PrintLinkageSpec(LSD);
|
||||
} else {
|
||||
assert(0 && "Unknown decl type!");
|
||||
}
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintFunctionDeclStart(FunctionDecl *FD) {
|
||||
bool HasBody = FD->getBody();
|
||||
|
||||
Out << '\n';
|
||||
|
||||
switch (FD->getStorageClass()) {
|
||||
default: assert(0 && "Unknown storage class");
|
||||
case FunctionDecl::None: break;
|
||||
case FunctionDecl::Extern: Out << "extern "; break;
|
||||
case FunctionDecl::Static: Out << "static "; break;
|
||||
}
|
||||
|
||||
if (FD->isInline())
|
||||
Out << "inline ";
|
||||
|
||||
std::string Proto = FD->getName();
|
||||
const FunctionType *AFT = FD->getType()->getAsFunctionType();
|
||||
|
||||
if (const 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);
|
||||
Out << Proto;
|
||||
|
||||
if (!FD->getBody())
|
||||
Out << ";\n";
|
||||
// Doesn't print the body.
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintTypeDefDecl(TypedefDecl *TD) {
|
||||
std::string S = TD->getName();
|
||||
TD->getUnderlyingType().getAsStringInternal(S);
|
||||
Out << "typedef " << S << ";\n";
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintLinkageSpec(LinkageSpecDecl *LS) {
|
||||
const char *l;
|
||||
if (LS->getLanguage() == LinkageSpecDecl::lang_c)
|
||||
l = "C";
|
||||
else if (LS->getLanguage() == LinkageSpecDecl::lang_cxx)
|
||||
l = "C++";
|
||||
else assert(0 && "unknown language in linkage specification");
|
||||
Out << "extern \"" << l << "\" { ";
|
||||
PrintDecl(LS->getDecl());
|
||||
Out << "}\n";
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCMethodDecl(ObjCMethodDecl *OMD) {
|
||||
if (OMD->isInstance())
|
||||
Out << "\n- ";
|
||||
else
|
||||
Out << "\n+ ";
|
||||
if (!OMD->getResultType().isNull())
|
||||
Out << '(' << OMD->getResultType().getAsString() << ") ";
|
||||
// FIXME: just print original selector name!
|
||||
Out << OMD->getSelector().getName();
|
||||
|
||||
for (int i = 0; i < OMD->getNumParams(); i++) {
|
||||
ParmVarDecl *PDecl = OMD->getParamDecl(i);
|
||||
// FIXME: selector is missing here!
|
||||
Out << " :(" << PDecl->getType().getAsString() << ") " << PDecl->getName();
|
||||
}
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCImplementationDecl(ObjCImplementationDecl *OID) {
|
||||
std::string I = OID->getName();
|
||||
ObjCInterfaceDecl *SID = OID->getSuperClass();
|
||||
|
||||
if (SID)
|
||||
Out << "@implementation " << I << " : " << SID->getName();
|
||||
else
|
||||
Out << "@implementation " << I;
|
||||
|
||||
for (ObjCImplementationDecl::instmeth_iterator I = OID->instmeth_begin(),
|
||||
E = OID->instmeth_end(); I != E; ++I) {
|
||||
ObjCMethodDecl *OMD = *I;
|
||||
PrintObjCMethodDecl(OMD);
|
||||
if (OMD->getBody()) {
|
||||
Out << ' ';
|
||||
OMD->getBody()->printPretty(Out);
|
||||
Out << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
for (ObjCImplementationDecl::classmeth_iterator I = OID->classmeth_begin(),
|
||||
E = OID->classmeth_end(); I != E; ++I) {
|
||||
ObjCMethodDecl *OMD = *I;
|
||||
PrintObjCMethodDecl(OMD);
|
||||
if (OMD->getBody()) {
|
||||
Out << ' ';
|
||||
OMD->getBody()->printPretty(Out);
|
||||
Out << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
Out << "@end\n";
|
||||
}
|
||||
|
||||
|
||||
void DeclPrinter::PrintObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
|
||||
std::string I = OID->getName();
|
||||
ObjCInterfaceDecl *SID = OID->getSuperClass();
|
||||
|
||||
if (SID)
|
||||
Out << "@interface " << I << " : " << SID->getName();
|
||||
else
|
||||
Out << "@interface " << I;
|
||||
|
||||
// Protocols?
|
||||
int count = OID->getNumIntfRefProtocols();
|
||||
|
||||
if (count > 0) {
|
||||
ObjCProtocolDecl **refProtocols = OID->getReferencedProtocols();
|
||||
for (int i = 0; i < count; i++)
|
||||
Out << (i == 0 ? '<' : ',') << refProtocols[i]->getName();
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
Out << ">\n";
|
||||
else
|
||||
Out << '\n';
|
||||
|
||||
if (OID->getNumInstanceVariables() > 0) {
|
||||
Out << '{';
|
||||
for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(),
|
||||
E = OID->ivar_end(); I != E; ++I) {
|
||||
Out << '\t' << (*I)->getType().getAsString()
|
||||
<< ' ' << (*I)->getName() << ";\n";
|
||||
}
|
||||
Out << "}\n";
|
||||
}
|
||||
|
||||
int NumProperties = OID->getNumPropertyDecl();
|
||||
if (NumProperties > 0) {
|
||||
for (int i = 0; i < NumProperties; i++) {
|
||||
ObjCPropertyDecl *PDecl = OID->getPropertyDecl()[i];
|
||||
Out << "@property";
|
||||
if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) {
|
||||
bool first = true;
|
||||
Out << " (";
|
||||
if (PDecl->getPropertyAttributes() &
|
||||
ObjCPropertyDecl::OBJC_PR_readonly) {
|
||||
Out << (first ? ' ' : ',') << "readonly";
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) {
|
||||
Out << (first ? ' ' : ',') << "getter = "
|
||||
<< PDecl->getGetterName()->getName();
|
||||
first = false;
|
||||
}
|
||||
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) {
|
||||
Out << (first ? ' ' : ',') << "setter = "
|
||||
<< PDecl->getSetterName()->getName();
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) {
|
||||
Out << (first ? ' ' : ',') << "assign";
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (PDecl->getPropertyAttributes() &
|
||||
ObjCPropertyDecl::OBJC_PR_readwrite) {
|
||||
Out << (first ? ' ' : ',') << "readwrite";
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) {
|
||||
Out << (first ? ' ' : ',') << "retain";
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) {
|
||||
Out << (first ? ' ' : ',') << "copy";
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (PDecl->getPropertyAttributes() &
|
||||
ObjCPropertyDecl::OBJC_PR_nonatomic) {
|
||||
Out << (first ? ' ' : ',') << "nonatomic";
|
||||
first = false;
|
||||
}
|
||||
Out << " )";
|
||||
}
|
||||
|
||||
ObjCIvarDecl **IDecl = PDecl->getPropertyDecls();
|
||||
|
||||
Out << ' ' << IDecl[0]->getType().getAsString()
|
||||
<< ' ' << IDecl[0]->getName();
|
||||
|
||||
for (int j = 1; j < PDecl->getNumPropertyDecls(); j++)
|
||||
Out << ", " << IDecl[j]->getName();
|
||||
|
||||
Out << ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
Out << "@end\n";
|
||||
// FIXME: implement the rest...
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCProtocolDecl(ObjCProtocolDecl *PID) {
|
||||
Out << "@protocol " << PID->getName() << '\n';
|
||||
// FIXME: implement the rest...
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
|
||||
Out << "@implementation "
|
||||
<< PID->getClassInterface()->getName()
|
||||
<< '(' << PID->getName() << ");\n";
|
||||
|
||||
// FIXME: implement the rest...
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCCategoryDecl(ObjCCategoryDecl *PID) {
|
||||
Out << "@interface "
|
||||
<< PID->getClassInterface()->getName()
|
||||
<< '(' << PID->getName() << ");\n";
|
||||
// FIXME: implement the rest...
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) {
|
||||
Out << "@compatibility_alias " << AID->getName()
|
||||
<< ' ' << AID->getClassInterface()->getName() << ";\n";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// ASTPrinter - Pretty-printer of ASTs
|
||||
|
||||
namespace {
|
||||
class ASTPrinter : public ASTConsumer, public DeclPrinter {
|
||||
public:
|
||||
ASTPrinter(std::ostream* o = NULL) : DeclPrinter(o) {}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
PrintDecl(D);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ASTConsumer *clang::CreateASTPrinter(std::ostream* out) {
|
||||
return new ASTPrinter(out);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// ASTDumper - Low-level dumper of ASTs
|
||||
|
||||
namespace {
|
||||
class ASTDumper : public ASTConsumer, public DeclPrinter {
|
||||
SourceManager *SM;
|
||||
public:
|
||||
ASTDumper() : DeclPrinter() {}
|
||||
|
||||
void Initialize(ASTContext &Context) {
|
||||
SM = &Context.getSourceManager();
|
||||
}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
PrintFunctionDeclStart(FD);
|
||||
|
||||
if (FD->getBody()) {
|
||||
Out << '\n';
|
||||
// FIXME: convert dumper to use std::ostream?
|
||||
FD->getBody()->dumpAll(*SM);
|
||||
Out << '\n';
|
||||
}
|
||||
} else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
|
||||
PrintTypeDefDecl(TD);
|
||||
} else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) {
|
||||
Out << "Read top-level variable decl: '" << SD->getName() << "'\n";
|
||||
} else if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(D)) {
|
||||
Out << "Read objc interface '" << OID->getName() << "'\n";
|
||||
} else if (ObjCProtocolDecl *OPD = dyn_cast<ObjCProtocolDecl>(D)) {
|
||||
Out << "Read objc protocol '" << OPD->getName() << "'\n";
|
||||
} else if (ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(D)) {
|
||||
Out << "Read objc category '" << OCD->getName() << "'\n";
|
||||
} else if (isa<ObjCForwardProtocolDecl>(D)) {
|
||||
Out << "Read objc fwd protocol decl\n";
|
||||
} else if (isa<ObjCClassDecl>(D)) {
|
||||
Out << "Read objc fwd class decl\n";
|
||||
} else {
|
||||
assert(0 && "Unknown decl type!");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ASTConsumer *clang::CreateASTDumper() { return new ASTDumper(); }
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// ASTViewer - AST Visualization
|
||||
|
||||
namespace {
|
||||
class ASTViewer : public ASTConsumer {
|
||||
SourceManager *SM;
|
||||
public:
|
||||
void Initialize(ASTContext &Context) {
|
||||
SM = &Context.getSourceManager();
|
||||
}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
DeclPrinter().PrintFunctionDeclStart(FD);
|
||||
|
||||
if (FD->getBody()) {
|
||||
llvm::cerr << '\n';
|
||||
FD->getBody()->viewAST();
|
||||
llvm::cerr << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); }
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CFGVisitor & VisitCFGs - Boilerplate interface and logic to visit
|
||||
// the CFGs for all function definitions.
|
||||
|
||||
namespace {
|
||||
|
||||
class CFGVisitor : public ASTConsumer {
|
||||
public:
|
||||
// CFG Visitor interface to be implemented by subclass.
|
||||
virtual void VisitCFG(CFG& C) = 0;
|
||||
virtual bool printFuncDeclStart() { return true; }
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D);
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
void CFGVisitor::HandleTopLevelDecl(Decl *D) {
|
||||
FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
|
||||
if (!FD || !FD->getBody())
|
||||
return;
|
||||
|
||||
if (printFuncDeclStart()) {
|
||||
DeclPrinter().PrintFunctionDeclStart(FD);
|
||||
llvm::cerr << '\n';
|
||||
}
|
||||
|
||||
CFG *C = CFG::buildCFG(FD->getBody());
|
||||
VisitCFG(*C);
|
||||
delete C;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DumpCFGs - Dump CFGs to stderr or visualize with Graphviz
|
||||
|
||||
namespace {
|
||||
class CFGDumper : public CFGVisitor {
|
||||
const bool UseGraphviz;
|
||||
public:
|
||||
CFGDumper(bool use_graphviz) : UseGraphviz(use_graphviz) {}
|
||||
|
||||
virtual void VisitCFG(CFG &C) {
|
||||
if (UseGraphviz)
|
||||
C.viewCFG();
|
||||
else
|
||||
C.dump();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer *clang::CreateCFGDumper(bool ViewGraphs) {
|
||||
return new CFGDumper(ViewGraphs);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AnalyzeLiveVariables - perform live variable analysis and dump results
|
||||
|
||||
namespace {
|
||||
class LivenessVisitor : public CFGVisitor {
|
||||
SourceManager *SM;
|
||||
public:
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
SM = &Context.getSourceManager();
|
||||
}
|
||||
|
||||
virtual void VisitCFG(CFG& C) {
|
||||
LiveVariables L(C);
|
||||
L.runOnCFG(C);
|
||||
L.dumpBlockLiveness(*SM);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer *clang::CreateLiveVarAnalyzer() {
|
||||
return new LivenessVisitor();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DeadStores - run checker to locate dead stores in a function
|
||||
|
||||
namespace {
|
||||
class DeadStoreVisitor : public CFGVisitor {
|
||||
Diagnostic &Diags;
|
||||
ASTContext *Ctx;
|
||||
public:
|
||||
DeadStoreVisitor(Diagnostic &diags) : Diags(diags) {}
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
Ctx = &Context;
|
||||
}
|
||||
|
||||
virtual void VisitCFG(CFG& C) { CheckDeadStores(C, *Ctx, Diags); }
|
||||
virtual bool printFuncDeclStart() { return false; }
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer *clang::CreateDeadStoreChecker(Diagnostic &Diags) {
|
||||
return new DeadStoreVisitor(Diags);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Unitialized Values - run checker to flag potential uses of uninitalized
|
||||
// variables.
|
||||
|
||||
namespace {
|
||||
class UninitValsVisitor : public CFGVisitor {
|
||||
Diagnostic &Diags;
|
||||
ASTContext *Ctx;
|
||||
public:
|
||||
UninitValsVisitor(Diagnostic &diags) : Diags(diags) {}
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
Ctx = &Context;
|
||||
}
|
||||
|
||||
virtual void VisitCFG(CFG& C) { CheckUninitializedValues(C, *Ctx, Diags); }
|
||||
virtual bool printFuncDeclStart() { return false; }
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer *clang::CreateUnitValsChecker(Diagnostic &Diags) {
|
||||
return new UninitValsVisitor(Diags);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GRConstants - Perform intra-procedural, path-sensitive constant propagation.
|
||||
|
||||
namespace {
|
||||
class GRConstantsVisitor : public CFGVisitor {
|
||||
public:
|
||||
virtual void Initialize(ASTContext &Context) {}
|
||||
|
||||
virtual void VisitCFG(CFG& C) {
|
||||
RunGRConstants(C);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer *clang::CreateGRConstants() {
|
||||
return new GRConstantsVisitor();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LLVM Emitter
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/CodeGen/ModuleBuilder.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
|
||||
namespace {
|
||||
class CodeGenerator : public ASTConsumer {
|
||||
Diagnostic &Diags;
|
||||
const llvm::TargetData *TD;
|
||||
ASTContext *Ctx;
|
||||
const LangOptions &Features;
|
||||
protected:
|
||||
llvm::Module *M;
|
||||
CodeGen::CodeGenModule *Builder;
|
||||
public:
|
||||
CodeGenerator(Diagnostic &diags, const LangOptions &LO)
|
||||
: Diags(diags)
|
||||
, Features(LO) {}
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
Ctx = &Context;
|
||||
M = new llvm::Module("foo");
|
||||
M->setTargetTriple(Ctx->Target.getTargetTriple());
|
||||
M->setDataLayout(Ctx->Target.getTargetDescription());
|
||||
TD = new llvm::TargetData(Ctx->Target.getTargetDescription());
|
||||
Builder = CodeGen::Init(Context, Features, *M, *TD, Diags);
|
||||
}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
// If an error occurred, stop code generation, but continue parsing and
|
||||
// semantic analysis (to ensure all warnings and errors are emitted).
|
||||
if (Diags.hasErrorOccurred())
|
||||
return;
|
||||
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
CodeGen::CodeGenFunction(Builder, FD);
|
||||
} else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
|
||||
CodeGen::CodeGenGlobalVar(Builder, FVD);
|
||||
} else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
|
||||
CodeGen::CodeGenLinkageSpec(Builder, LSD);
|
||||
} else {
|
||||
assert(isa<TypeDecl>(D) && "Only expected type decls here");
|
||||
// don't codegen for now, eventually pass down for debug info.
|
||||
//std::cerr << "Read top-level typedef decl: '"
|
||||
// << D->getName() << "'\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
class LLVMEmitter : public CodeGenerator {
|
||||
public:
|
||||
LLVMEmitter(Diagnostic &diags, const LangOptions &LO)
|
||||
: CodeGenerator(diags,LO) {}
|
||||
|
||||
~LLVMEmitter() {
|
||||
CodeGen::Terminate(Builder);
|
||||
|
||||
// Print the generated code.
|
||||
M->print(llvm::cout.stream());
|
||||
delete M;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ASTConsumer *clang::CreateLLVMEmitter(Diagnostic &Diags,
|
||||
const LangOptions &Features) {
|
||||
return new LLVMEmitter(Diags, Features);
|
||||
}
|
||||
|
||||
namespace {
|
||||
class BCWriter : public CodeGenerator {
|
||||
public:
|
||||
std::ostream& Out;
|
||||
|
||||
BCWriter(std::ostream* out, Diagnostic &diags, const LangOptions &LO)
|
||||
: CodeGenerator(diags,LO)
|
||||
, Out(*out) {}
|
||||
|
||||
~BCWriter() {
|
||||
CodeGen::Terminate(Builder);
|
||||
llvm::WriteBitcodeToFile(M, Out);
|
||||
delete M;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ASTConsumer *clang::CreateBCWriter(const std::string& InFile,
|
||||
const std::string& OutputFile,
|
||||
Diagnostic &Diags,
|
||||
const LangOptions &Features) {
|
||||
std::string FileName = OutputFile;
|
||||
|
||||
std::ostream *Out;
|
||||
if (OutputFile == "-")
|
||||
Out = llvm::cout.stream();
|
||||
else if (!OutputFile.size()) {
|
||||
if (InFile == "-")
|
||||
Out = llvm::cout.stream();
|
||||
else {
|
||||
llvm::sys::Path Path(InFile);
|
||||
Path.eraseSuffix();
|
||||
Path.appendSuffix("bc");
|
||||
FileName = Path.toString();
|
||||
Out = new std::ofstream(FileName.c_str(),
|
||||
std::ios_base::binary|std::ios_base::out);
|
||||
}
|
||||
} else {
|
||||
Out = new std::ofstream(FileName.c_str(),
|
||||
std::ios_base::binary|std::ios_base::out);
|
||||
}
|
||||
|
||||
return new BCWriter(Out, Diags, Features);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AST Serializer
|
||||
|
||||
namespace {
|
||||
|
||||
class ASTSerializer : public ASTConsumer {
|
||||
protected:
|
||||
Diagnostic &Diags;
|
||||
TranslationUnit TU;
|
||||
public:
|
||||
ASTSerializer(Diagnostic& diags, const LangOptions& LO)
|
||||
: Diags(diags), TU(LO) {}
|
||||
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
TU.setContext(&Context);
|
||||
}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
if (Diags.hasErrorOccurred())
|
||||
return;
|
||||
|
||||
TU.AddTopLevelDecl(D);
|
||||
}
|
||||
};
|
||||
|
||||
class SingleFileSerializer : public ASTSerializer {
|
||||
const llvm::sys::Path FName;
|
||||
public:
|
||||
SingleFileSerializer(const llvm::sys::Path& F, Diagnostic &diags,
|
||||
const LangOptions &LO)
|
||||
: ASTSerializer(diags,LO), FName(F) {}
|
||||
|
||||
~SingleFileSerializer() {
|
||||
EmitASTBitcodeFile(TU,FName);
|
||||
}
|
||||
};
|
||||
|
||||
class BuildSerializer : public ASTSerializer {
|
||||
llvm::sys::Path EmitDir;
|
||||
public:
|
||||
BuildSerializer(const llvm::sys::Path& dir, Diagnostic &diags,
|
||||
const LangOptions &LO)
|
||||
: ASTSerializer(diags,LO), EmitDir(dir) {}
|
||||
|
||||
~BuildSerializer() {
|
||||
SourceManager& SourceMgr = TU.getASTContext()->getSourceManager();
|
||||
unsigned ID = SourceMgr.getMainFileID();
|
||||
assert (ID && "MainFileID not set!");
|
||||
const FileEntry* FE = SourceMgr.getFileEntryForID(ID);
|
||||
assert (FE && "No FileEntry for main file.");
|
||||
|
||||
// FIXME: This is not portable to Windows.
|
||||
// FIXME: This logic should probably be moved elsewhere later.
|
||||
|
||||
llvm::sys::Path FName(EmitDir);
|
||||
|
||||
std::vector<char> buf;
|
||||
buf.reserve(strlen(FE->getName())+100);
|
||||
|
||||
sprintf(&buf[0], "dev_%llx", (uint64_t) FE->getDevice());
|
||||
FName.appendComponent(&buf[0]);
|
||||
FName.createDirectoryOnDisk(true);
|
||||
if (!FName.canWrite() || !FName.isDirectory()) {
|
||||
assert (false && "Could not create 'device' serialization directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(&buf[0], "%s-%llX.ast", FE->getName(), (uint64_t) FE->getInode());
|
||||
FName.appendComponent(&buf[0]);
|
||||
EmitASTBitcodeFile(TU,FName);
|
||||
|
||||
// Now emit the sources.
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
ASTConsumer* clang::CreateASTSerializer(const std::string& InFile,
|
||||
const std::string& OutputFile,
|
||||
Diagnostic &Diags,
|
||||
const LangOptions &Features) {
|
||||
|
||||
if (OutputFile.size()) {
|
||||
if (InFile == "-") {
|
||||
llvm::cerr <<
|
||||
"error: Cannot use --serialize with -o for source read from STDIN.\n";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The user specified an AST-emission directory. Determine if the path
|
||||
// is absolute.
|
||||
llvm::sys::Path EmitDir(OutputFile);
|
||||
|
||||
if (!EmitDir.isAbsolute()) {
|
||||
llvm::cerr <<
|
||||
"error: Output directory for --serialize must be an absolute path.\n";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create the directory if it does not exist.
|
||||
EmitDir.createDirectoryOnDisk(true);
|
||||
if (!EmitDir.canWrite() || !EmitDir.isDirectory()) {
|
||||
llvm::cerr <<
|
||||
"error: Could not create output directory for --serialize.\n";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// FIXME: We should probably only allow using BuildSerializer when
|
||||
// the ASTs come from parsed source files, and not from .ast files.
|
||||
return new BuildSerializer(EmitDir, Diags, Features);
|
||||
}
|
||||
|
||||
// The user did not specify an output directory for serialized ASTs.
|
||||
// Serialize the translation to a single file whose name is the same
|
||||
// as the input file with the ".ast" extension appended.
|
||||
|
||||
llvm::sys::Path FName(InFile.c_str());
|
||||
FName.appendSuffix("ast");
|
||||
return new SingleFileSerializer(FName, Diags, Features);
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
//===--- ASTConsumers.h - ASTConsumer implementations -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// AST Consumers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef DRIVER_ASTCONSUMERS_H
|
||||
#define DRIVER_ASTCONSUMERS_H
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
namespace llvm { namespace sys { class Path; }}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTConsumer;
|
||||
class Diagnostic;
|
||||
class FileManager;
|
||||
struct LangOptions;
|
||||
|
||||
ASTConsumer *CreateASTPrinter(std::ostream* OS = NULL);
|
||||
|
||||
ASTConsumer *CreateASTDumper();
|
||||
|
||||
ASTConsumer *CreateASTViewer();
|
||||
|
||||
ASTConsumer *CreateCFGDumper(bool ViewGraphs = false);
|
||||
|
||||
ASTConsumer *CreateLiveVarAnalyzer();
|
||||
|
||||
ASTConsumer *CreateDeadStoreChecker(Diagnostic &Diags);
|
||||
|
||||
ASTConsumer *CreateUnitValsChecker(Diagnostic &Diags);
|
||||
|
||||
ASTConsumer *CreateGRConstants();
|
||||
|
||||
ASTConsumer *CreateLLVMEmitter(Diagnostic &Diags, const LangOptions &Features);
|
||||
|
||||
ASTConsumer *CreateBCWriter(const std::string& InFile,
|
||||
const std::string& OutFile,
|
||||
Diagnostic &Diags,
|
||||
const LangOptions &LOpts);
|
||||
|
||||
ASTConsumer *CreateCodeRewriterTest(Diagnostic &Diags);
|
||||
|
||||
ASTConsumer *CreateSerializationTest(Diagnostic &Diags,
|
||||
FileManager& FMgr,
|
||||
const LangOptions &LOpts);
|
||||
|
||||
ASTConsumer *CreateASTSerializer(const std::string& InFile,
|
||||
const std::string& EmitDir,
|
||||
Diagnostic &Diags,
|
||||
const LangOptions &LOpts);
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,239 +0,0 @@
|
||||
//===--- DiagChecker.cpp - Diagnostic Checking Functions ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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 "ASTConsumers.h"
|
||||
#include "TextDiagnosticBuffer.h"
|
||||
#include "clang/Sema/ASTStreamer.h"
|
||||
#include "clang/AST/ASTConsumer.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 = 0;
|
||||
|
||||
for (;;) {
|
||||
ColNo = Comment.find(ExpectedStr, ColNo);
|
||||
if (ColNo == std::string::npos) break;
|
||||
|
||||
size_type OpenDiag = Comment.find("{{", ColNo);
|
||||
|
||||
if (OpenDiag == std::string::npos) {
|
||||
fprintf(stderr,
|
||||
"oops:%d: Cannot find beginning of expected error string\n",
|
||||
SourceMgr.getLogicalLineNumber(Pos));
|
||||
break;
|
||||
}
|
||||
|
||||
OpenDiag += 2;
|
||||
size_type CloseDiag = Comment.find("}}", OpenDiag);
|
||||
|
||||
if (CloseDiag == std::string::npos) {
|
||||
fprintf(stderr,
|
||||
"oops:%d: Cannot find end of expected error string\n",
|
||||
SourceMgr.getLogicalLineNumber(Pos));
|
||||
break;
|
||||
}
|
||||
|
||||
std::string Msg(Comment.substr(OpenDiag, CloseDiag - OpenDiag));
|
||||
ExpectedDiags.push_back(std::make_pair(Pos, Msg));
|
||||
ColNo = CloseDiag + 2;
|
||||
}
|
||||
}
|
||||
|
||||
/// FindExpectedDiags - Lex the main source file to find all of the
|
||||
// expected errors and warnings.
|
||||
static void FindExpectedDiags(Preprocessor &PP,
|
||||
DiagList &ExpectedErrors,
|
||||
DiagList &ExpectedWarnings) {
|
||||
// Return comments as tokens, this is how we find expected diagnostics.
|
||||
PP.SetCommentRetentionState(true, true);
|
||||
|
||||
// Enter the cave.
|
||||
PP.EnterMainSourceFile();
|
||||
|
||||
// Turn off all warnings from relexing or preprocessing.
|
||||
PP.getDiagnostics().setWarnOnExtensions(false);
|
||||
PP.getDiagnostics().setErrorOnExtensions(false);
|
||||
for (unsigned i = 0; i != diag::NUM_BUILTIN_DIAGNOSTICS; ++i)
|
||||
if (PP.getDiagnostics().isBuiltinNoteWarningOrExtension((diag::kind)i))
|
||||
PP.getDiagnostics().setDiagnosticMapping((diag::kind)i, diag::MAP_IGNORE);
|
||||
|
||||
Token Tok;
|
||||
do {
|
||||
PP.Lex(Tok);
|
||||
|
||||
if (Tok.is(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.isNot(tok::eof));
|
||||
|
||||
PP.SetCommentRetentionState(false, false);
|
||||
}
|
||||
|
||||
/// PrintProblem - This takes a diagnostic map of the delta between expected and
|
||||
/// seen diagnostics. If there's anything in it, then something unexpected
|
||||
/// happened. Print the map out in a nice format and return "true". If the map
|
||||
/// is empty and we're not going to print things, then return "false".
|
||||
///
|
||||
static bool PrintProblem(SourceManager &SourceMgr,
|
||||
const_diag_iterator diag_begin,
|
||||
const_diag_iterator diag_end,
|
||||
const char *Msg) {
|
||||
if (diag_begin == diag_end) return false;
|
||||
|
||||
fprintf(stderr, "%s\n", Msg);
|
||||
|
||||
for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I)
|
||||
fprintf(stderr, " Line %d: %s\n",
|
||||
SourceMgr.getLogicalLineNumber(I->first),
|
||||
I->second.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// CompareDiagLists - Compare two diangnostic lists and return the difference
|
||||
/// between them.
|
||||
///
|
||||
static bool CompareDiagLists(SourceManager &SourceMgr,
|
||||
const_diag_iterator d1_begin,
|
||||
const_diag_iterator d1_end,
|
||||
const_diag_iterator d2_begin,
|
||||
const_diag_iterator d2_end,
|
||||
const char *Msg) {
|
||||
DiagList DiffList;
|
||||
|
||||
for (const_diag_iterator I = d1_begin, E = d1_end; I != E; ++I) {
|
||||
unsigned LineNo1 = SourceMgr.getLogicalLineNumber(I->first);
|
||||
const std::string &Diag1 = I->second;
|
||||
bool Found = false;
|
||||
|
||||
for (const_diag_iterator II = d2_begin, IE = d2_end; II != IE; ++II) {
|
||||
unsigned LineNo2 = SourceMgr.getLogicalLineNumber(II->first);
|
||||
if (LineNo1 != LineNo2) continue;
|
||||
|
||||
const std::string &Diag2 = II->second;
|
||||
if (Diag2.find(Diag1) != std::string::npos ||
|
||||
Diag1.find(Diag2) != std::string::npos) {
|
||||
Found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Found)
|
||||
DiffList.push_back(std::make_pair(I->first, Diag1));
|
||||
}
|
||||
|
||||
return PrintProblem(SourceMgr, DiffList.begin(), DiffList.end(), Msg);
|
||||
}
|
||||
|
||||
/// CheckResults - This compares the expected results to those that
|
||||
/// were actually reported. It emits any discrepencies. Return "true" if there
|
||||
/// were problems. Return "false" otherwise.
|
||||
///
|
||||
static bool CheckResults(Preprocessor &PP,
|
||||
const DiagList &ExpectedErrors,
|
||||
const DiagList &ExpectedWarnings) {
|
||||
const TextDiagnosticBuffer &Diags =
|
||||
static_cast<const TextDiagnosticBuffer&>(PP.getDiagnostics().getClient());
|
||||
SourceManager &SourceMgr = PP.getSourceManager();
|
||||
|
||||
// We want to capture the delta between what was expected and what was
|
||||
// seen.
|
||||
//
|
||||
// Expected \ Seen - set expected but not seen
|
||||
// Seen \ Expected - set seen but not expected
|
||||
bool HadProblem = false;
|
||||
|
||||
// See if there were errors that were expected but not seen.
|
||||
HadProblem |= CompareDiagLists(SourceMgr,
|
||||
ExpectedErrors.begin(), ExpectedErrors.end(),
|
||||
Diags.err_begin(), Diags.err_end(),
|
||||
"Errors expected but not seen:");
|
||||
|
||||
// See if there were errors that were seen but not expected.
|
||||
HadProblem |= CompareDiagLists(SourceMgr,
|
||||
Diags.err_begin(), Diags.err_end(),
|
||||
ExpectedErrors.begin(), ExpectedErrors.end(),
|
||||
"Errors seen but not expected:");
|
||||
|
||||
// See if there were warnings that were expected but not seen.
|
||||
HadProblem |= CompareDiagLists(SourceMgr,
|
||||
ExpectedWarnings.begin(),
|
||||
ExpectedWarnings.end(),
|
||||
Diags.warn_begin(), Diags.warn_end(),
|
||||
"Warnings expected but not seen:");
|
||||
|
||||
// See if there were warnings that were seen but not expected.
|
||||
HadProblem |= CompareDiagLists(SourceMgr,
|
||||
Diags.warn_begin(), Diags.warn_end(),
|
||||
ExpectedWarnings.begin(),
|
||||
ExpectedWarnings.end(),
|
||||
"Warnings seen but not expected:");
|
||||
|
||||
return HadProblem;
|
||||
}
|
||||
|
||||
|
||||
/// CheckASTConsumer - Implement diagnostic checking for AST consumers.
|
||||
bool clang::CheckASTConsumer(Preprocessor &PP, ASTConsumer* C) {
|
||||
|
||||
// Parse the AST and run the consumer, ultimately deleting C.
|
||||
ParseAST(PP, C);
|
||||
|
||||
// Gather the set of expected diagnostics.
|
||||
DiagList ExpectedErrors, ExpectedWarnings;
|
||||
FindExpectedDiags(PP, ExpectedErrors, ExpectedWarnings);
|
||||
|
||||
// Check that the expected diagnostics occurred.
|
||||
return CheckResults(PP, ExpectedErrors, ExpectedWarnings);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
LEVEL = ../../..
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
||||
CXXFLAGS = -fno-rtti
|
||||
|
||||
TOOLNAME = clang
|
||||
USEDLIBS = clangCodeGen.a clangAnalysis.a clangRewrite.a clangSEMA.a \
|
||||
clangAST.a clangParse.a clangLex.a clangBasic.a \
|
||||
LLVMCore.a LLVMSupport.a LLVMSystem.a \
|
||||
LLVMBitWriter.a LLVMBitReader.a LLVMTarget.a
|
||||
|
||||
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
@@ -1,57 +0,0 @@
|
||||
//===--- PrintParserActions.cpp - Implement -parse-print-callbacks mode ---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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/Parse/Action.h"
|
||||
#include "clang/Parse/DeclSpec.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
class ParserPrintActions : public MinimalAction {
|
||||
|
||||
public:
|
||||
ParserPrintActions(IdentifierTable &IT) : MinimalAction(IT) {}
|
||||
|
||||
/// ActOnDeclarator - 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 *ActOnDeclarator(Scope *S, Declarator &D,
|
||||
DeclTy *LastInGroup) {
|
||||
llvm::cout << "ActOnDeclarator ";
|
||||
if (IdentifierInfo *II = D.getIdentifier()) {
|
||||
llvm::cout << "'" << II->getName() << "'";
|
||||
} else {
|
||||
llvm::cout << "<anon>";
|
||||
}
|
||||
llvm::cout << "\n";
|
||||
|
||||
// Pass up to EmptyActions so that the symbol table is maintained right.
|
||||
return MinimalAction::ActOnDeclarator(S, D, LastInGroup);
|
||||
}
|
||||
|
||||
/// ActOnPopScope - This callback is called immediately before the specified
|
||||
/// scope is popped and deleted.
|
||||
virtual void ActOnPopScope(SourceLocation Loc, Scope *S) {
|
||||
llvm::cout << "ActOnPopScope\n";
|
||||
|
||||
// Pass up to EmptyActions so that the symbol table is maintained right.
|
||||
MinimalAction::ActOnPopScope(Loc, S);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
MinimalAction *clang::CreatePrintParserActionsAction(IdentifierTable &IT) {
|
||||
return new ParserPrintActions(IT);
|
||||
}
|
||||
@@ -1,640 +0,0 @@
|
||||
//===--- PrintPreprocessedOutput.cpp - Implement the -E mode --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This code simply runs the preprocessor on the input file and prints out the
|
||||
// result. This is the traditional behavior of the -E option.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang.h"
|
||||
#include "clang/Lex/PPCallbacks.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/Pragma.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include <cstdio>
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Simple buffered I/O
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Empirically, iostream is over 30% slower than stdio for this workload, and
|
||||
// stdio itself isn't very well suited. The problem with stdio is use of
|
||||
// putchar_unlocked. We have many newline characters that need to be emitted,
|
||||
// but stdio needs to do extra checks to handle line buffering mode. These
|
||||
// extra checks make putchar_unlocked fall off its inlined code path, hitting
|
||||
// slow system code. In practice, using 'write' directly makes 'clang -E -P'
|
||||
// about 10% faster than using the stdio path on darwin.
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#define USE_STDIO 1
|
||||
#endif
|
||||
|
||||
static char *OutBufStart = 0, *OutBufEnd, *OutBufCur;
|
||||
|
||||
/// InitOutputBuffer - Initialize our output buffer.
|
||||
///
|
||||
static void InitOutputBuffer() {
|
||||
#ifndef USE_STDIO
|
||||
OutBufStart = new char[64*1024];
|
||||
OutBufEnd = OutBufStart+64*1024;
|
||||
OutBufCur = OutBufStart;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// FlushBuffer - Write the accumulated bytes to the output stream.
|
||||
///
|
||||
static void FlushBuffer() {
|
||||
#ifndef USE_STDIO
|
||||
write(STDOUT_FILENO, OutBufStart, OutBufCur-OutBufStart);
|
||||
OutBufCur = OutBufStart;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// CleanupOutputBuffer - Finish up output.
|
||||
///
|
||||
static void CleanupOutputBuffer() {
|
||||
#ifndef USE_STDIO
|
||||
FlushBuffer();
|
||||
delete [] OutBufStart;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void OutputChar(char c) {
|
||||
#if defined(_MSC_VER)
|
||||
putchar(c);
|
||||
#elif defined(USE_STDIO)
|
||||
putchar_unlocked(c);
|
||||
#else
|
||||
if (OutBufCur >= OutBufEnd)
|
||||
FlushBuffer();
|
||||
*OutBufCur++ = c;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void OutputString(const char *Ptr, unsigned Size) {
|
||||
#ifdef USE_STDIO
|
||||
fwrite(Ptr, Size, 1, stdout);
|
||||
#else
|
||||
if (OutBufCur+Size >= OutBufEnd)
|
||||
FlushBuffer();
|
||||
|
||||
switch (Size) {
|
||||
default:
|
||||
memcpy(OutBufCur, Ptr, Size);
|
||||
break;
|
||||
case 3:
|
||||
OutBufCur[2] = Ptr[2];
|
||||
case 2:
|
||||
OutBufCur[1] = Ptr[1];
|
||||
case 1:
|
||||
OutBufCur[0] = Ptr[0];
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
OutBufCur += Size;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Preprocessed token printer
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static llvm::cl::opt<bool>
|
||||
DisableLineMarkers("P", llvm::cl::desc("Disable linemarker output in -E mode"));
|
||||
static llvm::cl::opt<bool>
|
||||
EnableCommentOutput("C", llvm::cl::desc("Enable comment output in -E mode"));
|
||||
static llvm::cl::opt<bool>
|
||||
EnableMacroCommentOutput("CC",
|
||||
llvm::cl::desc("Enable comment output in -E mode, "
|
||||
"even from macro expansions"));
|
||||
|
||||
namespace {
|
||||
class PrintPPOutputPPCallbacks : public PPCallbacks {
|
||||
Preprocessor &PP;
|
||||
unsigned CurLine;
|
||||
bool EmittedTokensOnThisLine;
|
||||
DirectoryLookup::DirType FileType;
|
||||
llvm::SmallString<512> CurFilename;
|
||||
public:
|
||||
PrintPPOutputPPCallbacks(Preprocessor &pp) : PP(pp) {
|
||||
CurLine = 0;
|
||||
CurFilename += "<uninit>";
|
||||
EmittedTokensOnThisLine = false;
|
||||
FileType = DirectoryLookup::NormalHeaderDir;
|
||||
}
|
||||
|
||||
void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
|
||||
bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; }
|
||||
|
||||
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
|
||||
DirectoryLookup::DirType FileType);
|
||||
virtual void Ident(SourceLocation Loc, const std::string &str);
|
||||
|
||||
|
||||
bool HandleFirstTokOnLine(Token &Tok);
|
||||
bool MoveToLine(SourceLocation Loc);
|
||||
bool AvoidConcat(const Token &PrevTok, const Token &Tok);
|
||||
};
|
||||
}
|
||||
|
||||
/// UToStr - Do itoa on the specified number, in-place in the specified buffer.
|
||||
/// endptr points to the end of the buffer.
|
||||
static char *UToStr(unsigned N, char *EndPtr) {
|
||||
// Null terminate the buffer.
|
||||
*--EndPtr = '\0';
|
||||
if (N == 0) // Zero is a special case.
|
||||
*--EndPtr = '0';
|
||||
while (N) {
|
||||
*--EndPtr = '0' + char(N % 10);
|
||||
N /= 10;
|
||||
}
|
||||
return EndPtr;
|
||||
}
|
||||
|
||||
|
||||
/// MoveToLine - Move the output to the source line specified by the location
|
||||
/// object. We can do this by emitting some number of \n's, or be emitting a
|
||||
/// #line directive. This returns false if already at the specified line, true
|
||||
/// if some newlines were emitted.
|
||||
bool PrintPPOutputPPCallbacks::MoveToLine(SourceLocation Loc) {
|
||||
if (DisableLineMarkers) {
|
||||
unsigned LineNo = PP.getSourceManager().getLogicalLineNumber(Loc);
|
||||
if (LineNo == CurLine) return false;
|
||||
|
||||
CurLine = LineNo;
|
||||
|
||||
if (!EmittedTokensOnThisLine)
|
||||
return true;
|
||||
|
||||
OutputChar('\n');
|
||||
EmittedTokensOnThisLine = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned LineNo = PP.getSourceManager().getLogicalLineNumber(Loc);
|
||||
|
||||
// If this line is "close enough" to the original line, just print newlines,
|
||||
// otherwise print a #line directive.
|
||||
if (LineNo-CurLine < 8) {
|
||||
if (LineNo-CurLine == 1)
|
||||
OutputChar('\n');
|
||||
else if (LineNo == CurLine)
|
||||
return false; // Phys line moved, but logical line didn't.
|
||||
else {
|
||||
const char *NewLines = "\n\n\n\n\n\n\n\n";
|
||||
OutputString(NewLines, LineNo-CurLine);
|
||||
}
|
||||
CurLine = LineNo;
|
||||
} else {
|
||||
if (EmittedTokensOnThisLine) {
|
||||
OutputChar('\n');
|
||||
EmittedTokensOnThisLine = false;
|
||||
}
|
||||
|
||||
CurLine = LineNo;
|
||||
|
||||
OutputChar('#');
|
||||
OutputChar(' ');
|
||||
char NumberBuffer[20];
|
||||
const char *NumStr = UToStr(LineNo, NumberBuffer+20);
|
||||
OutputString(NumStr, (NumberBuffer+20)-NumStr-1);
|
||||
OutputChar(' ');
|
||||
OutputChar('"');
|
||||
OutputString(&CurFilename[0], CurFilename.size());
|
||||
OutputChar('"');
|
||||
|
||||
if (FileType == DirectoryLookup::SystemHeaderDir)
|
||||
OutputString(" 3", 2);
|
||||
else if (FileType == DirectoryLookup::ExternCSystemHeaderDir)
|
||||
OutputString(" 3 4", 4);
|
||||
OutputChar('\n');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// 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) {
|
||||
// Unless we are exiting a #include, make sure to skip ahead to the line the
|
||||
// #include directive was at.
|
||||
SourceManager &SourceMgr = PP.getSourceManager();
|
||||
if (Reason == PPCallbacks::EnterFile) {
|
||||
MoveToLine(SourceMgr.getIncludeLoc(Loc));
|
||||
} else if (Reason == PPCallbacks::SystemHeaderPragma) {
|
||||
MoveToLine(Loc);
|
||||
|
||||
// TODO GCC emits the # directive for this directive on the line AFTER the
|
||||
// directive and emits a bunch of spaces that aren't needed. Emulate this
|
||||
// strange behavior.
|
||||
}
|
||||
|
||||
Loc = SourceMgr.getLogicalLoc(Loc);
|
||||
CurLine = SourceMgr.getLineNumber(Loc);
|
||||
|
||||
if (DisableLineMarkers) return;
|
||||
|
||||
CurFilename.clear();
|
||||
CurFilename += SourceMgr.getSourceName(Loc);
|
||||
Lexer::Stringify(CurFilename);
|
||||
FileType = FileType;
|
||||
|
||||
if (EmittedTokensOnThisLine) {
|
||||
OutputChar('\n');
|
||||
EmittedTokensOnThisLine = false;
|
||||
}
|
||||
|
||||
OutputChar('#');
|
||||
OutputChar(' ');
|
||||
|
||||
char NumberBuffer[20];
|
||||
const char *NumStr = UToStr(CurLine, NumberBuffer+20);
|
||||
OutputString(NumStr, (NumberBuffer+20)-NumStr-1);
|
||||
OutputChar(' ');
|
||||
OutputChar('"');
|
||||
OutputString(&CurFilename[0], CurFilename.size());
|
||||
OutputChar('"');
|
||||
|
||||
switch (Reason) {
|
||||
case PPCallbacks::EnterFile:
|
||||
OutputString(" 1", 2);
|
||||
break;
|
||||
case PPCallbacks::ExitFile:
|
||||
OutputString(" 2", 2);
|
||||
break;
|
||||
case PPCallbacks::SystemHeaderPragma: break;
|
||||
case PPCallbacks::RenameFile: break;
|
||||
}
|
||||
|
||||
if (FileType == DirectoryLookup::SystemHeaderDir)
|
||||
OutputString(" 3", 2);
|
||||
else if (FileType == DirectoryLookup::ExternCSystemHeaderDir)
|
||||
OutputString(" 3 4", 4);
|
||||
|
||||
OutputChar('\n');
|
||||
}
|
||||
|
||||
/// HandleIdent - Handle #ident directives when read by the preprocessor.
|
||||
///
|
||||
void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
|
||||
MoveToLine(Loc);
|
||||
|
||||
OutputString("#ident ", strlen("#ident "));
|
||||
OutputString(&S[0], S.size());
|
||||
EmittedTokensOnThisLine = true;
|
||||
}
|
||||
|
||||
/// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this
|
||||
/// is called for the first token on each new line. If this really is the start
|
||||
/// of a new logical line, handle it and return true, otherwise return false.
|
||||
/// This may not be the start of a logical line because the "start of line"
|
||||
/// marker is set for physical lines, not logical ones.
|
||||
bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
|
||||
// Figure out what line we went to and insert the appropriate number of
|
||||
// newline characters.
|
||||
if (!MoveToLine(Tok.getLocation()))
|
||||
return false;
|
||||
|
||||
// Print out space characters so that the first token on a line is
|
||||
// indented for easy reading.
|
||||
const SourceManager &SourceMgr = PP.getSourceManager();
|
||||
unsigned ColNo = SourceMgr.getLogicalColumnNumber(Tok.getLocation());
|
||||
|
||||
// This hack prevents stuff like:
|
||||
// #define HASH #
|
||||
// HASH define foo bar
|
||||
// From having the # character end up at column 1, which makes it so it
|
||||
// is not handled as a #define next time through the preprocessor if in
|
||||
// -fpreprocessed mode.
|
||||
if (ColNo <= 1 && Tok.is(tok::hash))
|
||||
OutputChar(' ');
|
||||
|
||||
// Otherwise, indent the appropriate number of spaces.
|
||||
for (; ColNo > 1; --ColNo)
|
||||
OutputChar(' ');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct UnknownPragmaHandler : public PragmaHandler {
|
||||
const char *Prefix;
|
||||
PrintPPOutputPPCallbacks *Callbacks;
|
||||
|
||||
UnknownPragmaHandler(const char *prefix, PrintPPOutputPPCallbacks *callbacks)
|
||||
: PragmaHandler(0), Prefix(prefix), Callbacks(callbacks) {}
|
||||
virtual void HandlePragma(Preprocessor &PP, Token &PragmaTok) {
|
||||
// Figure out what line we went to and insert the appropriate number of
|
||||
// newline characters.
|
||||
Callbacks->MoveToLine(PragmaTok.getLocation());
|
||||
OutputString(Prefix, strlen(Prefix));
|
||||
|
||||
// Read and print all of the pragma tokens.
|
||||
while (PragmaTok.isNot(tok::eom)) {
|
||||
if (PragmaTok.hasLeadingSpace())
|
||||
OutputChar(' ');
|
||||
std::string TokSpell = PP.getSpelling(PragmaTok);
|
||||
OutputString(&TokSpell[0], TokSpell.size());
|
||||
PP.LexUnexpandedToken(PragmaTok);
|
||||
}
|
||||
OutputChar('\n');
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
enum AvoidConcatInfo {
|
||||
/// By default, a token never needs to avoid concatenation. Most tokens (e.g.
|
||||
/// ',', ')', etc) don't cause a problem when concatenated.
|
||||
aci_never_avoid_concat = 0,
|
||||
|
||||
/// aci_custom_firstchar - AvoidConcat contains custom code to handle this
|
||||
/// token's requirements, and it needs to know the first character of the
|
||||
/// token.
|
||||
aci_custom_firstchar = 1,
|
||||
|
||||
/// aci_custom - AvoidConcat contains custom code to handle this token's
|
||||
/// requirements, but it doesn't need to know the first character of the
|
||||
/// token.
|
||||
aci_custom = 2,
|
||||
|
||||
/// aci_avoid_equal - Many tokens cannot be safely followed by an '='
|
||||
/// character. For example, "<<" turns into "<<=" when followed by an =.
|
||||
aci_avoid_equal = 4
|
||||
};
|
||||
|
||||
/// This array contains information for each token on what action to take when
|
||||
/// avoiding concatenation of tokens in the AvoidConcat method.
|
||||
static char TokenInfo[tok::NUM_TOKENS];
|
||||
|
||||
/// InitAvoidConcatTokenInfo - Tokens that must avoid concatenation should be
|
||||
/// marked by this function.
|
||||
static void InitAvoidConcatTokenInfo() {
|
||||
// These tokens have custom code in AvoidConcat.
|
||||
TokenInfo[tok::identifier ] |= aci_custom;
|
||||
TokenInfo[tok::numeric_constant] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::period ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::amp ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::plus ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::minus ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::slash ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::less ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::greater ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::pipe ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::percent ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::colon ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::hash ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::arrow ] |= aci_custom_firstchar;
|
||||
|
||||
// These tokens change behavior if followed by an '='.
|
||||
TokenInfo[tok::amp ] |= aci_avoid_equal; // &=
|
||||
TokenInfo[tok::plus ] |= aci_avoid_equal; // +=
|
||||
TokenInfo[tok::minus ] |= aci_avoid_equal; // -=
|
||||
TokenInfo[tok::slash ] |= aci_avoid_equal; // /=
|
||||
TokenInfo[tok::less ] |= aci_avoid_equal; // <=
|
||||
TokenInfo[tok::greater ] |= aci_avoid_equal; // >=
|
||||
TokenInfo[tok::pipe ] |= aci_avoid_equal; // |=
|
||||
TokenInfo[tok::percent ] |= aci_avoid_equal; // %=
|
||||
TokenInfo[tok::star ] |= aci_avoid_equal; // *=
|
||||
TokenInfo[tok::exclaim ] |= aci_avoid_equal; // !=
|
||||
TokenInfo[tok::lessless ] |= aci_avoid_equal; // <<=
|
||||
TokenInfo[tok::greaterequal] |= aci_avoid_equal; // >>=
|
||||
TokenInfo[tok::caret ] |= aci_avoid_equal; // ^=
|
||||
TokenInfo[tok::equal ] |= aci_avoid_equal; // ==
|
||||
}
|
||||
|
||||
/// StartsWithL - Return true if the spelling of this token starts with 'L'.
|
||||
static bool StartsWithL(const Token &Tok, Preprocessor &PP) {
|
||||
if (!Tok.needsCleaning()) {
|
||||
SourceManager &SrcMgr = PP.getSourceManager();
|
||||
return *SrcMgr.getCharacterData(SrcMgr.getPhysicalLoc(Tok.getLocation()))
|
||||
== 'L';
|
||||
}
|
||||
|
||||
if (Tok.getLength() < 256) {
|
||||
char Buffer[256];
|
||||
const char *TokPtr = Buffer;
|
||||
PP.getSpelling(Tok, TokPtr);
|
||||
return TokPtr[0] == 'L';
|
||||
}
|
||||
|
||||
return PP.getSpelling(Tok)[0] == 'L';
|
||||
}
|
||||
|
||||
/// IsIdentifierL - Return true if the spelling of this token is literally 'L'.
|
||||
static bool IsIdentifierL(const Token &Tok, Preprocessor &PP) {
|
||||
if (!Tok.needsCleaning()) {
|
||||
if (Tok.getLength() != 1)
|
||||
return false;
|
||||
SourceManager &SrcMgr = PP.getSourceManager();
|
||||
return *SrcMgr.getCharacterData(SrcMgr.getPhysicalLoc(Tok.getLocation()))
|
||||
== 'L';
|
||||
}
|
||||
|
||||
if (Tok.getLength() < 256) {
|
||||
char Buffer[256];
|
||||
const char *TokPtr = Buffer;
|
||||
if (PP.getSpelling(Tok, TokPtr) != 1)
|
||||
return false;
|
||||
return TokPtr[0] == 'L';
|
||||
}
|
||||
|
||||
return PP.getSpelling(Tok) == "L";
|
||||
}
|
||||
|
||||
|
||||
/// AvoidConcat - If printing PrevTok immediately followed by Tok would cause
|
||||
/// the two individual tokens to be lexed as a single token, return true (which
|
||||
/// causes a space to be printed between them). This allows the output of -E
|
||||
/// mode to be lexed to the same token stream as lexing the input directly
|
||||
/// would.
|
||||
///
|
||||
/// This code must conservatively return true if it doesn't want to be 100%
|
||||
/// accurate. This will cause the output to include extra space characters, but
|
||||
/// the resulting output won't have incorrect concatenations going on. Examples
|
||||
/// include "..", which we print with a space between, because we don't want to
|
||||
/// track enough to tell "x.." from "...".
|
||||
bool PrintPPOutputPPCallbacks::AvoidConcat(const Token &PrevTok,
|
||||
const Token &Tok) {
|
||||
char Buffer[256];
|
||||
|
||||
tok::TokenKind PrevKind = PrevTok.getKind();
|
||||
if (PrevTok.getIdentifierInfo()) // Language keyword or named operator.
|
||||
PrevKind = tok::identifier;
|
||||
|
||||
// Look up information on when we should avoid concatenation with prevtok.
|
||||
unsigned ConcatInfo = TokenInfo[PrevKind];
|
||||
|
||||
// If prevtok never causes a problem for anything after it, return quickly.
|
||||
if (ConcatInfo == 0) return false;
|
||||
|
||||
if (ConcatInfo & aci_avoid_equal) {
|
||||
// If the next token is '=' or '==', avoid concatenation.
|
||||
if (Tok.is(tok::equal) || Tok.is(tok::equalequal))
|
||||
return true;
|
||||
ConcatInfo &= ~aci_avoid_equal;
|
||||
}
|
||||
|
||||
if (ConcatInfo == 0) return false;
|
||||
|
||||
|
||||
|
||||
// Basic algorithm: we look at the first character of the second token, and
|
||||
// determine whether it, if appended to the first token, would form (or would
|
||||
// contribute) to a larger token if concatenated.
|
||||
char FirstChar = 0;
|
||||
if (ConcatInfo & aci_custom) {
|
||||
// If the token does not need to know the first character, don't get it.
|
||||
} else if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
|
||||
// Avoid spelling identifiers, the most common form of token.
|
||||
FirstChar = II->getName()[0];
|
||||
} else if (!Tok.needsCleaning()) {
|
||||
SourceManager &SrcMgr = PP.getSourceManager();
|
||||
FirstChar =
|
||||
*SrcMgr.getCharacterData(SrcMgr.getPhysicalLoc(Tok.getLocation()));
|
||||
} else if (Tok.getLength() < 256) {
|
||||
const char *TokPtr = Buffer;
|
||||
PP.getSpelling(Tok, TokPtr);
|
||||
FirstChar = TokPtr[0];
|
||||
} else {
|
||||
FirstChar = PP.getSpelling(Tok)[0];
|
||||
}
|
||||
|
||||
switch (PrevKind) {
|
||||
default: assert(0 && "InitAvoidConcatTokenInfo built wrong");
|
||||
case tok::identifier: // id+id or id+number or id+L"foo".
|
||||
if (Tok.is(tok::numeric_constant) || Tok.getIdentifierInfo() ||
|
||||
Tok.is(tok::wide_string_literal) /* ||
|
||||
Tok.is(tok::wide_char_literal)*/)
|
||||
return true;
|
||||
|
||||
// If this isn't identifier + string, we're done.
|
||||
if (Tok.isNot(tok::char_constant) && Tok.isNot(tok::string_literal))
|
||||
return false;
|
||||
|
||||
// FIXME: need a wide_char_constant!
|
||||
|
||||
// If the string was a wide string L"foo" or wide char L'f', it would concat
|
||||
// with the previous identifier into fooL"bar". Avoid this.
|
||||
if (StartsWithL(Tok, PP))
|
||||
return true;
|
||||
|
||||
// Otherwise, this is a narrow character or string. If the *identifier* is
|
||||
// a literal 'L', avoid pasting L "foo" -> L"foo".
|
||||
return IsIdentifierL(PrevTok, PP);
|
||||
case tok::numeric_constant:
|
||||
return isalnum(FirstChar) || Tok.is(tok::numeric_constant) ||
|
||||
FirstChar == '+' || FirstChar == '-' || FirstChar == '.';
|
||||
case tok::period: // ..., .*, .1234
|
||||
return FirstChar == '.' || FirstChar == '*' || isdigit(FirstChar);
|
||||
case tok::amp: // &&
|
||||
return FirstChar == '&';
|
||||
case tok::plus: // ++
|
||||
return FirstChar == '+';
|
||||
case tok::minus: // --, ->, ->*
|
||||
return FirstChar == '-' || FirstChar == '>';
|
||||
case tok::slash: //, /*, //
|
||||
return FirstChar == '*' || FirstChar == '/';
|
||||
case tok::less: // <<, <<=, <:, <%
|
||||
return FirstChar == '<' || FirstChar == ':' || FirstChar == '%';
|
||||
case tok::greater: // >>, >>=
|
||||
return FirstChar == '>';
|
||||
case tok::pipe: // ||
|
||||
return FirstChar == '|';
|
||||
case tok::percent: // %>, %:
|
||||
return FirstChar == '>' || FirstChar == ':';
|
||||
case tok::colon: // ::, :>
|
||||
return FirstChar == ':' || FirstChar == '>';
|
||||
case tok::hash: // ##, #@, %:%:
|
||||
return FirstChar == '#' || FirstChar == '@' || FirstChar == '%';
|
||||
case tok::arrow: // ->*
|
||||
return FirstChar == '*';
|
||||
}
|
||||
}
|
||||
|
||||
/// DoPrintPreprocessedInput - This implements -E mode.
|
||||
///
|
||||
void clang::DoPrintPreprocessedInput(Preprocessor &PP) {
|
||||
// Inform the preprocessor whether we want it to retain comments or not, due
|
||||
// to -C or -CC.
|
||||
PP.SetCommentRetentionState(EnableCommentOutput, EnableMacroCommentOutput);
|
||||
|
||||
InitOutputBuffer();
|
||||
InitAvoidConcatTokenInfo();
|
||||
|
||||
Token Tok, PrevTok;
|
||||
char Buffer[256];
|
||||
PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks(PP);
|
||||
PP.setPPCallbacks(Callbacks);
|
||||
|
||||
PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks));
|
||||
PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",Callbacks));
|
||||
|
||||
// After we have configured the preprocessor, enter the main file.
|
||||
|
||||
// Start parsing the specified input file.
|
||||
PP.EnterMainSourceFile();
|
||||
|
||||
// Consume all of the tokens that come from the predefines buffer. Those
|
||||
// should not be emitted into the output and are guaranteed to be at the
|
||||
// start.
|
||||
const SourceManager &SourceMgr = PP.getSourceManager();
|
||||
do PP.Lex(Tok);
|
||||
while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() &&
|
||||
!strcmp(SourceMgr.getSourceName(Tok.getLocation()), "<predefines>"));
|
||||
|
||||
while (1) {
|
||||
|
||||
// If this token is at the start of a line, emit newlines if needed.
|
||||
if (Tok.isAtStartOfLine() && Callbacks->HandleFirstTokOnLine(Tok)) {
|
||||
// done.
|
||||
} else if (Tok.hasLeadingSpace() ||
|
||||
// If we haven't emitted a token on this line yet, PrevTok isn't
|
||||
// useful to look at and no concatenation could happen anyway.
|
||||
(Callbacks->hasEmittedTokensOnThisLine() &&
|
||||
// Don't print "-" next to "-", it would form "--".
|
||||
Callbacks->AvoidConcat(PrevTok, Tok))) {
|
||||
OutputChar(' ');
|
||||
}
|
||||
|
||||
if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
|
||||
const char *Str = II->getName();
|
||||
unsigned Len = Tok.needsCleaning() ? strlen(Str) : Tok.getLength();
|
||||
OutputString(Str, Len);
|
||||
} else if (Tok.getLength() < 256) {
|
||||
const char *TokPtr = Buffer;
|
||||
unsigned Len = PP.getSpelling(Tok, TokPtr);
|
||||
OutputString(TokPtr, Len);
|
||||
} else {
|
||||
std::string S = PP.getSpelling(Tok);
|
||||
OutputString(&S[0], S.size());
|
||||
}
|
||||
Callbacks->SetEmittedTokensOnThisLine();
|
||||
|
||||
if (Tok.is(tok::eof)) break;
|
||||
|
||||
PrevTok = Tok;
|
||||
PP.Lex(Tok);
|
||||
}
|
||||
OutputChar('\n');
|
||||
|
||||
CleanupOutputBuffer();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,196 +0,0 @@
|
||||
//===--- SerializationTest.cpp - Experimental Object Serialization --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements prototype code for serialization of objects in clang.
|
||||
// It is not intended yet for public use, but simply is a placeholder to
|
||||
// experiment with new serialization features. Serialization will eventually
|
||||
// be integrated as a proper component of the clang libraries.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang.h"
|
||||
#include "ASTConsumers.h"
|
||||
#include "clang/AST/TranslationUnit.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include <fstream>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Driver code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
|
||||
class SerializationTest : public ASTConsumer {
|
||||
TranslationUnit TU;
|
||||
Diagnostic &Diags;
|
||||
FileManager &FMgr;
|
||||
public:
|
||||
SerializationTest(Diagnostic &d, FileManager& fmgr, const LangOptions& LOpts)
|
||||
: TU(LOpts), Diags(d), FMgr(fmgr) {}
|
||||
|
||||
~SerializationTest();
|
||||
|
||||
virtual void Initialize(ASTContext& context) {
|
||||
TU.setContext(&context);
|
||||
}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
TU.AddTopLevelDecl(D);
|
||||
}
|
||||
|
||||
private:
|
||||
bool Serialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
|
||||
bool Deserialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer*
|
||||
clang::CreateSerializationTest(Diagnostic &Diags, FileManager& FMgr,
|
||||
const LangOptions &LOpts) {
|
||||
|
||||
return new SerializationTest(Diags,FMgr,LOpts);
|
||||
}
|
||||
|
||||
|
||||
bool SerializationTest::Serialize(llvm::sys::Path& Filename,
|
||||
llvm::sys::Path& FNameDeclPrint) {
|
||||
{
|
||||
// Pretty-print the decls to a temp file.
|
||||
std::ofstream DeclPP(FNameDeclPrint.c_str());
|
||||
assert (DeclPP && "Could not open file for printing out decls.");
|
||||
llvm::OwningPtr<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
|
||||
|
||||
for (TranslationUnit::iterator I=TU.begin(), E=TU.end(); I!=E; ++I)
|
||||
FilePrinter->HandleTopLevelDecl(*I);
|
||||
}
|
||||
|
||||
// Serialize the translation unit.
|
||||
return EmitASTBitcodeFile(TU,Filename);
|
||||
}
|
||||
|
||||
bool SerializationTest::Deserialize(llvm::sys::Path& Filename,
|
||||
llvm::sys::Path& FNameDeclPrint) {
|
||||
|
||||
// Deserialize the translation unit.
|
||||
TranslationUnit* NewTU = ReadASTBitcodeFile(Filename,FMgr);
|
||||
|
||||
if (!NewTU)
|
||||
return false;
|
||||
|
||||
{
|
||||
// Pretty-print the deserialized decls to a temp file.
|
||||
std::ofstream DeclPP(FNameDeclPrint.c_str());
|
||||
assert (DeclPP && "Could not open file for printing out decls.");
|
||||
llvm::OwningPtr<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
|
||||
|
||||
for (TranslationUnit::iterator I=NewTU->begin(), E=NewTU->end(); I!=E; ++I)
|
||||
FilePrinter->HandleTopLevelDecl(*I);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class TmpDirJanitor {
|
||||
llvm::sys::Path& Dir;
|
||||
public:
|
||||
explicit TmpDirJanitor(llvm::sys::Path& dir) : Dir(dir) {}
|
||||
|
||||
~TmpDirJanitor() {
|
||||
llvm::cerr << "Removing: " << Dir.c_str() << '\n';
|
||||
Dir.eraseFromDisk(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SerializationTest::~SerializationTest() {
|
||||
|
||||
std::string ErrMsg;
|
||||
llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
|
||||
|
||||
if (Dir.isEmpty()) {
|
||||
llvm::cerr << "Error: " << ErrMsg << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
TmpDirJanitor RemoveTmpOnExit(Dir);
|
||||
|
||||
llvm::sys::Path FNameDeclBefore = Dir;
|
||||
FNameDeclBefore.appendComponent("test.decl_before.txt");
|
||||
|
||||
if (FNameDeclBefore.makeUnique(true,&ErrMsg)) {
|
||||
llvm::cerr << "Error: " << ErrMsg << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::sys::Path FNameDeclAfter = Dir;
|
||||
FNameDeclAfter.appendComponent("test.decl_after.txt");
|
||||
|
||||
if (FNameDeclAfter.makeUnique(true,&ErrMsg)) {
|
||||
llvm::cerr << "Error: " << ErrMsg << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::sys::Path ASTFilename = Dir;
|
||||
ASTFilename.appendComponent("test.ast");
|
||||
|
||||
if (ASTFilename.makeUnique(true,&ErrMsg)) {
|
||||
llvm::cerr << "Error: " << ErrMsg << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Serialize and then deserialize the ASTs.
|
||||
bool status = Serialize(ASTFilename, FNameDeclBefore);
|
||||
assert (status && "Serialization failed.");
|
||||
status = Deserialize(ASTFilename, FNameDeclAfter);
|
||||
assert (status && "Deserialization failed.");
|
||||
|
||||
// Read both pretty-printed files and compare them.
|
||||
|
||||
using llvm::MemoryBuffer;
|
||||
|
||||
llvm::OwningPtr<MemoryBuffer>
|
||||
MBufferSer(MemoryBuffer::getFile(FNameDeclBefore.c_str(),
|
||||
strlen(FNameDeclBefore.c_str())));
|
||||
|
||||
if(!MBufferSer) {
|
||||
llvm::cerr << "ERROR: Cannot read pretty-printed file (pre-pickle).\n";
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::OwningPtr<MemoryBuffer>
|
||||
MBufferDSer(MemoryBuffer::getFile(FNameDeclAfter.c_str(),
|
||||
strlen(FNameDeclAfter.c_str())));
|
||||
|
||||
if(!MBufferDSer) {
|
||||
llvm::cerr << "ERROR: Cannot read pretty-printed file (post-pickle).\n";
|
||||
return;
|
||||
}
|
||||
|
||||
const char *p1 = MBufferSer->getBufferStart();
|
||||
const char *e1 = MBufferSer->getBufferEnd();
|
||||
const char *p2 = MBufferDSer->getBufferStart();
|
||||
const char *e2 = MBufferDSer->getBufferEnd();
|
||||
|
||||
if (MBufferSer->getBufferSize() == MBufferDSer->getBufferSize())
|
||||
for ( ; p1 != e1 ; ++p1, ++p2 )
|
||||
if (*p1 != *p2) break;
|
||||
|
||||
if (p1 != e1 || p2 != e2 )
|
||||
llvm::cerr << "ERROR: Pretty-printed files are not the same.\n";
|
||||
else
|
||||
llvm::cerr << "SUCCESS: Pretty-printed files are the same.\n";
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
//===--- TextDiagnosticBuffer.cpp - Buffer Text Diagnostics ---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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 &Diags,
|
||||
Diagnostic::Level Level,
|
||||
FullSourceLoc 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.getLocation(),
|
||||
FormatDiagnostic(Diags, Level, ID,
|
||||
Strs, NumStrs)));
|
||||
break;
|
||||
case Diagnostic::Error:
|
||||
Errors.push_back(std::make_pair(Pos.getLocation(),
|
||||
FormatDiagnostic(Diags, Level, ID,
|
||||
Strs, NumStrs)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
//===--- TextDiagnosticBuffer.h - Buffer Text Diagnostics -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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() {}
|
||||
|
||||
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 &Diags,
|
||||
Diagnostic::Level DiagLevel,
|
||||
FullSourceLoc Pos,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs,
|
||||
const SourceRange *Ranges,
|
||||
unsigned NumRanges);
|
||||
};
|
||||
|
||||
} // end namspace clang
|
||||
|
||||
#endif
|
||||
@@ -1,208 +0,0 @@
|
||||
//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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 "llvm/Support/Streams.h"
|
||||
#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(FullSourceLoc Pos) {
|
||||
if (Pos.isInvalid()) return;
|
||||
|
||||
Pos = Pos.getLogicalLoc();
|
||||
|
||||
// Print out the other include frames first.
|
||||
PrintIncludeStack(Pos.getIncludeLoc());
|
||||
unsigned LineNo = Pos.getLineNumber();
|
||||
|
||||
llvm::cerr << "In file included from " << Pos.getSourceName()
|
||||
<< ":" << 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,
|
||||
SourceManager& SourceMgr,
|
||||
unsigned LineNo, unsigned FileID,
|
||||
std::string &CaratLine,
|
||||
const std::string &SourceLine) {
|
||||
assert(CaratLine.size() == SourceLine.size() &&
|
||||
"Expect a correspondence between source and carat line!");
|
||||
if (!R.isValid()) return;
|
||||
|
||||
SourceLocation LogicalStart = SourceMgr.getLogicalLoc(R.getBegin());
|
||||
unsigned StartLineNo = SourceMgr.getLineNumber(LogicalStart);
|
||||
if (StartLineNo > LineNo || LogicalStart.getFileID() != FileID)
|
||||
return; // No intersection.
|
||||
|
||||
SourceLocation LogicalEnd = SourceMgr.getLogicalLoc(R.getEnd());
|
||||
unsigned EndLineNo = SourceMgr.getLineNumber(LogicalEnd);
|
||||
if (EndLineNo < LineNo || LogicalStart.getFileID() != FileID)
|
||||
return; // No intersection.
|
||||
|
||||
// Compute the column number of the start.
|
||||
unsigned StartColNo = 0;
|
||||
if (StartLineNo == LineNo) {
|
||||
StartColNo = SourceMgr.getLogicalColumnNumber(R.getBegin());
|
||||
if (StartColNo) --StartColNo; // Zero base the col #.
|
||||
}
|
||||
|
||||
// Pick the first non-whitespace column.
|
||||
while (StartColNo < SourceLine.size() &&
|
||||
(SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
|
||||
++StartColNo;
|
||||
|
||||
// Compute the column number of the end.
|
||||
unsigned EndColNo = CaratLine.size();
|
||||
if (EndLineNo == LineNo) {
|
||||
EndColNo = SourceMgr.getLogicalColumnNumber(R.getEnd());
|
||||
if (EndColNo) {
|
||||
--EndColNo; // Zero base the col #.
|
||||
|
||||
// Add in the length of the token, so that we cover multi-char tokens.
|
||||
EndColNo += Lexer::MeasureTokenLength(R.getEnd(), SourceMgr);
|
||||
} 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] = '~';
|
||||
}
|
||||
|
||||
void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic &Diags,
|
||||
Diagnostic::Level Level,
|
||||
FullSourceLoc Pos,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs,
|
||||
const SourceRange *Ranges,
|
||||
unsigned NumRanges) {
|
||||
unsigned LineNo = 0, ColNo = 0;
|
||||
unsigned FileID = 0;
|
||||
const char *LineStart = 0, *LineEnd = 0;
|
||||
|
||||
if (Pos.isValid()) {
|
||||
FullSourceLoc LPos = Pos.getLogicalLoc();
|
||||
LineNo = LPos.getLineNumber();
|
||||
FileID = LPos.getLocation().getFileID();
|
||||
|
||||
// First, if this diagnostic is not in the main file, print out the
|
||||
// "included from" lines.
|
||||
if (LastWarningLoc != LPos.getIncludeLoc()) {
|
||||
LastWarningLoc = LPos.getIncludeLoc();
|
||||
PrintIncludeStack(LastWarningLoc);
|
||||
}
|
||||
|
||||
// Compute the column number. Rewind from the current position to the start
|
||||
// of the line.
|
||||
ColNo = LPos.getColumnNumber();
|
||||
const char *TokLogicalPtr = LPos.getCharacterData();
|
||||
LineStart = TokLogicalPtr-ColNo+1; // Column # is 1-based
|
||||
|
||||
// Compute the line end. Scan forward from the error position to the end of
|
||||
// the line.
|
||||
const llvm::MemoryBuffer *Buffer = LPos.getBuffer();
|
||||
const char *BufEnd = Buffer->getBufferEnd();
|
||||
LineEnd = TokLogicalPtr;
|
||||
while (LineEnd != BufEnd &&
|
||||
*LineEnd != '\n' && *LineEnd != '\r')
|
||||
++LineEnd;
|
||||
|
||||
llvm::cerr << Buffer->getBufferIdentifier()
|
||||
<< ":" << LineNo << ":";
|
||||
if (ColNo && !NoShowColumn)
|
||||
llvm::cerr << ColNo << ":";
|
||||
llvm::cerr << " ";
|
||||
}
|
||||
|
||||
switch (Level) {
|
||||
default: assert(0 && "Unknown diagnostic type!");
|
||||
case Diagnostic::Note: llvm::cerr << "note: "; break;
|
||||
case Diagnostic::Warning: llvm::cerr << "warning: "; break;
|
||||
case Diagnostic::Error: llvm::cerr << "error: "; break;
|
||||
case Diagnostic::Fatal: llvm::cerr << "fatal error: "; break;
|
||||
break;
|
||||
}
|
||||
|
||||
llvm::cerr << FormatDiagnostic(Diags, Level, ID, Strs, NumStrs) << "\n";
|
||||
|
||||
if (!NoCaretDiagnostics && Pos.isValid()) {
|
||||
// Get the line of the source file.
|
||||
std::string SourceLine(LineStart, LineEnd);
|
||||
|
||||
// Create a line for the carat that is filled with spaces that is the same
|
||||
// length as the line of source code.
|
||||
std::string CaratLine(LineEnd-LineStart, ' ');
|
||||
|
||||
// Highlight all of the characters covered by Ranges with ~ characters.
|
||||
for (unsigned i = 0; i != NumRanges; ++i)
|
||||
HighlightRange(Ranges[i], Pos.getManager(), LineNo, FileID,
|
||||
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.
|
||||
llvm::cerr << SourceLine << "\n";
|
||||
llvm::cerr << CaratLine << "\n";
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
//===--- TextDiagnosticPrinter.h - Text Diagnostic Client -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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 {
|
||||
FullSourceLoc LastWarningLoc;
|
||||
public:
|
||||
TextDiagnosticPrinter() {}
|
||||
|
||||
void PrintIncludeStack(FullSourceLoc Pos);
|
||||
|
||||
void HighlightRange(const SourceRange &R,
|
||||
SourceManager& SrcMgr,
|
||||
unsigned LineNo, unsigned FileID,
|
||||
std::string &CaratLine,
|
||||
const std::string &SourceLine);
|
||||
|
||||
virtual void HandleDiagnostic(Diagnostic &Diags,
|
||||
Diagnostic::Level DiagLevel,
|
||||
FullSourceLoc Pos,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs,
|
||||
const SourceRange *Ranges,
|
||||
unsigned NumRanges);
|
||||
};
|
||||
|
||||
} // end namspace clang
|
||||
|
||||
#endif
|
||||
@@ -1,58 +0,0 @@
|
||||
//===--- TextDiagnostics.cpp - Text Diagnostics Parent Class --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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 &Diags,
|
||||
Diagnostic::Level Level,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs) {
|
||||
std::string Msg = Diags.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,
|
||||
FullSourceLoc Pos) {
|
||||
if (Pos.isValid()) {
|
||||
// If this is a warning or note, and if it a system header, suppress the
|
||||
// diagnostic.
|
||||
if (Level == Diagnostic::Warning || Level == Diagnostic::Note) {
|
||||
if (const FileEntry *F = Pos.getFileEntryForLoc()) {
|
||||
DirectoryLookup::DirType DirInfo = TheHeaderSearch->getFileDirFlavor(F);
|
||||
if (DirInfo == DirectoryLookup::SystemHeaderDir ||
|
||||
DirInfo == DirectoryLookup::ExternCSystemHeaderDir)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
//===--- TextDiagnostics.h - Text Diagnostics Checkers ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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:
|
||||
std::string FormatDiagnostic(Diagnostic &Diags, Diagnostic::Level Level,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs);
|
||||
public:
|
||||
TextDiagnostics() {}
|
||||
virtual ~TextDiagnostics();
|
||||
|
||||
void setHeaderSearch(HeaderSearch &HS) { TheHeaderSearch = &HS; }
|
||||
|
||||
virtual bool IgnoreDiagnostic(Diagnostic::Level Level,
|
||||
FullSourceLoc Pos);
|
||||
|
||||
virtual void HandleDiagnostic(Diagnostic &Diags, Diagnostic::Level DiagLevel,
|
||||
FullSourceLoc Pos,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs,
|
||||
const SourceRange *Ranges,
|
||||
unsigned NumRanges) = 0;
|
||||
};
|
||||
|
||||
} // end namspace clang
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,45 +0,0 @@
|
||||
//===--- clang.h - C-Language Front-end -----------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
class Preprocessor;
|
||||
class MinimalAction;
|
||||
class TargetInfo;
|
||||
class Diagnostic;
|
||||
class ASTConsumer;
|
||||
class IdentifierTable;
|
||||
class SourceManager;
|
||||
|
||||
/// DoPrintPreprocessedInput - Implement -E mode.
|
||||
void DoPrintPreprocessedInput(Preprocessor &PP);
|
||||
|
||||
/// CreatePrintParserActionsAction - Return the actions implementation that
|
||||
/// implements the -parse-print-callbacks option.
|
||||
MinimalAction *CreatePrintParserActionsAction(IdentifierTable &);
|
||||
|
||||
/// EmitLLVMFromASTs - Implement -emit-llvm, which generates llvm IR from C.
|
||||
void EmitLLVMFromASTs(Preprocessor &PP, bool PrintStats);
|
||||
|
||||
/// CheckASTConsumer - Implement diagnostic checking for AST consumers.
|
||||
bool CheckASTConsumer(Preprocessor &PP, ASTConsumer* C);
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,2 +0,0 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
//#import<vecLib/vecLib.h>
|
||||
@@ -1,5 +0,0 @@
|
||||
// clang -I/usr/include/c++/4.0.0 -I/usr/include/c++/4.0.0/powerpc-apple-darwin8 -I/usr/include/c++/4.0.0/backward INPUTS/iostream.cc -Eonly
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
// This pounds on macro expansion for performance reasons. This is currently
|
||||
// heavily constrained by darwin's malloc.
|
||||
|
||||
// Function-like macros.
|
||||
#define A0(A, B) A B
|
||||
#define A1(A, B) A0(A,B) A0(A,B) A0(A,B) A0(A,B) A0(A,B) A0(A,B)
|
||||
#define A2(A, B) A1(A,B) A1(A,B) A1(A,B) A1(A,B) A1(A,B) A1(A,B)
|
||||
#define A3(A, B) A2(A,B) A2(A,B) A2(A,B) A2(A,B) A2(A,B) A2(A,B)
|
||||
#define A4(A, B) A3(A,B) A3(A,B) A3(A,B) A3(A,B) A3(A,B) A3(A,B)
|
||||
#define A5(A, B) A4(A,B) A4(A,B) A4(A,B) A4(A,B) A4(A,B) A4(A,B)
|
||||
#define A6(A, B) A5(A,B) A5(A,B) A5(A,B) A5(A,B) A5(A,B) A5(A,B)
|
||||
#define A7(A, B) A6(A,B) A6(A,B) A6(A,B) A6(A,B) A6(A,B) A6(A,B)
|
||||
#define A8(A, B) A7(A,B) A7(A,B) A7(A,B) A7(A,B) A7(A,B) A7(A,B)
|
||||
|
||||
A8(a, b)
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
// This pounds on macro expansion for performance reasons. This is currently
|
||||
// heavily constrained by darwin's malloc.
|
||||
|
||||
// Object-like expansions
|
||||
#define A0 a b
|
||||
#define A1 A0 A0 A0 A0 A0 A0
|
||||
#define A2 A1 A1 A1 A1 A1 A1
|
||||
#define A3 A2 A2 A2 A2 A2 A2
|
||||
#define A4 A3 A3 A3 A3 A3 A3
|
||||
#define A5 A4 A4 A4 A4 A4 A4
|
||||
#define A6 A5 A5 A5 A5 A5 A5
|
||||
#define A7 A6 A6 A6 A6 A6 A6
|
||||
#define A8 A7 A7 A7 A7 A7 A7
|
||||
|
||||
A8
|
||||
@@ -1,47 +0,0 @@
|
||||
#define __extension__
|
||||
|
||||
#define __stpcpy(dest, src) (__extension__ (__builtin_constant_p (src) ? (__string2_1bptr_p (src) && strlen (src) + 1 <= 8 ? __stpcpy_small (dest, __stpcpy_args (src), strlen (src) + 1) : ((char *) __mempcpy (dest, src, strlen (src) + 1) - 1)) : __stpcpy (dest, src)))
|
||||
#define stpcpy(dest, src) __stpcpy (dest, src)
|
||||
#define __stpcpy_args(src) __extension__ __STRING2_SMALL_GET16 (src, 0), __extension__ __STRING2_SMALL_GET16 (src, 4), __extension__ __STRING2_SMALL_GET32 (src, 0), __extension__ __STRING2_SMALL_GET32 (src, 4)
|
||||
|
||||
#define __mempcpy(dest, src, n) (__extension__ (__builtin_constant_p (src) && __builtin_constant_p (n) && __string2_1bptr_p (src) && n <= 8 ? __mempcpy_small (dest, __mempcpy_args (src), n) : __mempcpy (dest, src, n)))
|
||||
#define mempcpy(dest, src, n) __mempcpy (dest, src, n)
|
||||
#define __mempcpy_args(src) ((char *) (src))[0], ((char *) (src))[2], ((char *) (src))[4], ((char *) (src))[6], __extension__ __STRING2_SMALL_GET16 (src, 0), __extension__ __STRING2_SMALL_GET16 (src, 4), __extension__ __STRING2_SMALL_GET32 (src, 0), __extension__ __STRING2_SMALL_GET32 (src, 4)
|
||||
|
||||
#define __STRING2_SMALL_GET16(src, idx) (((__const unsigned char *) (__const char *) (src))[idx + 1] << 8 | ((__const unsigned char *) (__const char *) (src))[idx])
|
||||
|
||||
#define __STRING2_SMALL_GET32(src, idx) (((((__const unsigned char *) (__const char *) (src))[idx + 3] << 8 | ((__const unsigned char *) (__const char *) (src))[idx + 2]) << 8 | ((__const unsigned char *) (__const char *) (src))[idx + 1]) << 8 | ((__const unsigned char *) (__const char *) (src))[idx])
|
||||
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
@@ -1,63 +0,0 @@
|
||||
==============================================================================
|
||||
LLVM Release License
|
||||
==============================================================================
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2007 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
LLVM Team
|
||||
|
||||
University of Illinois at Urbana-Champaign
|
||||
|
||||
http://llvm.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the LLVM Team, University of Illinois at
|
||||
Urbana-Champaign, nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this Software without specific
|
||||
prior written permission.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||
SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
The LLVM software contains code written by third parties. Such software will
|
||||
have its own individual LICENSE.TXT file in the directory in which it appears.
|
||||
This file will describe the copyrights, license, and restrictions which apply
|
||||
to that code.
|
||||
|
||||
The disclaimer of warranty in the University of Illinois Open Source License
|
||||
applies to all code in the LLVM Distribution, and nothing in any of the
|
||||
other licenses gives permission to use the names of the LLVM Team or the
|
||||
University of Illinois to endorse or promote products derived from this
|
||||
Software.
|
||||
|
||||
The following pieces of software have additional or alternate copyrights,
|
||||
licenses, and/or restrictions:
|
||||
|
||||
Program Directory
|
||||
------- ---------
|
||||
<none yet>
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
//===--- HeaderMap.cpp - A file that acts like dir of symlinks ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the HeaderMap interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Lex/HeaderMap.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Data Structures and Manifest Constants
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
enum {
|
||||
HMAP_HeaderMagicNumber = ('h' << 24) | ('m' << 16) | ('a' << 8) | 'p',
|
||||
HMAP_HeaderVersion = 1,
|
||||
|
||||
HMAP_EmptyBucketKey = 0
|
||||
};
|
||||
|
||||
namespace clang {
|
||||
struct HMapBucket {
|
||||
uint32_t Key; // Offset (into strings) of key.
|
||||
|
||||
uint32_t Prefix; // Offset (into strings) of value prefix.
|
||||
uint32_t Suffix; // Offset (into strings) of value suffix.
|
||||
};
|
||||
|
||||
struct HMapHeader {
|
||||
uint32_t Magic; // Magic word, also indicates byte order.
|
||||
uint16_t Version; // Version number -- currently 1.
|
||||
uint16_t Reserved; // Reserved for future use - zero for now.
|
||||
uint32_t StringsOffset; // Offset to start of string pool.
|
||||
uint32_t NumEntries; // Number of entries in the string table.
|
||||
uint32_t NumBuckets; // Number of buckets (always a power of 2).
|
||||
uint32_t MaxValueLength; // Length of longest result path (excluding nul).
|
||||
// An array of 'NumBuckets' HMapBucket objects follows this header.
|
||||
// Strings follow the buckets, at StringsOffset.
|
||||
};
|
||||
} // end namespace clang.
|
||||
|
||||
/// HashHMapKey - This is the 'well known' hash function required by the file
|
||||
/// format, used to look up keys in the hash table. The hash table uses simple
|
||||
/// linear probing based on this function.
|
||||
static inline unsigned HashHMapKey(const char *S, const char *End) {
|
||||
unsigned Result = 0;
|
||||
|
||||
for (; S != End; S++)
|
||||
Result += tolower(*S) * 13;
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Verification and Construction
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// HeaderMap::Create - This attempts to load the specified file as a header
|
||||
/// map. If it doesn't look like a HeaderMap, it gives up and returns null.
|
||||
/// If it looks like a HeaderMap but is obviously corrupted, it puts a reason
|
||||
/// into the string error argument and returns null.
|
||||
const HeaderMap *HeaderMap::Create(const FileEntry *FE) {
|
||||
// If the file is too small to be a header map, ignore it.
|
||||
unsigned FileSize = FE->getSize();
|
||||
if (FileSize <= sizeof(HMapHeader)) return 0;
|
||||
|
||||
llvm::OwningPtr<const llvm::MemoryBuffer> FileBuffer(
|
||||
llvm::MemoryBuffer::getFile(FE->getName(), strlen(FE->getName()), 0,
|
||||
FE->getSize()));
|
||||
if (FileBuffer == 0) return 0; // Unreadable file?
|
||||
const char *FileStart = FileBuffer->getBufferStart();
|
||||
|
||||
// We know the file is at least as big as the header, check it now.
|
||||
const HMapHeader *Header = reinterpret_cast<const HMapHeader*>(FileStart);
|
||||
|
||||
// Sniff it to see if it's a headermap by checking the magic number and
|
||||
// version.
|
||||
bool NeedsByteSwap;
|
||||
if (Header->Magic == HMAP_HeaderMagicNumber &&
|
||||
Header->Version == HMAP_HeaderVersion)
|
||||
NeedsByteSwap = false;
|
||||
else if (Header->Magic == llvm::ByteSwap_32(HMAP_HeaderMagicNumber) &&
|
||||
Header->Version == llvm::ByteSwap_16(HMAP_HeaderVersion))
|
||||
NeedsByteSwap = true; // Mixed endianness headermap.
|
||||
else
|
||||
return 0; // Not a header map.
|
||||
|
||||
if (Header->Reserved != 0) return 0;
|
||||
|
||||
// Okay, everything looks good, create the header map.
|
||||
return new HeaderMap(FileBuffer.take(), NeedsByteSwap);
|
||||
}
|
||||
|
||||
HeaderMap::~HeaderMap() {
|
||||
delete FileBuffer;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utility Methods
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
/// getFileName - Return the filename of the headermap.
|
||||
const char *HeaderMap::getFileName() const {
|
||||
return FileBuffer->getBufferIdentifier();
|
||||
}
|
||||
|
||||
unsigned HeaderMap::getEndianAdjustedWord(unsigned X) const {
|
||||
if (!NeedsBSwap) return X;
|
||||
return llvm::ByteSwap_32(X);
|
||||
}
|
||||
|
||||
/// getHeader - Return a reference to the file header, in unbyte-swapped form.
|
||||
/// This method cannot fail.
|
||||
const HMapHeader &HeaderMap::getHeader() const {
|
||||
// We know the file is at least as big as the header. Return it.
|
||||
return *reinterpret_cast<const HMapHeader*>(FileBuffer->getBufferStart());
|
||||
}
|
||||
|
||||
/// getBucket - Return the specified hash table bucket from the header map,
|
||||
/// bswap'ing its fields as appropriate. If the bucket number is not valid,
|
||||
/// this return a bucket with an empty key (0).
|
||||
HMapBucket HeaderMap::getBucket(unsigned BucketNo) const {
|
||||
HMapBucket Result;
|
||||
Result.Key = HMAP_EmptyBucketKey;
|
||||
|
||||
const HMapBucket *BucketArray =
|
||||
reinterpret_cast<const HMapBucket*>(FileBuffer->getBufferStart() +
|
||||
sizeof(HMapHeader));
|
||||
|
||||
const HMapBucket *BucketPtr = BucketArray+BucketNo;
|
||||
if ((char*)(BucketPtr+1) > FileBuffer->getBufferEnd())
|
||||
return Result; // Invalid buffer, corrupt hmap.
|
||||
|
||||
// Otherwise, the bucket is valid. Load the values, bswapping as needed.
|
||||
Result.Key = getEndianAdjustedWord(BucketPtr->Key);
|
||||
Result.Prefix = getEndianAdjustedWord(BucketPtr->Prefix);
|
||||
Result.Suffix = getEndianAdjustedWord(BucketPtr->Suffix);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// getString - Look up the specified string in the string table. If the string
|
||||
/// index is not valid, it returns an empty string.
|
||||
const char *HeaderMap::getString(unsigned StrTabIdx) const {
|
||||
// Add the start of the string table to the idx.
|
||||
StrTabIdx += getEndianAdjustedWord(getHeader().StringsOffset);
|
||||
|
||||
// Check for invalid index.
|
||||
if (StrTabIdx >= FileBuffer->getBufferSize())
|
||||
return 0;
|
||||
|
||||
// Otherwise, we have a valid pointer into the file. Just return it. We know
|
||||
// that the "string" can not overrun the end of the file, because the buffer
|
||||
// is nul terminated by virtue of being a MemoryBuffer.
|
||||
return FileBuffer->getBufferStart()+StrTabIdx;
|
||||
}
|
||||
|
||||
/// StringsEqualWithoutCase - Compare the specified two strings for case-
|
||||
/// insensitive equality, returning true if they are equal. Both strings are
|
||||
/// known to have the same length.
|
||||
static bool StringsEqualWithoutCase(const char *S1, const char *S2,
|
||||
unsigned Len) {
|
||||
for (; Len; ++S1, ++S2, --Len)
|
||||
if (tolower(*S1) != tolower(*S2))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// The Main Drivers
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// dump - Print the contents of this headermap to stderr.
|
||||
void HeaderMap::dump() const {
|
||||
const HMapHeader &Hdr = getHeader();
|
||||
unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
|
||||
|
||||
fprintf(stderr, "Header Map %s:\n %d buckets, %d entries\n",
|
||||
getFileName(), NumBuckets,
|
||||
getEndianAdjustedWord(Hdr.NumEntries));
|
||||
|
||||
for (unsigned i = 0; i != NumBuckets; ++i) {
|
||||
HMapBucket B = getBucket(i);
|
||||
if (B.Key == HMAP_EmptyBucketKey) continue;
|
||||
|
||||
const char *Key = getString(B.Key);
|
||||
const char *Prefix = getString(B.Prefix);
|
||||
const char *Suffix = getString(B.Suffix);
|
||||
fprintf(stderr, " %d. %s -> '%s' '%s'\n", i, Key, Prefix, Suffix);
|
||||
}
|
||||
}
|
||||
|
||||
/// LookupFile - Check to see if the specified relative filename is located in
|
||||
/// this HeaderMap. If so, open it and return its FileEntry.
|
||||
const FileEntry *HeaderMap::LookupFile(const char *FilenameStart,
|
||||
const char *FilenameEnd,
|
||||
FileManager &FM) const {
|
||||
const HMapHeader &Hdr = getHeader();
|
||||
unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
|
||||
|
||||
// If the number of buckets is not a power of two, the headermap is corrupt.
|
||||
// Don't probe infinitely.
|
||||
if (NumBuckets & (NumBuckets-1))
|
||||
return 0;
|
||||
|
||||
// Linearly probe the hash table.
|
||||
for (unsigned Bucket = HashHMapKey(FilenameStart, FilenameEnd);; ++Bucket) {
|
||||
HMapBucket B = getBucket(Bucket & (NumBuckets-1));
|
||||
if (B.Key == HMAP_EmptyBucketKey) return 0; // Hash miss.
|
||||
|
||||
// See if the key matches. If not, probe on.
|
||||
const char *Key = getString(B.Key);
|
||||
unsigned BucketKeyLen = strlen(Key);
|
||||
if (BucketKeyLen != unsigned(FilenameEnd-FilenameStart))
|
||||
continue;
|
||||
|
||||
// See if the actual strings equal.
|
||||
if (!StringsEqualWithoutCase(FilenameStart, Key, BucketKeyLen))
|
||||
continue;
|
||||
|
||||
// If so, we have a match in the hash table. Construct the destination
|
||||
// path.
|
||||
llvm::SmallString<1024> DestPath;
|
||||
DestPath += getString(B.Prefix);
|
||||
DestPath += getString(B.Suffix);
|
||||
return FM.getFile(DestPath.begin(), DestPath.end());
|
||||
}
|
||||
}
|
||||
@@ -1,413 +0,0 @@
|
||||
//===--- HeaderSearch.cpp - Resolve Header File Locations ---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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/Lex/HeaderSearch.h"
|
||||
#include "clang/Lex/HeaderMap.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/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;
|
||||
}
|
||||
|
||||
HeaderSearch::~HeaderSearch() {
|
||||
// Delete headermaps.
|
||||
for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i)
|
||||
delete HeaderMaps[i].second;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/// CreateHeaderMap - This method returns a HeaderMap for the specified
|
||||
/// FileEntry, uniquing them through the the 'HeaderMaps' datastructure.
|
||||
const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
|
||||
// We expect the number of headermaps to be small, and almost always empty.
|
||||
// If it ever grows, use of a linear search should be re-evaluated.
|
||||
if (!HeaderMaps.empty()) {
|
||||
for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i)
|
||||
// Pointer equality comparison of FileEntries works because they are
|
||||
// already uniqued by inode.
|
||||
if (HeaderMaps[i].first == FE)
|
||||
return HeaderMaps[i].second;
|
||||
}
|
||||
|
||||
if (const HeaderMap *HM = HeaderMap::Create(FE)) {
|
||||
HeaderMaps.push_back(std::make_pair(FE, HM));
|
||||
return HM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// File lookup within a DirectoryLookup scope
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// getName - Return the directory or filename corresponding to this lookup
|
||||
/// object.
|
||||
const char *DirectoryLookup::getName() const {
|
||||
if (isNormalDir())
|
||||
return getDir()->getName();
|
||||
if (isFramework())
|
||||
return getFrameworkDir()->getName();
|
||||
assert(isHeaderMap() && "Unknown DirectoryLookup");
|
||||
return getHeaderMap()->getFileName();
|
||||
}
|
||||
|
||||
|
||||
/// LookupFile - Lookup the specified file in this search path, returning it
|
||||
/// if it exists or returning null if not.
|
||||
const FileEntry *DirectoryLookup::LookupFile(const char *FilenameStart,
|
||||
const char *FilenameEnd,
|
||||
HeaderSearch &HS) const {
|
||||
llvm::SmallString<1024> TmpDir;
|
||||
if (isNormalDir()) {
|
||||
// Concatenate the requested file onto the directory.
|
||||
// FIXME: Portability. Filename concatenation should be in sys::Path.
|
||||
TmpDir += getDir()->getName();
|
||||
TmpDir.push_back('/');
|
||||
TmpDir.append(FilenameStart, FilenameEnd);
|
||||
return HS.getFileMgr().getFile(TmpDir.begin(), TmpDir.end());
|
||||
}
|
||||
|
||||
if (isFramework())
|
||||
return DoFrameworkLookup(FilenameStart, FilenameEnd, HS);
|
||||
|
||||
assert(isHeaderMap() && "Unknown directory lookup");
|
||||
return getHeaderMap()->LookupFile(FilenameStart, FilenameEnd,HS.getFileMgr());
|
||||
}
|
||||
|
||||
|
||||
/// DoFrameworkLookup - Do a lookup of the specified file in the current
|
||||
/// DirectoryLookup, which is a framework directory.
|
||||
const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart,
|
||||
const char *FilenameEnd,
|
||||
HeaderSearch &HS) const {
|
||||
FileManager &FileMgr = HS.getFileMgr();
|
||||
|
||||
// Framework names must have a '/' in the filename.
|
||||
const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/');
|
||||
if (SlashPos == FilenameEnd) return 0;
|
||||
|
||||
// Find out if this is the home for the specified framework, by checking
|
||||
// HeaderSearch. Possible answer are yes/no and unknown.
|
||||
const DirectoryEntry *&FrameworkDirCache =
|
||||
HS.LookupFrameworkCache(FilenameStart, SlashPos);
|
||||
|
||||
// If it is known and in some other directory, fail.
|
||||
if (FrameworkDirCache && FrameworkDirCache != getFrameworkDir())
|
||||
return 0;
|
||||
|
||||
// Otherwise, construct the path to this framework dir.
|
||||
|
||||
// FrameworkName = "/System/Library/Frameworks/"
|
||||
llvm::SmallString<1024> FrameworkName;
|
||||
FrameworkName += getFrameworkDir()->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 the cache entry is still unresolved, query to see if the cache entry is
|
||||
// still unresolved. If so, check its existence now.
|
||||
if (FrameworkDirCache == 0) {
|
||||
HS.IncrementFrameworkLookupCount();
|
||||
|
||||
// If the framework dir doesn't exist, we fail.
|
||||
// FIXME: It's probably more efficient to query this with FileMgr.getDir.
|
||||
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.
|
||||
FrameworkDirCache = getFrameworkDir();
|
||||
}
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Header File Location.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
||||
// Step #0, unless disabled, check to see if the file is in the #includer's
|
||||
// directory. This has to be based on CurFileEnt, not CurDir, because
|
||||
// CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and
|
||||
// a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h".
|
||||
// This search is not done for <> headers.
|
||||
if (CurFileEnt && !isAngled && !NoCurDirSearch) {
|
||||
llvm::SmallString<1024> TmpDir;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
CurDir = 0;
|
||||
|
||||
// If this is a system #include, ignore the user #include locs.
|
||||
unsigned i = isAngled ? SystemDirIdx : 0;
|
||||
|
||||
// If this is a #include_next request, start searching after the directory the
|
||||
// file was found in.
|
||||
if (FromDir)
|
||||
i = FromDir-&SearchDirs[0];
|
||||
|
||||
// Cache all of the lookups performed by this method. Many headers are
|
||||
// multiply included, and the "pragma once" optimization prevents them from
|
||||
// being relex/pp'd, but they would still have to search through a
|
||||
// (potentially huge) series of SearchDirs to find it.
|
||||
std::pair<unsigned, unsigned> &CacheLookup =
|
||||
LookupFileCache.GetOrCreateValue(FilenameStart, FilenameEnd).getValue();
|
||||
|
||||
// If the entry has been previously looked up, the first value will be
|
||||
// non-zero. If the value is equal to i (the start point of our search), then
|
||||
// this is a matching hit.
|
||||
if (CacheLookup.first == i+1) {
|
||||
// Skip querying potentially lots of directories for this lookup.
|
||||
i = CacheLookup.second;
|
||||
} else {
|
||||
// Otherwise, this is the first query, or the previous query didn't match
|
||||
// our search start. We will fill in our found location below, so prime the
|
||||
// start point value.
|
||||
CacheLookup.first = i+1;
|
||||
}
|
||||
|
||||
// Check each directory in sequence to see if it contains this file.
|
||||
for (; i != SearchDirs.size(); ++i) {
|
||||
const FileEntry *FE =
|
||||
SearchDirs[i].LookupFile(FilenameStart, FilenameEnd, *this);
|
||||
if (!FE) continue;
|
||||
|
||||
CurDir = &SearchDirs[i];
|
||||
|
||||
// This file is a system header or C++ unfriendly if the dir is.
|
||||
getFileInfo(FE).DirInfo = CurDir->getDirCharacteristic();
|
||||
|
||||
// Remember this location for the next lookup we do.
|
||||
CacheLookup.second = i;
|
||||
return FE;
|
||||
}
|
||||
|
||||
// Otherwise, didn't find it. Remember we didn't find this.
|
||||
CacheLookup.second = SearchDirs.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// LookupSubframeworkHeader - Look up a subframework for the specified
|
||||
/// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from
|
||||
/// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
|
||||
/// is a subframework within Carbon.framework. If so, return the FileEntry
|
||||
/// for the designated file, otherwise return null.
|
||||
const FileEntry *HeaderSearch::
|
||||
LookupSubframeworkHeader(const char *FilenameStart,
|
||||
const char *FilenameEnd,
|
||||
const FileEntry *ContextFileEnt) {
|
||||
// Framework names must have a '/' in the filename. Find it.
|
||||
const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/');
|
||||
if (SlashPos == FilenameEnd) return 0;
|
||||
|
||||
// Look up the base framework name of the ContextFileEnt.
|
||||
const char *ContextName = ContextFileEnt->getName();
|
||||
|
||||
// If the context info wasn't a framework, couldn't be a subframework.
|
||||
const char *FrameworkPos = strstr(ContextName, ".framework/");
|
||||
if (FrameworkPos == 0)
|
||||
return 0;
|
||||
|
||||
llvm::SmallString<1024> FrameworkName(ContextName,
|
||||
FrameworkPos+strlen(".framework/"));
|
||||
|
||||
// Append Frameworks/HIToolbox.framework/
|
||||
FrameworkName += "Frameworks/";
|
||||
FrameworkName.append(FilenameStart, SlashPos);
|
||||
FrameworkName += ".framework/";
|
||||
|
||||
llvm::StringMapEntry<const DirectoryEntry *> &CacheLookup =
|
||||
FrameworkMap.GetOrCreateValue(FilenameStart, SlashPos);
|
||||
|
||||
// Some other location?
|
||||
if (CacheLookup.getValue() &&
|
||||
CacheLookup.getKeyLength() == FrameworkName.size() &&
|
||||
memcmp(CacheLookup.getKeyData(), &FrameworkName[0],
|
||||
CacheLookup.getKeyLength()) != 0)
|
||||
return 0;
|
||||
|
||||
// Cache subframework.
|
||||
if (CacheLookup.getValue() == 0) {
|
||||
++NumSubFrameworkLookups;
|
||||
|
||||
// If the framework dir doesn't exist, we fail.
|
||||
const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.begin(),
|
||||
FrameworkName.end());
|
||||
if (Dir == 0) return 0;
|
||||
|
||||
// Otherwise, if it does, remember that this is the right direntry for this
|
||||
// framework.
|
||||
CacheLookup.setValue(Dir);
|
||||
}
|
||||
|
||||
const FileEntry *FE = 0;
|
||||
|
||||
// Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h"
|
||||
llvm::SmallString<1024> HeadersFilename(FrameworkName);
|
||||
HeadersFilename += "Headers/";
|
||||
HeadersFilename.append(SlashPos+1, FilenameEnd);
|
||||
if (!(FE = FileMgr.getFile(HeadersFilename.begin(),
|
||||
HeadersFilename.end()))) {
|
||||
|
||||
// Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
|
||||
HeadersFilename = FrameworkName;
|
||||
HeadersFilename += "PrivateHeaders/";
|
||||
HeadersFilename.append(SlashPos+1, FilenameEnd);
|
||||
if (!(FE = FileMgr.getFile(HeadersFilename.begin(), HeadersFilename.end())))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This file is a system header or C++ unfriendly if the old file is.
|
||||
getFileInfo(FE).DirInfo = getFileInfo(ContextFileEnt).DirInfo;
|
||||
return FE;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// File Info Management.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
/// getFileInfo - Return the PerFileInfo structure for the specified
|
||||
/// FileEntry.
|
||||
HeaderSearch::PerFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
|
||||
if (FE->getUID() >= FileInfo.size())
|
||||
FileInfo.resize(FE->getUID()+1);
|
||||
return FileInfo[FE->getUID()];
|
||||
}
|
||||
|
||||
/// ShouldEnterIncludeFile - Mark the specified file as a target of of a
|
||||
/// #include, #include_next, or #import directive. Return false if #including
|
||||
/// the file will have no effect or true if we should include it.
|
||||
bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
|
||||
++NumIncluded; // Count # of attempted #includes.
|
||||
|
||||
// Get information about this file.
|
||||
PerFileInfo &FileInfo = getFileInfo(File);
|
||||
|
||||
// If this is a #import directive, check that we have not already imported
|
||||
// this header.
|
||||
if (isImport) {
|
||||
// If this has already been imported, don't import it again.
|
||||
FileInfo.isImport = true;
|
||||
|
||||
// Has this already been #import'ed or #include'd?
|
||||
if (FileInfo.NumIncludes) return false;
|
||||
} else {
|
||||
// Otherwise, if this is a #include of a file that was previously #import'd
|
||||
// or if this is the second #include of a #pragma once file, ignore it.
|
||||
if (FileInfo.isImport)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Next, check to see if the file is wrapped with #ifndef guards. If so, and
|
||||
// if the macro that guards it is defined, we know the #include has no effect.
|
||||
if (FileInfo.ControllingMacro &&
|
||||
FileInfo.ControllingMacro->hasMacroDefinition()) {
|
||||
++NumMultiIncludeFileOptzn;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Increment the number of times this file has been included.
|
||||
++FileInfo.NumIncludes;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
1661
clang/Lex/Lexer.cpp
1661
clang/Lex/Lexer.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,697 +0,0 @@
|
||||
//===--- LiteralSupport.cpp - Code to parse and process literals ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the NumericLiteralParser, CharLiteralParser, and
|
||||
// StringLiteralParser interfaces.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Lex/LiteralSupport.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
using namespace clang;
|
||||
|
||||
/// HexDigitValue - Return the value of the specified hex digit, or -1 if it's
|
||||
/// not valid.
|
||||
static int HexDigitValue(char C) {
|
||||
if (C >= '0' && C <= '9') return C-'0';
|
||||
if (C >= 'a' && C <= 'f') return C-'a'+10;
|
||||
if (C >= 'A' && C <= 'F') return C-'A'+10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// ProcessCharEscape - Parse a standard C escape sequence, which can occur in
|
||||
/// either a character or a string literal.
|
||||
static unsigned ProcessCharEscape(const char *&ThisTokBuf,
|
||||
const char *ThisTokEnd, bool &HadError,
|
||||
SourceLocation Loc, bool IsWide,
|
||||
Preprocessor &PP) {
|
||||
// Skip the '\' char.
|
||||
++ThisTokBuf;
|
||||
|
||||
// We know that this character can't be off the end of the buffer, because
|
||||
// that would have been \", which would not have been the end of string.
|
||||
unsigned ResultChar = *ThisTokBuf++;
|
||||
switch (ResultChar) {
|
||||
// These map to themselves.
|
||||
case '\\': case '\'': case '"': case '?': break;
|
||||
|
||||
// These have fixed mappings.
|
||||
case 'a':
|
||||
// TODO: K&R: the meaning of '\\a' is different in traditional C
|
||||
ResultChar = 7;
|
||||
break;
|
||||
case 'b':
|
||||
ResultChar = 8;
|
||||
break;
|
||||
case 'e':
|
||||
PP.Diag(Loc, diag::ext_nonstandard_escape, "e");
|
||||
ResultChar = 27;
|
||||
break;
|
||||
case 'f':
|
||||
ResultChar = 12;
|
||||
break;
|
||||
case 'n':
|
||||
ResultChar = 10;
|
||||
break;
|
||||
case 'r':
|
||||
ResultChar = 13;
|
||||
break;
|
||||
case 't':
|
||||
ResultChar = 9;
|
||||
break;
|
||||
case 'v':
|
||||
ResultChar = 11;
|
||||
break;
|
||||
|
||||
//case 'u': case 'U': // FIXME: UCNs.
|
||||
case 'x': { // Hex escape.
|
||||
ResultChar = 0;
|
||||
if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
|
||||
PP.Diag(Loc, diag::err_hex_escape_no_digits);
|
||||
HadError = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Hex escapes are a maximal series of hex digits.
|
||||
bool Overflow = false;
|
||||
for (; ThisTokBuf != ThisTokEnd; ++ThisTokBuf) {
|
||||
int CharVal = HexDigitValue(ThisTokBuf[0]);
|
||||
if (CharVal == -1) break;
|
||||
Overflow |= (ResultChar & 0xF0000000) ? true : false; // About to shift out a digit?
|
||||
ResultChar <<= 4;
|
||||
ResultChar |= CharVal;
|
||||
}
|
||||
|
||||
// See if any bits will be truncated when evaluated as a character.
|
||||
unsigned CharWidth = IsWide
|
||||
? PP.getTargetInfo().getWCharWidth(PP.getFullLoc(Loc))
|
||||
: PP.getTargetInfo().getCharWidth(PP.getFullLoc(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(PP.getFullLoc(Loc))
|
||||
: PP.getTargetInfo().getCharWidth(PP.getFullLoc(Loc));
|
||||
|
||||
if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
|
||||
PP.Diag(Loc, diag::warn_octal_escape_too_large);
|
||||
ResultChar &= ~0U >> (32-CharWidth);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise, these are not valid escapes.
|
||||
case '(': case '{': case '[': case '%':
|
||||
// GCC accepts these as extensions. We warn about them as such though.
|
||||
if (!PP.getLangOptions().NoExtensions) {
|
||||
PP.Diag(Loc, diag::ext_nonstandard_escape,
|
||||
std::string()+(char)ResultChar);
|
||||
break;
|
||||
}
|
||||
// FALL THROUGH.
|
||||
default:
|
||||
if (isgraph(ThisTokBuf[0])) {
|
||||
PP.Diag(Loc, diag::ext_unknown_escape, std::string()+(char)ResultChar);
|
||||
} else {
|
||||
PP.Diag(Loc, diag::ext_unknown_escape, "x"+llvm::utohexstr(ResultChar));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ResultChar;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// integer-constant: [C99 6.4.4.1]
|
||||
/// decimal-constant integer-suffix
|
||||
/// octal-constant integer-suffix
|
||||
/// hexadecimal-constant integer-suffix
|
||||
/// decimal-constant:
|
||||
/// nonzero-digit
|
||||
/// decimal-constant digit
|
||||
/// octal-constant:
|
||||
/// 0
|
||||
/// octal-constant octal-digit
|
||||
/// hexadecimal-constant:
|
||||
/// hexadecimal-prefix hexadecimal-digit
|
||||
/// hexadecimal-constant hexadecimal-digit
|
||||
/// hexadecimal-prefix: one of
|
||||
/// 0x 0X
|
||||
/// integer-suffix:
|
||||
/// unsigned-suffix [long-suffix]
|
||||
/// unsigned-suffix [long-long-suffix]
|
||||
/// long-suffix [unsigned-suffix]
|
||||
/// long-long-suffix [unsigned-sufix]
|
||||
/// nonzero-digit:
|
||||
/// 1 2 3 4 5 6 7 8 9
|
||||
/// octal-digit:
|
||||
/// 0 1 2 3 4 5 6 7
|
||||
/// hexadecimal-digit:
|
||||
/// 0 1 2 3 4 5 6 7 8 9
|
||||
/// a b c d e f
|
||||
/// A B C D E F
|
||||
/// unsigned-suffix: one of
|
||||
/// u U
|
||||
/// long-suffix: one of
|
||||
/// l L
|
||||
/// long-long-suffix: one of
|
||||
/// ll LL
|
||||
///
|
||||
/// floating-constant: [C99 6.4.4.2]
|
||||
/// TODO: add rules...
|
||||
///
|
||||
|
||||
NumericLiteralParser::
|
||||
NumericLiteralParser(const char *begin, const char *end,
|
||||
SourceLocation TokLoc, Preprocessor &pp)
|
||||
: PP(pp), ThisTokBegin(begin), ThisTokEnd(end) {
|
||||
s = DigitsBegin = begin;
|
||||
saw_exponent = false;
|
||||
saw_period = false;
|
||||
isLong = false;
|
||||
isUnsigned = false;
|
||||
isLongLong = false;
|
||||
isFloat = false;
|
||||
isImaginary = false;
|
||||
hadError = false;
|
||||
|
||||
if (*s == '0') { // parse radix
|
||||
s++;
|
||||
if ((*s == 'x' || *s == 'X') && (isxdigit(s[1]) || s[1] == '.')) {
|
||||
s++;
|
||||
radix = 16;
|
||||
DigitsBegin = s;
|
||||
s = SkipHexDigits(s);
|
||||
if (s == ThisTokEnd) {
|
||||
// Done.
|
||||
} else if (*s == '.') {
|
||||
s++;
|
||||
saw_period = true;
|
||||
s = SkipHexDigits(s);
|
||||
}
|
||||
// A binary exponent can appear with or with a '.'. If dotted, the
|
||||
// binary exponent is required.
|
||||
if ((*s == 'p' || *s == 'P') && PP.getLangOptions().HexFloats) {
|
||||
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) && !(*s == 'e' || *s == 'E')) {
|
||||
TokLoc = PP.AdvanceToTokenCharacter(TokLoc, s-begin);
|
||||
Diag(TokLoc, diag::err_invalid_octal_digit, std::string(s, s+1));
|
||||
return;
|
||||
} else if (*s == '.') {
|
||||
s++;
|
||||
radix = 10;
|
||||
saw_period = true;
|
||||
s = SkipDigits(s);
|
||||
}
|
||||
if (*s == 'e' || *s == 'E') { // exponent
|
||||
s++;
|
||||
radix = 10;
|
||||
saw_exponent = true;
|
||||
if (*s == '+' || *s == '-') s++; // sign
|
||||
const char *first_non_digit = SkipDigits(s);
|
||||
if (first_non_digit == s) {
|
||||
Diag(TokLoc, diag::err_exponent_has_no_digits);
|
||||
return;
|
||||
} else {
|
||||
s = first_non_digit;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // the first digit is non-zero
|
||||
radix = 10;
|
||||
s = SkipDigits(s);
|
||||
if (s == ThisTokEnd) {
|
||||
// Done.
|
||||
} else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) {
|
||||
Diag(TokLoc, diag::err_invalid_decimal_digit, std::string(s, s+1));
|
||||
return;
|
||||
} else if (*s == '.') {
|
||||
s++;
|
||||
saw_period = true;
|
||||
s = SkipDigits(s);
|
||||
}
|
||||
if (*s == 'e' || *s == 'E') { // exponent
|
||||
s++;
|
||||
saw_exponent = true;
|
||||
if (*s == '+' || *s == '-') s++; // sign
|
||||
const char *first_non_digit = SkipDigits(s);
|
||||
if (first_non_digit == s) {
|
||||
Diag(TokLoc, diag::err_exponent_has_no_digits);
|
||||
return;
|
||||
} else {
|
||||
s = first_non_digit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SuffixBegin = s;
|
||||
|
||||
// Parse the suffix. At this point we can classify whether we have an FP or
|
||||
// integer constant.
|
||||
bool isFPConstant = isFloatingLiteral();
|
||||
|
||||
// Loop over all of the characters of the suffix. If we see something bad,
|
||||
// we break out of the loop.
|
||||
for (; s != ThisTokEnd; ++s) {
|
||||
switch (*s) {
|
||||
case 'f': // FP Suffix for "float"
|
||||
case 'F':
|
||||
if (!isFPConstant) break; // Error for integer constant.
|
||||
if (isFloat || isLong) break; // FF, LF invalid.
|
||||
isFloat = true;
|
||||
continue; // Success.
|
||||
case 'u':
|
||||
case 'U':
|
||||
if (isFPConstant) break; // Error for floating constant.
|
||||
if (isUnsigned) break; // Cannot be repeated.
|
||||
isUnsigned = true;
|
||||
continue; // Success.
|
||||
case 'l':
|
||||
case 'L':
|
||||
if (isLong || isLongLong) break; // Cannot be repeated.
|
||||
if (isFloat) break; // LF invalid.
|
||||
|
||||
// Check for long long. The L's need to be adjacent and the same case.
|
||||
if (s+1 != ThisTokEnd && s[1] == s[0]) {
|
||||
if (isFPConstant) break; // long long invalid for floats.
|
||||
isLongLong = true;
|
||||
++s; // Eat both of them.
|
||||
} else {
|
||||
isLong = true;
|
||||
}
|
||||
continue; // Success.
|
||||
case 'i':
|
||||
case 'I':
|
||||
case 'j':
|
||||
case 'J':
|
||||
if (isImaginary) break; // Cannot be repeated.
|
||||
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
|
||||
diag::ext_imaginary_constant);
|
||||
isImaginary = true;
|
||||
continue; // Success.
|
||||
}
|
||||
// If we reached here, there was an error.
|
||||
break;
|
||||
}
|
||||
|
||||
// Report an error if there are any.
|
||||
if (s != ThisTokEnd) {
|
||||
TokLoc = PP.AdvanceToTokenCharacter(TokLoc, s-begin);
|
||||
Diag(TokLoc, isFPConstant ? diag::err_invalid_suffix_float_constant :
|
||||
diag::err_invalid_suffix_integer_constant,
|
||||
std::string(SuffixBegin, ThisTokEnd));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// GetIntegerValue - Convert this numeric literal value to an APInt that
|
||||
/// matches Val's input width. If there is an overflow, set Val to the low bits
|
||||
/// of the result and return true. Otherwise, return false.
|
||||
bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
|
||||
Val = 0;
|
||||
s = DigitsBegin;
|
||||
|
||||
llvm::APInt RadixVal(Val.getBitWidth(), radix);
|
||||
llvm::APInt CharVal(Val.getBitWidth(), 0);
|
||||
llvm::APInt OldVal = Val;
|
||||
|
||||
bool OverflowOccurred = false;
|
||||
while (s < SuffixBegin) {
|
||||
unsigned C = HexDigitValue(*s++);
|
||||
|
||||
// If this letter is out of bound for this radix, reject it.
|
||||
assert(C < radix && "NumericLiteralParser ctor should have rejected this");
|
||||
|
||||
CharVal = C;
|
||||
|
||||
// Add the digit to the value in the appropriate radix. If adding in digits
|
||||
// made the value smaller, then this overflowed.
|
||||
OldVal = Val;
|
||||
|
||||
// Multiply by radix, did overflow occur on the multiply?
|
||||
Val *= RadixVal;
|
||||
OverflowOccurred |= Val.udiv(RadixVal) != OldVal;
|
||||
|
||||
OldVal = Val;
|
||||
// Add value, did overflow occur on the value?
|
||||
Val += CharVal;
|
||||
OverflowOccurred |= Val.ult(OldVal);
|
||||
OverflowOccurred |= Val.ult(CharVal);
|
||||
}
|
||||
return OverflowOccurred;
|
||||
}
|
||||
|
||||
llvm::APFloat NumericLiteralParser::
|
||||
GetFloatValue(const llvm::fltSemantics &Format, bool* isExact) {
|
||||
using llvm::APFloat;
|
||||
|
||||
llvm::SmallVector<char,256> floatChars;
|
||||
for (unsigned i = 0, n = ThisTokEnd-ThisTokBegin; i != n; ++i)
|
||||
floatChars.push_back(ThisTokBegin[i]);
|
||||
|
||||
floatChars.push_back('\0');
|
||||
|
||||
APFloat V (Format, APFloat::fcZero, false);
|
||||
APFloat::opStatus status;
|
||||
|
||||
status = V.convertFromString(&floatChars[0],APFloat::rmNearestTiesToEven);
|
||||
|
||||
if (isExact)
|
||||
*isExact = status == APFloat::opOK;
|
||||
|
||||
return V;
|
||||
}
|
||||
|
||||
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(PP.getFullLoc(Loc)) == 32 &&
|
||||
"Assumes sizeof(int) == 4 for now");
|
||||
// FIXME: This assumes that wchar_t is 32-bits for now.
|
||||
assert(PP.getTargetInfo().getWCharWidth(PP.getFullLoc(Loc)) == 32 &&
|
||||
"Assumes sizeof(wchar_t) == 4 for now");
|
||||
// FIXME: This extensively assumes that 'char' is 8-bits.
|
||||
assert(PP.getTargetInfo().getCharWidth(PP.getFullLoc(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(PP.getFullLoc(Loc)))
|
||||
Value = (signed char)Value;
|
||||
}
|
||||
|
||||
|
||||
/// string-literal: [C99 6.4.5]
|
||||
/// " [s-char-sequence] "
|
||||
/// L" [s-char-sequence] "
|
||||
/// s-char-sequence:
|
||||
/// s-char
|
||||
/// s-char-sequence s-char
|
||||
/// s-char:
|
||||
/// any source character except the double quote ",
|
||||
/// backslash \, or newline character
|
||||
/// escape-character
|
||||
/// universal-character-name
|
||||
/// escape-character: [C99 6.4.4.4]
|
||||
/// \ escape-code
|
||||
/// universal-character-name
|
||||
/// escape-code:
|
||||
/// character-escape-code
|
||||
/// octal-escape-code
|
||||
/// hex-escape-code
|
||||
/// character-escape-code: one of
|
||||
/// n t b r f v a
|
||||
/// \ ' " ?
|
||||
/// octal-escape-code:
|
||||
/// octal-digit
|
||||
/// octal-digit octal-digit
|
||||
/// octal-digit octal-digit octal-digit
|
||||
/// hex-escape-code:
|
||||
/// x hex-digit
|
||||
/// hex-escape-code hex-digit
|
||||
/// universal-character-name:
|
||||
/// \u hex-quad
|
||||
/// \U hex-quad hex-quad
|
||||
/// hex-quad:
|
||||
/// hex-digit hex-digit hex-digit hex-digit
|
||||
///
|
||||
StringLiteralParser::
|
||||
StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
|
||||
Preprocessor &pp, TargetInfo &t)
|
||||
: PP(pp), Target(t) {
|
||||
// Scan all of the string portions, remember the max individual token length,
|
||||
// computing a bound on the concatenated string length, and see whether any
|
||||
// piece is a wide-string. If any of the string portions is a wide-string
|
||||
// literal, the result is a wide-string literal [C99 6.4.5p4].
|
||||
MaxTokenLength = StringToks[0].getLength();
|
||||
SizeBound = StringToks[0].getLength()-2; // -2 for "".
|
||||
AnyWide = StringToks[0].is(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].is(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(PP.getFullLoc(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.
|
||||
|
||||
Pascal = false;
|
||||
|
||||
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;
|
||||
|
||||
// Check if this is a pascal string
|
||||
if (pp.getLangOptions().PascalStrings && ThisTokBuf + 1 != ThisTokEnd &&
|
||||
ThisTokBuf[0] == '\\' && ThisTokBuf[1] == 'p') {
|
||||
|
||||
// If the \p sequence is found in the first token, we have a pascal string
|
||||
// Otherwise, if we already have a pascal string, ignore the first \p
|
||||
if (i == 0) {
|
||||
++ThisTokBuf;
|
||||
Pascal = true;
|
||||
} else if (Pascal)
|
||||
ThisTokBuf += 2;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (Pascal)
|
||||
ResultBuf[0] = ResultPtr-&ResultBuf[0]-1;
|
||||
}
|
||||
@@ -1,647 +0,0 @@
|
||||
//===--- MacroExpander.cpp - Lex from a macro expansion -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the MacroExpander interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Lex/MacroExpander.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MacroArgs Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// MacroArgs ctor function - This destroys the vector passed in.
|
||||
MacroArgs *MacroArgs::create(const MacroInfo *MI,
|
||||
const Token *UnexpArgTokens,
|
||||
unsigned NumToks, bool VarargsElided) {
|
||||
assert(MI->isFunctionLike() &&
|
||||
"Can't have args for an object-like macro!");
|
||||
|
||||
// Allocate memory for the MacroArgs object with the lexer tokens at the end.
|
||||
MacroArgs *Result = (MacroArgs*)malloc(sizeof(MacroArgs) +
|
||||
NumToks*sizeof(Token));
|
||||
// Construct the macroargs object.
|
||||
new (Result) MacroArgs(NumToks, VarargsElided);
|
||||
|
||||
// Copy the actual unexpanded tokens to immediately after the result ptr.
|
||||
if (NumToks)
|
||||
memcpy(const_cast<Token*>(Result->getUnexpArgument(0)),
|
||||
UnexpArgTokens, NumToks*sizeof(Token));
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// destroy - Destroy and deallocate the memory for this object.
|
||||
///
|
||||
void MacroArgs::destroy() {
|
||||
// Run the dtor to deallocate the vectors.
|
||||
this->~MacroArgs();
|
||||
// Release the memory for the object.
|
||||
free(this);
|
||||
}
|
||||
|
||||
|
||||
/// getArgLength - Given a pointer to an expanded or unexpanded argument,
|
||||
/// return the number of tokens, not counting the EOF, that make up the
|
||||
/// argument.
|
||||
unsigned MacroArgs::getArgLength(const Token *ArgPtr) {
|
||||
unsigned NumArgTokens = 0;
|
||||
for (; ArgPtr->isNot(tok::eof); ++ArgPtr)
|
||||
++NumArgTokens;
|
||||
return NumArgTokens;
|
||||
}
|
||||
|
||||
|
||||
/// getUnexpArgument - Return the unexpanded tokens for the specified formal.
|
||||
///
|
||||
const Token *MacroArgs::getUnexpArgument(unsigned Arg) const {
|
||||
// The unexpanded argument tokens start immediately after the MacroArgs object
|
||||
// in memory.
|
||||
const Token *Start = (const Token *)(this+1);
|
||||
const Token *Result = Start;
|
||||
// Scan to find Arg.
|
||||
for (; Arg; ++Result) {
|
||||
assert(Result < Start+NumUnexpArgTokens && "Invalid arg #");
|
||||
if (Result->is(tok::eof))
|
||||
--Arg;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
/// ArgNeedsPreexpansion - If we can prove that the argument won't be affected
|
||||
/// by pre-expansion, return false. Otherwise, conservatively return true.
|
||||
bool MacroArgs::ArgNeedsPreexpansion(const Token *ArgTok,
|
||||
Preprocessor &PP) 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->isNot(tok::eof); ++ArgTok)
|
||||
if (IdentifierInfo *II = ArgTok->getIdentifierInfo()) {
|
||||
if (II->hasMacroDefinition() && PP.getMacroInfo(II)->isEnabled())
|
||||
// Return true even though the macro could be a function-like macro
|
||||
// without a following '(' token.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// getPreExpArgument - Return the pre-expanded form of the specified
|
||||
/// argument.
|
||||
const std::vector<Token> &
|
||||
MacroArgs::getPreExpArgument(unsigned Arg, Preprocessor &PP) {
|
||||
assert(Arg < NumUnexpArgTokens && "Invalid argument number!");
|
||||
|
||||
// If we have already computed this, return it.
|
||||
if (PreExpArgTokens.empty())
|
||||
PreExpArgTokens.resize(NumUnexpArgTokens);
|
||||
|
||||
std::vector<Token> &Result = PreExpArgTokens[Arg];
|
||||
if (!Result.empty()) return Result;
|
||||
|
||||
const Token *AT = getUnexpArgument(Arg);
|
||||
unsigned NumToks = getArgLength(AT)+1; // Include the EOF.
|
||||
|
||||
// Otherwise, we have to pre-expand this argument, populating Result. To do
|
||||
// this, we set up a fake MacroExpander to lex from the unexpanded argument
|
||||
// list. With this installed, we lex expanded tokens until we hit the EOF
|
||||
// token at the end of the unexp list.
|
||||
PP.EnterTokenStream(AT, NumToks);
|
||||
|
||||
// Lex all of the macro-expanded tokens into Result.
|
||||
do {
|
||||
Result.push_back(Token());
|
||||
PP.Lex(Result.back());
|
||||
} while (Result.back().isNot(tok::eof));
|
||||
|
||||
// Pop the token stream off the top of the stack. We know that the internal
|
||||
// pointer inside of it is to the "end" of the token stream, but the stack
|
||||
// will not otherwise be popped until the next token is lexed. The problem is
|
||||
// that the token may be lexed sometime after the vector of tokens itself is
|
||||
// destroyed, which would be badness.
|
||||
PP.RemoveTopOfLexerStack();
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
/// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of
|
||||
/// tokens into the literal string token that should be produced by the C #
|
||||
/// preprocessor operator.
|
||||
///
|
||||
static Token StringifyArgument(const Token *ArgToks,
|
||||
Preprocessor &PP, bool Charify = false) {
|
||||
Token Tok;
|
||||
Tok.startToken();
|
||||
Tok.setKind(tok::string_literal);
|
||||
|
||||
const Token *ArgTokStart = ArgToks;
|
||||
|
||||
// Stringify all the tokens.
|
||||
std::string Result = "\"";
|
||||
// FIXME: Optimize this loop to not use std::strings.
|
||||
bool isFirst = true;
|
||||
for (; ArgToks->isNot(tok::eof); ++ArgToks) {
|
||||
const Token &Tok = *ArgToks;
|
||||
if (!isFirst && (Tok.hasLeadingSpace() || Tok.isAtStartOfLine()))
|
||||
Result += ' ';
|
||||
isFirst = false;
|
||||
|
||||
// If this is a string or character constant, escape the token as specified
|
||||
// by 6.10.3.2p2.
|
||||
if (Tok.is(tok::string_literal) || // "foo"
|
||||
Tok.is(tok::wide_string_literal) || // L"foo"
|
||||
Tok.is(tok::char_constant)) { // 'x' and L'x'.
|
||||
Result += Lexer::Stringify(PP.getSpelling(Tok));
|
||||
} else {
|
||||
// Otherwise, just append the token.
|
||||
Result += PP.getSpelling(Tok);
|
||||
}
|
||||
}
|
||||
|
||||
// If the last character of the string is a \, and if it isn't escaped, this
|
||||
// is an invalid string literal, diagnose it as specified in C99.
|
||||
if (Result[Result.size()-1] == '\\') {
|
||||
// Count the number of consequtive \ characters. If even, then they are
|
||||
// just escaped backslashes, otherwise it's an error.
|
||||
unsigned FirstNonSlash = Result.size()-2;
|
||||
// Guaranteed to find the starting " if nothing else.
|
||||
while (Result[FirstNonSlash] == '\\')
|
||||
--FirstNonSlash;
|
||||
if ((Result.size()-1-FirstNonSlash) & 1) {
|
||||
// Diagnose errors for things like: #define F(X) #X / F(\)
|
||||
PP.Diag(ArgToks[-1], diag::pp_invalid_string_literal);
|
||||
Result.erase(Result.end()-1); // remove one of the \'s.
|
||||
}
|
||||
}
|
||||
Result += '"';
|
||||
|
||||
// If this is the charify operation and the result is not a legal character
|
||||
// constant, diagnose it.
|
||||
if (Charify) {
|
||||
// First step, turn double quotes into single quotes:
|
||||
Result[0] = '\'';
|
||||
Result[Result.size()-1] = '\'';
|
||||
|
||||
// Check for bogus character.
|
||||
bool isBad = false;
|
||||
if (Result.size() == 3) {
|
||||
isBad = Result[1] == '\''; // ''' is not legal. '\' already fixed above.
|
||||
} else {
|
||||
isBad = (Result.size() != 4 || Result[1] != '\\'); // Not '\x'
|
||||
}
|
||||
|
||||
if (isBad) {
|
||||
PP.Diag(ArgTokStart[0], diag::err_invalid_character_to_charify);
|
||||
Result = "' '"; // Use something arbitrary, but legal.
|
||||
}
|
||||
}
|
||||
|
||||
Tok.setLength(Result.size());
|
||||
Tok.setLocation(PP.CreateString(&Result[0], Result.size()));
|
||||
return Tok;
|
||||
}
|
||||
|
||||
/// getStringifiedArgument - Compute, cache, and return the specified argument
|
||||
/// that has been 'stringified' as required by the # operator.
|
||||
const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
|
||||
Preprocessor &PP) {
|
||||
assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!");
|
||||
if (StringifiedArgs.empty()) {
|
||||
StringifiedArgs.resize(getNumArguments());
|
||||
memset(&StringifiedArgs[0], 0,
|
||||
sizeof(StringifiedArgs[0])*getNumArguments());
|
||||
}
|
||||
if (StringifiedArgs[ArgNo].isNot(tok::string_literal))
|
||||
StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP);
|
||||
return StringifiedArgs[ArgNo];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MacroExpander Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Create a macro expander for the specified macro with the specified actual
|
||||
/// arguments. Note that this ctor takes ownership of the ActualArgs pointer.
|
||||
void MacroExpander::Init(Token &Tok, MacroArgs *Actuals) {
|
||||
// If the client is reusing a macro expander, make sure to free any memory
|
||||
// associated with it.
|
||||
destroy();
|
||||
|
||||
Macro = PP.getMacroInfo(Tok.getIdentifierInfo());
|
||||
ActualArgs = Actuals;
|
||||
CurToken = 0;
|
||||
InstantiateLoc = Tok.getLocation();
|
||||
AtStartOfLine = Tok.isAtStartOfLine();
|
||||
HasLeadingSpace = Tok.hasLeadingSpace();
|
||||
MacroTokens = &*Macro->tokens_begin();
|
||||
OwnsMacroTokens = false;
|
||||
NumMacroTokens = Macro->tokens_end()-Macro->tokens_begin();
|
||||
|
||||
// If this is a function-like macro, expand the arguments and change
|
||||
// MacroTokens to point to the expanded tokens.
|
||||
if (Macro->isFunctionLike() && Macro->getNumArgs())
|
||||
ExpandFunctionArguments();
|
||||
|
||||
// Mark the macro as currently disabled, so that it is not recursively
|
||||
// expanded. The macro must be disabled only after argument pre-expansion of
|
||||
// function-like macro arguments occurs.
|
||||
Macro->DisableMacro();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Create a macro expander for the specified token stream. This does not
|
||||
/// take ownership of the specified token vector.
|
||||
void MacroExpander::Init(const Token *TokArray, unsigned NumToks) {
|
||||
// If the client is reusing a macro expander, make sure to free any memory
|
||||
// associated with it.
|
||||
destroy();
|
||||
|
||||
Macro = 0;
|
||||
ActualArgs = 0;
|
||||
MacroTokens = TokArray;
|
||||
OwnsMacroTokens = false;
|
||||
NumMacroTokens = NumToks;
|
||||
CurToken = 0;
|
||||
InstantiateLoc = SourceLocation();
|
||||
AtStartOfLine = false;
|
||||
HasLeadingSpace = false;
|
||||
|
||||
// Set HasLeadingSpace/AtStartOfLine so that the first token will be
|
||||
// returned unmodified.
|
||||
if (NumToks != 0) {
|
||||
AtStartOfLine = TokArray[0].isAtStartOfLine();
|
||||
HasLeadingSpace = TokArray[0].hasLeadingSpace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroExpander::destroy() {
|
||||
// If this was a function-like macro that actually uses its arguments, delete
|
||||
// the expanded tokens.
|
||||
if (OwnsMacroTokens) {
|
||||
delete [] MacroTokens;
|
||||
MacroTokens = 0;
|
||||
}
|
||||
|
||||
// MacroExpander owns its formal arguments.
|
||||
if (ActualArgs) ActualArgs->destroy();
|
||||
}
|
||||
|
||||
/// Expand the arguments of a function-like macro so that we can quickly
|
||||
/// return preexpanded tokens from MacroTokens.
|
||||
void MacroExpander::ExpandFunctionArguments() {
|
||||
llvm::SmallVector<Token, 128> ResultToks;
|
||||
|
||||
// Loop through the MacroTokens tokens, expanding them into ResultToks. Keep
|
||||
// track of whether we change anything. If not, no need to keep them. If so,
|
||||
// we install the newly expanded sequence as MacroTokens.
|
||||
bool MadeChange = false;
|
||||
|
||||
// NextTokGetsSpace - When this is true, the next token appended to the
|
||||
// output list will get a leading space, regardless of whether it had one to
|
||||
// begin with or not. This is used for placemarker support.
|
||||
bool NextTokGetsSpace = false;
|
||||
|
||||
for (unsigned i = 0, e = NumMacroTokens; i != e; ++i) {
|
||||
// If we found the stringify operator, get the argument stringified. The
|
||||
// preprocessor already verified that the following token is a macro name
|
||||
// when the #define was parsed.
|
||||
const Token &CurTok = MacroTokens[i];
|
||||
if (CurTok.is(tok::hash) || CurTok.is(tok::hashat)) {
|
||||
int ArgNo = Macro->getArgumentNum(MacroTokens[i+1].getIdentifierInfo());
|
||||
assert(ArgNo != -1 && "Token following # is not an argument?");
|
||||
|
||||
Token Res;
|
||||
if (CurTok.is(tok::hash)) // Stringify
|
||||
Res = ActualArgs->getStringifiedArgument(ArgNo, PP);
|
||||
else {
|
||||
// 'charify': don't bother caching these.
|
||||
Res = StringifyArgument(ActualArgs->getUnexpArgument(ArgNo), PP, true);
|
||||
}
|
||||
|
||||
// The stringified/charified string leading space flag gets set to match
|
||||
// the #/#@ operator.
|
||||
if (CurTok.hasLeadingSpace() || NextTokGetsSpace)
|
||||
Res.setFlag(Token::LeadingSpace);
|
||||
|
||||
ResultToks.push_back(Res);
|
||||
MadeChange = true;
|
||||
++i; // Skip arg name.
|
||||
NextTokGetsSpace = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, if this is not an argument token, just add the token to the
|
||||
// output buffer.
|
||||
IdentifierInfo *II = CurTok.getIdentifierInfo();
|
||||
int ArgNo = II ? Macro->getArgumentNum(II) : -1;
|
||||
if (ArgNo == -1) {
|
||||
// This isn't an argument, just add it.
|
||||
ResultToks.push_back(CurTok);
|
||||
|
||||
if (NextTokGetsSpace) {
|
||||
ResultToks.back().setFlag(Token::LeadingSpace);
|
||||
NextTokGetsSpace = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// An argument is expanded somehow, the result is different than the
|
||||
// input.
|
||||
MadeChange = true;
|
||||
|
||||
// Otherwise, this is a use of the argument. Find out if there is a paste
|
||||
// (##) operator before or after the argument.
|
||||
bool PasteBefore =
|
||||
!ResultToks.empty() && ResultToks.back().is(tok::hashhash);
|
||||
bool PasteAfter = i+1 != e && MacroTokens[i+1].is(tok::hashhash);
|
||||
|
||||
// If it is not the LHS/RHS of a ## operator, we must pre-expand the
|
||||
// argument and substitute the expanded tokens into the result. This is
|
||||
// C99 6.10.3.1p1.
|
||||
if (!PasteBefore && !PasteAfter) {
|
||||
const Token *ResultArgToks;
|
||||
|
||||
// Only preexpand the argument if it could possibly need it. This
|
||||
// avoids some work in common cases.
|
||||
const Token *ArgTok = ActualArgs->getUnexpArgument(ArgNo);
|
||||
if (ActualArgs->ArgNeedsPreexpansion(ArgTok, PP))
|
||||
ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, PP)[0];
|
||||
else
|
||||
ResultArgToks = ArgTok; // Use non-preexpanded tokens.
|
||||
|
||||
// If the arg token expanded into anything, append it.
|
||||
if (ResultArgToks->isNot(tok::eof)) {
|
||||
unsigned FirstResult = ResultToks.size();
|
||||
unsigned NumToks = MacroArgs::getArgLength(ResultArgToks);
|
||||
ResultToks.append(ResultArgToks, ResultArgToks+NumToks);
|
||||
|
||||
// If any tokens were substituted from the argument, the whitespace
|
||||
// before the first token should match the whitespace of the arg
|
||||
// identifier.
|
||||
ResultToks[FirstResult].setFlagValue(Token::LeadingSpace,
|
||||
CurTok.hasLeadingSpace() ||
|
||||
NextTokGetsSpace);
|
||||
NextTokGetsSpace = false;
|
||||
} else {
|
||||
// If this is an empty argument, and if there was whitespace before the
|
||||
// formal token, make sure the next token gets whitespace before it.
|
||||
NextTokGetsSpace = CurTok.hasLeadingSpace();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Okay, we have a token that is either the LHS or RHS of a paste (##)
|
||||
// argument. It gets substituted as its non-pre-expanded tokens.
|
||||
const Token *ArgToks = ActualArgs->getUnexpArgument(ArgNo);
|
||||
unsigned NumToks = MacroArgs::getArgLength(ArgToks);
|
||||
if (NumToks) { // Not an empty argument?
|
||||
ResultToks.append(ArgToks, ArgToks+NumToks);
|
||||
|
||||
// If the next token was supposed to get leading whitespace, ensure it has
|
||||
// it now.
|
||||
if (NextTokGetsSpace) {
|
||||
ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace);
|
||||
NextTokGetsSpace = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If an empty argument is on the LHS or RHS of a paste, the standard (C99
|
||||
// 6.10.3.3p2,3) calls for a bunch of placemarker stuff to occur. We
|
||||
// implement this by eating ## operators when a LHS or RHS expands to
|
||||
// empty.
|
||||
NextTokGetsSpace |= CurTok.hasLeadingSpace();
|
||||
if (PasteAfter) {
|
||||
// Discard the argument token and skip (don't copy to the expansion
|
||||
// buffer) the paste operator after it.
|
||||
NextTokGetsSpace |= MacroTokens[i+1].hasLeadingSpace();
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is on the RHS of a paste operator, we've already copied the
|
||||
// paste operator to the ResultToks list. Remove it.
|
||||
assert(PasteBefore && ResultToks.back().is(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().is(tok::comma)) {
|
||||
// Never add a space, even if the comma, ##, or arg had a space.
|
||||
NextTokGetsSpace = false;
|
||||
ResultToks.pop_back();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If anything changed, install this as the new MacroTokens list.
|
||||
if (MadeChange) {
|
||||
// This is deleted in the dtor.
|
||||
NumMacroTokens = ResultToks.size();
|
||||
Token *Res = new Token[ResultToks.size()];
|
||||
if (NumMacroTokens)
|
||||
memcpy(Res, &ResultToks[0], NumMacroTokens*sizeof(Token));
|
||||
MacroTokens = Res;
|
||||
OwnsMacroTokens = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Lex - Lex and return a token from this macro stream.
|
||||
///
|
||||
void MacroExpander::Lex(Token &Tok) {
|
||||
// Lexing off the end of the macro, pop this macro off the expansion stack.
|
||||
if (isAtEnd()) {
|
||||
// If this is a macro (not a token stream), mark the macro enabled now
|
||||
// that it is no longer being expanded.
|
||||
if (Macro) Macro->EnableMacro();
|
||||
|
||||
// Pop this context off the preprocessors lexer stack and get the next
|
||||
// token. This will delete "this" so remember the PP instance var.
|
||||
Preprocessor &PPCache = PP;
|
||||
if (PP.HandleEndOfMacro(Tok))
|
||||
return;
|
||||
|
||||
// HandleEndOfMacro may not return a token. If it doesn't, lex whatever is
|
||||
// next.
|
||||
return PPCache.Lex(Tok);
|
||||
}
|
||||
|
||||
// If this is the first token of the expanded result, we inherit spacing
|
||||
// properties later.
|
||||
bool isFirstToken = CurToken == 0;
|
||||
|
||||
// Get the next token to return.
|
||||
Tok = MacroTokens[CurToken++];
|
||||
|
||||
// If this token is followed by a token paste (##) operator, paste the tokens!
|
||||
if (!isAtEnd() && MacroTokens[CurToken].is(tok::hashhash))
|
||||
PasteTokens(Tok);
|
||||
|
||||
// The token's current location indicate where the token was lexed from. We
|
||||
// need this information to compute the spelling of the token, but any
|
||||
// diagnostics for the expanded token should appear as if they came from
|
||||
// InstantiationLoc. Pull this information together into a new SourceLocation
|
||||
// that captures all of this.
|
||||
if (InstantiateLoc.isValid()) { // Don't do this for token streams.
|
||||
SourceManager &SrcMgr = PP.getSourceManager();
|
||||
Tok.setLocation(SrcMgr.getInstantiationLoc(Tok.getLocation(),
|
||||
InstantiateLoc));
|
||||
}
|
||||
|
||||
// If this is the first token, set the lexical properties of the token to
|
||||
// match the lexical properties of the macro identifier.
|
||||
if (isFirstToken) {
|
||||
Tok.setFlagValue(Token::StartOfLine , AtStartOfLine);
|
||||
Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace);
|
||||
}
|
||||
|
||||
// Handle recursive expansion!
|
||||
if (Tok.getIdentifierInfo())
|
||||
return PP.HandleIdentifier(Tok);
|
||||
|
||||
// Otherwise, return a normal token.
|
||||
}
|
||||
|
||||
/// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ##
|
||||
/// operator. Read the ## and RHS, and paste the LHS/RHS together. If there
|
||||
/// are is another ## after it, chomp it iteratively. Return the result as Tok.
|
||||
void MacroExpander::PasteTokens(Token &Tok) {
|
||||
llvm::SmallVector<char, 128> Buffer;
|
||||
do {
|
||||
// Consume the ## operator.
|
||||
SourceLocation PasteOpLoc = MacroTokens[CurToken].getLocation();
|
||||
++CurToken;
|
||||
assert(!isAtEnd() && "No token on the RHS of a paste operator!");
|
||||
|
||||
// Get the RHS token.
|
||||
const Token &RHS = MacroTokens[CurToken];
|
||||
|
||||
bool isInvalid = false;
|
||||
|
||||
// Allocate space for the result token. This is guaranteed to be enough for
|
||||
// the two tokens and a null terminator.
|
||||
Buffer.resize(Tok.getLength() + RHS.getLength() + 1);
|
||||
|
||||
// Get the spelling of the LHS token in Buffer.
|
||||
const char *BufPtr = &Buffer[0];
|
||||
unsigned LHSLen = PP.getSpelling(Tok, BufPtr);
|
||||
if (BufPtr != &Buffer[0]) // Really, we want the chars in Buffer!
|
||||
memcpy(&Buffer[0], BufPtr, LHSLen);
|
||||
|
||||
BufPtr = &Buffer[LHSLen];
|
||||
unsigned RHSLen = PP.getSpelling(RHS, BufPtr);
|
||||
if (BufPtr != &Buffer[LHSLen]) // Really, we want the chars in Buffer!
|
||||
memcpy(&Buffer[LHSLen], BufPtr, RHSLen);
|
||||
|
||||
// Add null terminator.
|
||||
Buffer[LHSLen+RHSLen] = '\0';
|
||||
|
||||
// Trim excess space.
|
||||
Buffer.resize(LHSLen+RHSLen+1);
|
||||
|
||||
// Plop the pasted result (including the trailing newline and null) into a
|
||||
// scratch buffer where we can lex it.
|
||||
SourceLocation ResultTokLoc = PP.CreateString(&Buffer[0], Buffer.size());
|
||||
|
||||
// Lex the resultant pasted token into Result.
|
||||
Token Result;
|
||||
|
||||
// Avoid testing /*, as the lexer would think it is the start of a comment
|
||||
// and emit an error that it is unterminated.
|
||||
if (Tok.is(tok::slash) && RHS.is(tok::star)) {
|
||||
isInvalid = true;
|
||||
} else if (Tok.is(tok::identifier) && RHS.is(tok::identifier)) {
|
||||
// Common paste case: identifier+identifier = identifier. Avoid creating
|
||||
// a lexer and other overhead.
|
||||
PP.IncrementPasteCounter(true);
|
||||
Result.startToken();
|
||||
Result.setKind(tok::identifier);
|
||||
Result.setLocation(ResultTokLoc);
|
||||
Result.setLength(LHSLen+RHSLen);
|
||||
} else {
|
||||
PP.IncrementPasteCounter(false);
|
||||
|
||||
// Make a lexer to lex this string from.
|
||||
SourceManager &SourceMgr = PP.getSourceManager();
|
||||
const char *ResultStrData = SourceMgr.getCharacterData(ResultTokLoc);
|
||||
|
||||
// Make a lexer object so that we lex and expand the paste result.
|
||||
Lexer *TL = new Lexer(ResultTokLoc, PP, ResultStrData,
|
||||
ResultStrData+LHSLen+RHSLen /*don't include null*/);
|
||||
|
||||
// Lex a token in raw mode. This way it won't look up identifiers
|
||||
// automatically, lexing off the end will return an eof token, and
|
||||
// warnings are disabled. This returns true if the result token is the
|
||||
// entire buffer.
|
||||
bool IsComplete = TL->LexRawToken(Result);
|
||||
|
||||
// If we got an EOF token, we didn't form even ONE token. For example, we
|
||||
// did "/ ## /" to get "//".
|
||||
IsComplete &= Result.isNot(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.is(tok::hashhash))
|
||||
Result.setKind(tok::unknown);
|
||||
// FIXME: Turn __VARRGS__ into "not a token"?
|
||||
|
||||
// Transfer properties of the LHS over the the Result.
|
||||
Result.setFlagValue(Token::StartOfLine , Tok.isAtStartOfLine());
|
||||
Result.setFlagValue(Token::LeadingSpace, Tok.hasLeadingSpace());
|
||||
|
||||
// Finally, replace LHS with the result, consume the RHS, and iterate.
|
||||
++CurToken;
|
||||
Tok = Result;
|
||||
} while (!isAtEnd() && MacroTokens[CurToken].is(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.is(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].is(tok::l_paren);
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
//===--- MacroInfo.cpp - Information about #defined identifiers -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the MacroInfo interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
using namespace clang;
|
||||
|
||||
MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
|
||||
IsFunctionLike = false;
|
||||
IsC99Varargs = false;
|
||||
IsGNUVarargs = false;
|
||||
IsBuiltinMacro = false;
|
||||
IsTargetSpecific = false;
|
||||
IsDisabled = false;
|
||||
IsUsed = true;
|
||||
|
||||
ArgumentList = 0;
|
||||
NumArguments = 0;
|
||||
}
|
||||
|
||||
/// isIdenticalTo - Return true if the specified macro definition is equal to
|
||||
/// this macro in spelling, arguments, and whitespace. This is used to emit
|
||||
/// duplicate definition warnings. This implements the rules in C99 6.10.3.
|
||||
///
|
||||
/// Note that this intentionally does not check isTargetSpecific for matching.
|
||||
///
|
||||
bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
|
||||
// Check # tokens in replacement, number of args, and various flags all match.
|
||||
if (ReplacementTokens.size() != Other.ReplacementTokens.size() ||
|
||||
getNumArgs() != Other.getNumArgs() ||
|
||||
isFunctionLike() != Other.isFunctionLike() ||
|
||||
isC99Varargs() != Other.isC99Varargs() ||
|
||||
isGNUVarargs() != Other.isGNUVarargs())
|
||||
return false;
|
||||
|
||||
// Check arguments.
|
||||
for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end();
|
||||
I != E; ++I, ++OI)
|
||||
if (*I != *OI) return false;
|
||||
|
||||
// Check all the tokens.
|
||||
for (unsigned i = 0, e = ReplacementTokens.size(); i != e; ++i) {
|
||||
const Token &A = ReplacementTokens[i];
|
||||
const Token &B = Other.ReplacementTokens[i];
|
||||
if (A.getKind() != B.getKind() ||
|
||||
A.isAtStartOfLine() != B.isAtStartOfLine() ||
|
||||
A.hasLeadingSpace() != B.hasLeadingSpace())
|
||||
return false;
|
||||
|
||||
// If this is an identifier, it is easy.
|
||||
if (A.getIdentifierInfo() || B.getIdentifierInfo()) {
|
||||
if (A.getIdentifierInfo() != B.getIdentifierInfo())
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, check the spelling.
|
||||
if (PP.getSpelling(A) != PP.getSpelling(B))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
##===- clang/Lex/Makefile ----------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# This implements the Lexer library for the C-Language front-end.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../..
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
LIBRARYNAME := clangLex
|
||||
BUILD_ARCHIVE = 1
|
||||
CXXFLAGS = -fno-rtti
|
||||
|
||||
ifeq ($(ARCH),PowerPC)
|
||||
CXXFLAGS += -maltivec
|
||||
endif
|
||||
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
@@ -1,664 +0,0 @@
|
||||
//===--- PPExpressions.cpp - Preprocessor Expression Evaluation -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the Preprocessor::EvaluateDirectiveExpression method,
|
||||
// which parses and evaluates integer constant expressions for #if directives.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// FIXME: implement testing for #assert's.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "clang/Lex/LiteralSupport.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
using namespace clang;
|
||||
|
||||
static bool EvaluateDirectiveSubExpr(llvm::APSInt &LHS, unsigned MinPrec,
|
||||
Token &PeekTok, bool ValueLive,
|
||||
Preprocessor &PP);
|
||||
|
||||
/// DefinedTracker - This struct is used while parsing expressions to keep track
|
||||
/// of whether !defined(X) has been seen.
|
||||
///
|
||||
/// With this simple scheme, we handle the basic forms:
|
||||
/// !defined(X) and !defined X
|
||||
/// but we also trivially handle (silly) stuff like:
|
||||
/// !!!defined(X) and +!defined(X) and !+!+!defined(X) and !(defined(X)).
|
||||
struct DefinedTracker {
|
||||
/// Each time a Value is evaluated, it returns information about whether the
|
||||
/// parsed value is of the form defined(X), !defined(X) or is something else.
|
||||
enum TrackerState {
|
||||
DefinedMacro, // defined(X)
|
||||
NotDefinedMacro, // !defined(X)
|
||||
Unknown // Something else.
|
||||
} State;
|
||||
/// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this
|
||||
/// indicates the macro that was checked.
|
||||
IdentifierInfo *TheMacro;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// EvaluateValue - Evaluate the token PeekTok (and any others needed) and
|
||||
/// return the computed value in Result. Return true if there was an error
|
||||
/// parsing. This function also returns information about the form of the
|
||||
/// expression in DT. See above for information on what DT means.
|
||||
///
|
||||
/// If ValueLive is false, then this value is being evaluated in a context where
|
||||
/// the result is not used. As such, avoid diagnostics that relate to
|
||||
/// evaluation.
|
||||
static bool EvaluateValue(llvm::APSInt &Result, Token &PeekTok,
|
||||
DefinedTracker &DT, bool ValueLive,
|
||||
Preprocessor &PP) {
|
||||
Result = 0;
|
||||
DT.State = DefinedTracker::Unknown;
|
||||
|
||||
// If this token's spelling is a pp-identifier, check to see if it is
|
||||
// 'defined' or if it is a macro. Note that we check here because many
|
||||
// keywords are pp-identifiers, so we can't check the kind.
|
||||
if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) {
|
||||
// If this identifier isn't 'defined' and it wasn't macro expanded, it turns
|
||||
// into a simple 0, unless it is the C++ keyword "true", in which case it
|
||||
// turns into "1".
|
||||
if (II->getPPKeywordID() != tok::pp_defined) {
|
||||
Result = II->getTokenID() == tok::kw_true;
|
||||
Result.setIsUnsigned(false); // "0" is signed intmax_t 0.
|
||||
PP.LexNonComment(PeekTok);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle "defined X" and "defined(X)".
|
||||
|
||||
// Get the next token, don't expand it.
|
||||
PP.LexUnexpandedToken(PeekTok);
|
||||
|
||||
// Two options, it can either be a pp-identifier or a (.
|
||||
bool InParens = false;
|
||||
if (PeekTok.is(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->hasMacroDefinition();
|
||||
Result.setIsUnsigned(false); // Result is signed intmax_t.
|
||||
|
||||
// If there is a macro, mark it used.
|
||||
if (Result != 0 && ValueLive) {
|
||||
MacroInfo *Macro = PP.getMacroInfo(II);
|
||||
Macro->setIsUsed(true);
|
||||
|
||||
// If this is the first use of a target-specific macro, warn about it.
|
||||
if (Macro->isTargetSpecific()) {
|
||||
// Don't warn on second use.
|
||||
Macro->setIsTargetSpecific(false);
|
||||
PP.getTargetInfo().DiagnoseNonPortability(
|
||||
PP.getFullLoc(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(
|
||||
PP.getFullLoc(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.isNot(tok::r_paren)) {
|
||||
PP.Diag(PeekTok, diag::err_pp_missing_rparen);
|
||||
return true;
|
||||
}
|
||||
// Consume the ).
|
||||
PP.LexNonComment(PeekTok);
|
||||
}
|
||||
|
||||
// Success, remember that we saw defined(X).
|
||||
DT.State = DefinedTracker::DefinedMacro;
|
||||
DT.TheMacro = II;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (PeekTok.getKind()) {
|
||||
default: // Non-value token.
|
||||
PP.Diag(PeekTok, diag::err_pp_expr_bad_token);
|
||||
return true;
|
||||
case tok::eom:
|
||||
case tok::r_paren:
|
||||
// If there is no expression, report and exit.
|
||||
PP.Diag(PeekTok, diag::err_pp_expected_value_in_expr);
|
||||
return true;
|
||||
case tok::numeric_constant: {
|
||||
llvm::SmallString<64> IntegerBuffer;
|
||||
IntegerBuffer.resize(PeekTok.getLength());
|
||||
const char *ThisTokBegin = &IntegerBuffer[0];
|
||||
unsigned ActualLength = PP.getSpelling(PeekTok, ThisTokBegin);
|
||||
NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
|
||||
PeekTok.getLocation(), PP);
|
||||
if (Literal.hadError)
|
||||
return true; // a diagnostic was already reported.
|
||||
|
||||
if (Literal.isFloatingLiteral() || Literal.isImaginary) {
|
||||
PP.Diag(PeekTok, diag::err_pp_illegal_floating_literal);
|
||||
return true;
|
||||
}
|
||||
assert(Literal.isIntegerLiteral() && "Unknown ppnumber");
|
||||
|
||||
// long long is a C99 feature.
|
||||
if (!PP.getLangOptions().C99 && !PP.getLangOptions().CPlusPlus0x
|
||||
&& Literal.isLongLong)
|
||||
PP.Diag(PeekTok, diag::ext_longlong);
|
||||
|
||||
// Parse the integer literal into Result.
|
||||
if (Literal.GetIntegerValue(Result)) {
|
||||
// Overflow parsing integer literal.
|
||||
if (ValueLive) PP.Diag(PeekTok, diag::warn_integer_too_large);
|
||||
Result.setIsUnsigned(true);
|
||||
} else {
|
||||
// Set the signedness of the result to match whether there was a U suffix
|
||||
// or not.
|
||||
Result.setIsUnsigned(Literal.isUnsigned);
|
||||
|
||||
// Detect overflow based on whether the value is signed. If signed
|
||||
// and if the value is too large, emit a warning "integer constant is so
|
||||
// large that it is unsigned" e.g. on 12345678901234567890 where intmax_t
|
||||
// is 64-bits.
|
||||
if (!Literal.isUnsigned && Result.isNegative()) {
|
||||
if (ValueLive)PP.Diag(PeekTok, diag::warn_integer_too_large_for_signed);
|
||||
Result.setIsUnsigned(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Consume the token.
|
||||
PP.LexNonComment(PeekTok);
|
||||
return false;
|
||||
}
|
||||
case tok::char_constant: { // 'x'
|
||||
llvm::SmallString<32> CharBuffer;
|
||||
CharBuffer.resize(PeekTok.getLength());
|
||||
const char *ThisTokBegin = &CharBuffer[0];
|
||||
unsigned ActualLength = PP.getSpelling(PeekTok, ThisTokBegin);
|
||||
CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
|
||||
PeekTok.getLocation(), PP);
|
||||
if (Literal.hadError())
|
||||
return true; // A diagnostic was already emitted.
|
||||
|
||||
// Character literals are always int or wchar_t, expand to intmax_t.
|
||||
TargetInfo &TI = PP.getTargetInfo();
|
||||
unsigned NumBits;
|
||||
if (Literal.isWide())
|
||||
NumBits = TI.getWCharWidth(PP.getFullLoc(PeekTok.getLocation()));
|
||||
else
|
||||
NumBits = TI.getCharWidth(PP.getFullLoc(PeekTok.getLocation()));
|
||||
|
||||
// Set the width.
|
||||
llvm::APSInt Val(NumBits);
|
||||
// Set the value.
|
||||
Val = Literal.getValue();
|
||||
// Set the signedness.
|
||||
Val.setIsUnsigned(!TI.isCharSigned(PP.getFullLoc(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.is(tok::r_paren)) {
|
||||
// Just use DT unmodified as our result.
|
||||
} else {
|
||||
if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP))
|
||||
return true;
|
||||
|
||||
if (PeekTok.isNot(tok::r_paren)) {
|
||||
PP.Diag(PeekTok, diag::err_pp_expected_rparen);
|
||||
return true;
|
||||
}
|
||||
DT.State = DefinedTracker::Unknown;
|
||||
}
|
||||
PP.LexNonComment(PeekTok); // Eat the ).
|
||||
return false;
|
||||
|
||||
case tok::plus:
|
||||
// Unary plus doesn't modify the value.
|
||||
PP.LexNonComment(PeekTok);
|
||||
return EvaluateValue(Result, PeekTok, DT, ValueLive, PP);
|
||||
case tok::minus: {
|
||||
SourceLocation Loc = PeekTok.getLocation();
|
||||
PP.LexNonComment(PeekTok);
|
||||
if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
|
||||
// C99 6.5.3.3p3: The sign of the result matches the sign of the operand.
|
||||
Result = -Result;
|
||||
|
||||
bool Overflow = false;
|
||||
if (Result.isUnsigned())
|
||||
Overflow = !Result.isPositive();
|
||||
else if (Result.isMinSignedValue())
|
||||
Overflow = true; // -MININT is the only thing that overflows.
|
||||
|
||||
// If this operator is live and overflowed, report the issue.
|
||||
if (Overflow && ValueLive)
|
||||
PP.Diag(Loc, diag::warn_pp_expr_overflow);
|
||||
|
||||
DT.State = DefinedTracker::Unknown;
|
||||
return false;
|
||||
}
|
||||
|
||||
case tok::tilde:
|
||||
PP.LexNonComment(PeekTok);
|
||||
if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
|
||||
// C99 6.5.3.3p4: The sign of the result matches the sign of the operand.
|
||||
Result = ~Result;
|
||||
DT.State = DefinedTracker::Unknown;
|
||||
return false;
|
||||
|
||||
case tok::exclaim:
|
||||
PP.LexNonComment(PeekTok);
|
||||
if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
|
||||
Result = !Result;
|
||||
// C99 6.5.3.3p5: The sign of the result is 'int', aka it is signed.
|
||||
Result.setIsUnsigned(false);
|
||||
|
||||
if (DT.State == DefinedTracker::DefinedMacro)
|
||||
DT.State = DefinedTracker::NotDefinedMacro;
|
||||
else if (DT.State == DefinedTracker::NotDefinedMacro)
|
||||
DT.State = DefinedTracker::DefinedMacro;
|
||||
return false;
|
||||
|
||||
// FIXME: Handle #assert
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// getPrecedence - Return the precedence of the specified binary operator
|
||||
/// token. This returns:
|
||||
/// ~0 - Invalid token.
|
||||
/// 14 - *,/,%
|
||||
/// 13 - -,+
|
||||
/// 12 - <<,>>
|
||||
/// 11 - >=, <=, >, <
|
||||
/// 10 - ==, !=
|
||||
/// 9 - &
|
||||
/// 8 - ^
|
||||
/// 7 - |
|
||||
/// 6 - &&
|
||||
/// 5 - ||
|
||||
/// 4 - ?
|
||||
/// 3 - :
|
||||
/// 0 - eom, )
|
||||
static unsigned getPrecedence(tok::TokenKind Kind) {
|
||||
switch (Kind) {
|
||||
default: return ~0U;
|
||||
case tok::percent:
|
||||
case tok::slash:
|
||||
case tok::star: return 14;
|
||||
case tok::plus:
|
||||
case tok::minus: return 13;
|
||||
case tok::lessless:
|
||||
case tok::greatergreater: return 12;
|
||||
case tok::lessequal:
|
||||
case tok::less:
|
||||
case tok::greaterequal:
|
||||
case tok::greater: return 11;
|
||||
case tok::exclaimequal:
|
||||
case tok::equalequal: return 10;
|
||||
case tok::amp: return 9;
|
||||
case tok::caret: return 8;
|
||||
case tok::pipe: return 7;
|
||||
case tok::ampamp: return 6;
|
||||
case tok::pipepipe: return 5;
|
||||
case tok::question: return 4;
|
||||
case tok::colon: return 3;
|
||||
case tok::comma: return 2;
|
||||
case tok::r_paren: return 0; // Lowest priority, end of expr.
|
||||
case tok::eom: return 0; // Lowest priority, end of macro.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// EvaluateDirectiveSubExpr - Evaluate the subexpression whose first token is
|
||||
/// PeekTok, and whose precedence is PeekPrec.
|
||||
///
|
||||
/// If ValueLive is false, then this value is being evaluated in a context where
|
||||
/// the result is not used. As such, avoid diagnostics that relate to
|
||||
/// evaluation.
|
||||
static bool EvaluateDirectiveSubExpr(llvm::APSInt &LHS, unsigned MinPrec,
|
||||
Token &PeekTok, bool ValueLive,
|
||||
Preprocessor &PP) {
|
||||
unsigned PeekPrec = getPrecedence(PeekTok.getKind());
|
||||
// If this token isn't valid, report the error.
|
||||
if (PeekPrec == ~0U) {
|
||||
PP.Diag(PeekTok, diag::err_pp_expr_bad_token);
|
||||
return true;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
// If this token has a lower precedence than we are allowed to parse, return
|
||||
// it so that higher levels of the recursion can parse it.
|
||||
if (PeekPrec < MinPrec)
|
||||
return false;
|
||||
|
||||
tok::TokenKind Operator = PeekTok.getKind();
|
||||
|
||||
// If this is a short-circuiting operator, see if the RHS of the operator is
|
||||
// dead. Note that this cannot just clobber ValueLive. Consider
|
||||
// "0 && 1 ? 4 : 1 / 0", which is parsed as "(0 && 1) ? 4 : (1 / 0)". In
|
||||
// this example, the RHS of the && being dead does not make the rest of the
|
||||
// expr dead.
|
||||
bool RHSIsLive;
|
||||
if (Operator == tok::ampamp && LHS == 0)
|
||||
RHSIsLive = false; // RHS of "0 && x" is dead.
|
||||
else if (Operator == tok::pipepipe && LHS != 0)
|
||||
RHSIsLive = false; // RHS of "1 || x" is dead.
|
||||
else if (Operator == tok::question && LHS == 0)
|
||||
RHSIsLive = false; // RHS (x) of "0 ? x : y" is dead.
|
||||
else
|
||||
RHSIsLive = ValueLive;
|
||||
|
||||
// Consume the operator, saving the operator token for error reporting.
|
||||
Token OpToken = PeekTok;
|
||||
PP.LexNonComment(PeekTok);
|
||||
|
||||
llvm::APSInt RHS(LHS.getBitWidth());
|
||||
// Parse the RHS of the operator.
|
||||
DefinedTracker DT;
|
||||
if (EvaluateValue(RHS, PeekTok, DT, RHSIsLive, PP)) return true;
|
||||
|
||||
// Remember the precedence of this operator and get the precedence of the
|
||||
// operator immediately to the right of the RHS.
|
||||
unsigned ThisPrec = PeekPrec;
|
||||
PeekPrec = getPrecedence(PeekTok.getKind());
|
||||
|
||||
// If this token isn't valid, report the error.
|
||||
if (PeekPrec == ~0U) {
|
||||
PP.Diag(PeekTok, diag::err_pp_expr_bad_token);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isRightAssoc = Operator == tok::question;
|
||||
|
||||
// Get the precedence of the operator to the right of the RHS. If it binds
|
||||
// more tightly with RHS than we do, evaluate it completely first.
|
||||
if (ThisPrec < PeekPrec ||
|
||||
(ThisPrec == PeekPrec && isRightAssoc)) {
|
||||
if (EvaluateDirectiveSubExpr(RHS, ThisPrec+1, PeekTok, RHSIsLive, PP))
|
||||
return true;
|
||||
PeekPrec = getPrecedence(PeekTok.getKind());
|
||||
}
|
||||
assert(PeekPrec <= ThisPrec && "Recursion didn't work!");
|
||||
|
||||
// Usual arithmetic conversions (C99 6.3.1.8p1): result is unsigned if
|
||||
// either operand is unsigned. Don't do this for x and y in "x ? y : z".
|
||||
llvm::APSInt Res(LHS.getBitWidth());
|
||||
if (Operator != tok::question) {
|
||||
Res.setIsUnsigned(LHS.isUnsigned()|RHS.isUnsigned());
|
||||
// If this just promoted something from signed to unsigned, and if the
|
||||
// value was negative, warn about it.
|
||||
if (ValueLive && Res.isUnsigned()) {
|
||||
if (!LHS.isUnsigned() && LHS.isNegative())
|
||||
PP.Diag(OpToken, diag::warn_pp_convert_lhs_to_positive,
|
||||
LHS.toStringSigned() + " to " + LHS.toStringUnsigned());
|
||||
if (!RHS.isUnsigned() && RHS.isNegative())
|
||||
PP.Diag(OpToken, diag::warn_pp_convert_rhs_to_positive,
|
||||
RHS.toStringSigned() + " to " + RHS.toStringUnsigned());
|
||||
}
|
||||
LHS.setIsUnsigned(Res.isUnsigned());
|
||||
RHS.setIsUnsigned(Res.isUnsigned());
|
||||
}
|
||||
|
||||
// FIXME: All of these should detect and report overflow??
|
||||
bool Overflow = false;
|
||||
switch (Operator) {
|
||||
default: assert(0 && "Unknown operator token!");
|
||||
case tok::percent:
|
||||
if (RHS == 0) {
|
||||
if (ValueLive) PP.Diag(OpToken, diag::err_pp_remainder_by_zero);
|
||||
return true;
|
||||
}
|
||||
Res = LHS % RHS;
|
||||
break;
|
||||
case tok::slash:
|
||||
if (RHS == 0) {
|
||||
if (ValueLive) PP.Diag(OpToken, diag::err_pp_division_by_zero);
|
||||
return true;
|
||||
}
|
||||
Res = LHS / RHS;
|
||||
if (LHS.isSigned())
|
||||
Overflow = LHS.isMinSignedValue() && RHS.isAllOnesValue(); // MININT/-1
|
||||
break;
|
||||
case tok::star:
|
||||
Res = LHS * RHS;
|
||||
if (LHS != 0 && RHS != 0)
|
||||
Overflow = Res/RHS != LHS || Res/LHS != RHS;
|
||||
break;
|
||||
case tok::lessless: {
|
||||
// Determine whether overflow is about to happen.
|
||||
unsigned ShAmt = static_cast<unsigned>(RHS.getLimitedValue());
|
||||
if (ShAmt >= LHS.getBitWidth())
|
||||
Overflow = true, ShAmt = LHS.getBitWidth()-1;
|
||||
else if (LHS.isUnsigned())
|
||||
Overflow = ShAmt > LHS.countLeadingZeros();
|
||||
else if (LHS.isPositive())
|
||||
Overflow = ShAmt >= LHS.countLeadingZeros(); // Don't allow sign change.
|
||||
else
|
||||
Overflow = ShAmt >= LHS.countLeadingOnes();
|
||||
|
||||
Res = LHS << ShAmt;
|
||||
break;
|
||||
}
|
||||
case tok::greatergreater: {
|
||||
// Determine whether overflow is about to happen.
|
||||
unsigned ShAmt = static_cast<unsigned>(RHS.getLimitedValue());
|
||||
if (ShAmt >= LHS.getBitWidth())
|
||||
Overflow = true, ShAmt = LHS.getBitWidth()-1;
|
||||
Res = LHS >> ShAmt;
|
||||
break;
|
||||
}
|
||||
case tok::plus:
|
||||
Res = LHS + RHS;
|
||||
if (LHS.isUnsigned())
|
||||
Overflow = Res.ult(LHS);
|
||||
else if (LHS.isPositive() == RHS.isPositive() &&
|
||||
Res.isPositive() != LHS.isPositive())
|
||||
Overflow = true; // Overflow for signed addition.
|
||||
break;
|
||||
case tok::minus:
|
||||
Res = LHS - RHS;
|
||||
if (LHS.isUnsigned())
|
||||
Overflow = Res.ugt(LHS);
|
||||
else if (LHS.isPositive() != RHS.isPositive() &&
|
||||
Res.isPositive() != LHS.isPositive())
|
||||
Overflow = true; // Overflow for signed subtraction.
|
||||
break;
|
||||
case tok::lessequal:
|
||||
Res = LHS <= RHS;
|
||||
Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed)
|
||||
break;
|
||||
case tok::less:
|
||||
Res = LHS < RHS;
|
||||
Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed)
|
||||
break;
|
||||
case tok::greaterequal:
|
||||
Res = LHS >= RHS;
|
||||
Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed)
|
||||
break;
|
||||
case tok::greater:
|
||||
Res = LHS > RHS;
|
||||
Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed)
|
||||
break;
|
||||
case tok::exclaimequal:
|
||||
Res = LHS != RHS;
|
||||
Res.setIsUnsigned(false); // C99 6.5.9p3, result is always int (signed)
|
||||
break;
|
||||
case tok::equalequal:
|
||||
Res = LHS == RHS;
|
||||
Res.setIsUnsigned(false); // C99 6.5.9p3, result is always int (signed)
|
||||
break;
|
||||
case tok::amp:
|
||||
Res = LHS & RHS;
|
||||
break;
|
||||
case tok::caret:
|
||||
Res = LHS ^ RHS;
|
||||
break;
|
||||
case tok::pipe:
|
||||
Res = LHS | RHS;
|
||||
break;
|
||||
case tok::ampamp:
|
||||
Res = (LHS != 0 && RHS != 0);
|
||||
Res.setIsUnsigned(false); // C99 6.5.13p3, result is always int (signed)
|
||||
break;
|
||||
case tok::pipepipe:
|
||||
Res = (LHS != 0 || RHS != 0);
|
||||
Res.setIsUnsigned(false); // C99 6.5.14p3, result is always int (signed)
|
||||
break;
|
||||
case tok::comma:
|
||||
PP.Diag(OpToken, diag::ext_pp_comma_expr);
|
||||
Res = RHS; // LHS = LHS,RHS -> RHS.
|
||||
break;
|
||||
case tok::question: {
|
||||
// Parse the : part of the expression.
|
||||
if (PeekTok.isNot(tok::colon)) {
|
||||
PP.Diag(OpToken, diag::err_pp_question_without_colon);
|
||||
return true;
|
||||
}
|
||||
// Consume the :.
|
||||
PP.LexNonComment(PeekTok);
|
||||
|
||||
// Evaluate the value after the :.
|
||||
bool AfterColonLive = ValueLive && LHS == 0;
|
||||
llvm::APSInt AfterColonVal(LHS.getBitWidth());
|
||||
DefinedTracker DT;
|
||||
if (EvaluateValue(AfterColonVal, PeekTok, DT, AfterColonLive, PP))
|
||||
return true;
|
||||
|
||||
// Parse anything after the : RHS that has a higher precedence than ?.
|
||||
if (EvaluateDirectiveSubExpr(AfterColonVal, ThisPrec+1,
|
||||
PeekTok, AfterColonLive, PP))
|
||||
return true;
|
||||
|
||||
// Now that we have the condition, the LHS and the RHS of the :, evaluate.
|
||||
Res = LHS != 0 ? RHS : AfterColonVal;
|
||||
|
||||
// Usual arithmetic conversions (C99 6.3.1.8p1): result is unsigned if
|
||||
// either operand is unsigned.
|
||||
Res.setIsUnsigned(RHS.isUnsigned() | AfterColonVal.isUnsigned());
|
||||
|
||||
// Figure out the precedence of the token after the : part.
|
||||
PeekPrec = getPrecedence(PeekTok.getKind());
|
||||
break;
|
||||
}
|
||||
case tok::colon:
|
||||
// Don't allow :'s to float around without being part of ?: exprs.
|
||||
PP.Diag(OpToken, diag::err_pp_colon_without_question);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this operator is live and overflowed, report the issue.
|
||||
if (Overflow && ValueLive)
|
||||
PP.Diag(OpToken, diag::warn_pp_expr_overflow);
|
||||
|
||||
// Put the result back into 'LHS' for our next iteration.
|
||||
LHS = Res;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// EvaluateDirectiveExpression - Evaluate an integer constant expression that
|
||||
/// may occur after a #if or #elif directive. If the expression is equivalent
|
||||
/// to "!defined(X)" return X in IfNDefMacro.
|
||||
bool Preprocessor::
|
||||
EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
|
||||
// Peek ahead one token.
|
||||
Token Tok;
|
||||
Lex(Tok);
|
||||
|
||||
// C99 6.10.1p3 - All expressions are evaluated as intmax_t or uintmax_t.
|
||||
unsigned BitWidth =
|
||||
getTargetInfo().getIntMaxTWidth(getFullLoc(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.isNot(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.is(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.isNot(tok::eom))
|
||||
DiscardUntilEndOfDirective();
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we aren't at the tok::eom token, something bad happened, like an extra
|
||||
// ')' token.
|
||||
if (Tok.isNot(tok::eom)) {
|
||||
Diag(Tok, diag::err_pp_expected_eol);
|
||||
DiscardUntilEndOfDirective();
|
||||
}
|
||||
|
||||
return ResVal != 0;
|
||||
}
|
||||
|
||||
@@ -1,386 +0,0 @@
|
||||
//===--- Pragma.cpp - Pragma registration and handling --------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the PragmaHandler/PragmaTable interfaces and implements
|
||||
// pragma related methods of the Preprocessor class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Lex/Pragma.h"
|
||||
#include "clang/Lex/PPCallbacks.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
using namespace clang;
|
||||
|
||||
// Out-of-line destructor to provide a home for the class.
|
||||
PragmaHandler::~PragmaHandler() {
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// PragmaNamespace Implementation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
PragmaNamespace::~PragmaNamespace() {
|
||||
for (unsigned i = 0, e = Handlers.size(); i != e; ++i)
|
||||
delete Handlers[i];
|
||||
}
|
||||
|
||||
/// FindHandler - Check to see if there is already a handler for the
|
||||
/// specified name. If not, return the handler for the null identifier if it
|
||||
/// exists, otherwise return null. If IgnoreNull is true (the default) then
|
||||
/// the null handler isn't returned on failure to match.
|
||||
PragmaHandler *PragmaNamespace::FindHandler(const IdentifierInfo *Name,
|
||||
bool IgnoreNull) const {
|
||||
PragmaHandler *NullHandler = 0;
|
||||
for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
|
||||
if (Handlers[i]->getName() == Name)
|
||||
return Handlers[i];
|
||||
|
||||
if (Handlers[i]->getName() == 0)
|
||||
NullHandler = Handlers[i];
|
||||
}
|
||||
return IgnoreNull ? 0 : NullHandler;
|
||||
}
|
||||
|
||||
void PragmaNamespace::HandlePragma(Preprocessor &PP, Token &Tok) {
|
||||
// Read the 'namespace' that the directive is in, e.g. STDC. Do not macro
|
||||
// expand it, the user can have a STDC #define, that should not affect this.
|
||||
PP.LexUnexpandedToken(Tok);
|
||||
|
||||
// Get the handler for this token. If there is no handler, ignore the pragma.
|
||||
PragmaHandler *Handler = FindHandler(Tok.getIdentifierInfo(), false);
|
||||
if (Handler == 0) return;
|
||||
|
||||
// Otherwise, pass it down.
|
||||
Handler->HandlePragma(PP, Tok);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Preprocessor Pragma Directive Handling.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// HandlePragmaDirective - The "#pragma" directive has been parsed. Lex the
|
||||
/// rest of the pragma, passing it to the registered pragma handlers.
|
||||
void Preprocessor::HandlePragmaDirective() {
|
||||
++NumPragma;
|
||||
|
||||
// Invoke the first level of pragma handlers which reads the namespace id.
|
||||
Token Tok;
|
||||
PragmaHandlers->HandlePragma(*this, Tok);
|
||||
|
||||
// If the pragma handler didn't read the rest of the line, consume it now.
|
||||
if (CurLexer->ParsingPreprocessorDirective)
|
||||
DiscardUntilEndOfDirective();
|
||||
}
|
||||
|
||||
/// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then
|
||||
/// return the first token after the directive. The _Pragma token has just
|
||||
/// been read into 'Tok'.
|
||||
void Preprocessor::Handle_Pragma(Token &Tok) {
|
||||
// Remember the pragma token location.
|
||||
SourceLocation PragmaLoc = Tok.getLocation();
|
||||
|
||||
// Read the '('.
|
||||
Lex(Tok);
|
||||
if (Tok.isNot(tok::l_paren))
|
||||
return Diag(PragmaLoc, diag::err__Pragma_malformed);
|
||||
|
||||
// Read the '"..."'.
|
||||
Lex(Tok);
|
||||
if (Tok.isNot(tok::string_literal) && Tok.isNot(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.isNot(tok::r_paren))
|
||||
return Diag(PragmaLoc, diag::err__Pragma_malformed);
|
||||
|
||||
// The _Pragma is lexically sound. Destringize according to C99 6.10.9.1.
|
||||
if (StrVal[0] == 'L') // Remove L prefix.
|
||||
StrVal.erase(StrVal.begin());
|
||||
assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' &&
|
||||
"Invalid string token!");
|
||||
|
||||
// Remove the front quote, replacing it with a space, so that the pragma
|
||||
// contents appear to have a space before them.
|
||||
StrVal[0] = ' ';
|
||||
|
||||
// Replace the terminating quote with a \n\0.
|
||||
StrVal[StrVal.size()-1] = '\n';
|
||||
StrVal += '\0';
|
||||
|
||||
// Remove escaped quotes and escapes.
|
||||
for (unsigned i = 0, e = StrVal.size(); i != e-1; ++i) {
|
||||
if (StrVal[i] == '\\' &&
|
||||
(StrVal[i+1] == '\\' || StrVal[i+1] == '"')) {
|
||||
// \\ -> '\' and \" -> '"'.
|
||||
StrVal.erase(StrVal.begin()+i);
|
||||
--e;
|
||||
}
|
||||
}
|
||||
|
||||
// Plop the string (including the newline and trailing null) into a buffer
|
||||
// where we can lex it.
|
||||
SourceLocation TokLoc = CreateString(&StrVal[0], StrVal.size(), StrLoc);
|
||||
const char *StrData = SourceMgr.getCharacterData(TokLoc);
|
||||
|
||||
// Make and enter a lexer object so that we lex and expand the tokens just
|
||||
// like any others.
|
||||
Lexer *TL = new Lexer(TokLoc, *this,
|
||||
StrData, StrData+StrVal.size()-1 /* no null */);
|
||||
|
||||
// Ensure that the lexer thinks it is inside a directive, so that end \n will
|
||||
// return an EOM token.
|
||||
TL->ParsingPreprocessorDirective = true;
|
||||
|
||||
// This lexer really is for _Pragma.
|
||||
TL->Is_PragmaLexer = true;
|
||||
|
||||
EnterSourceFileWithLexer(TL, 0);
|
||||
|
||||
// With everything set up, lex this as a #pragma directive.
|
||||
HandlePragmaDirective();
|
||||
|
||||
// Finally, return whatever came after the pragma directive.
|
||||
return Lex(Tok);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// HandlePragmaOnce - Handle #pragma once. OnceTok is the 'once'.
|
||||
///
|
||||
void Preprocessor::HandlePragmaOnce(Token &OnceTok) {
|
||||
if (isInPrimaryFile()) {
|
||||
Diag(OnceTok, diag::pp_pragma_once_in_main_file);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current file lexer we're looking at. Ignore _Pragma 'files' etc.
|
||||
SourceLocation FileLoc = getCurrentFileLexer()->getFileLoc();
|
||||
|
||||
// Mark the file as a once-only file now.
|
||||
HeaderInfo.MarkFileIncludeOnce(SourceMgr.getFileEntryForLoc(FileLoc));
|
||||
}
|
||||
|
||||
void Preprocessor::HandlePragmaMark() {
|
||||
assert(CurLexer && "No current lexer?");
|
||||
CurLexer->ReadToEndOfLine();
|
||||
}
|
||||
|
||||
|
||||
/// HandlePragmaPoison - Handle #pragma GCC poison. PoisonTok is the 'poison'.
|
||||
///
|
||||
void Preprocessor::HandlePragmaPoison(Token &PoisonTok) {
|
||||
Token Tok;
|
||||
|
||||
while (1) {
|
||||
// Read the next token to poison. While doing this, pretend that we are
|
||||
// skipping while reading the identifier to poison.
|
||||
// This avoids errors on code like:
|
||||
// #pragma GCC poison X
|
||||
// #pragma GCC poison X
|
||||
if (CurLexer) CurLexer->LexingRawMode = true;
|
||||
LexUnexpandedToken(Tok);
|
||||
if (CurLexer) CurLexer->LexingRawMode = false;
|
||||
|
||||
// If we reached the end of line, we're done.
|
||||
if (Tok.is(tok::eom)) return;
|
||||
|
||||
// Can only poison identifiers.
|
||||
if (Tok.isNot(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->hasMacroDefinition())
|
||||
Diag(Tok, diag::pp_poisoning_existing_macro);
|
||||
|
||||
// Finally, poison it!
|
||||
II->setIsPoisoned();
|
||||
}
|
||||
}
|
||||
|
||||
/// HandlePragmaSystemHeader - Implement #pragma GCC system_header. We know
|
||||
/// that the whole directive has been parsed.
|
||||
void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
|
||||
if (isInPrimaryFile()) {
|
||||
Diag(SysHeaderTok, diag::pp_pragma_sysheader_in_main_file);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current file lexer we're looking at. Ignore _Pragma 'files' etc.
|
||||
Lexer *TheLexer = getCurrentFileLexer();
|
||||
|
||||
// Mark the file as a system header.
|
||||
const FileEntry *File = SourceMgr.getFileEntryForLoc(TheLexer->getFileLoc());
|
||||
HeaderInfo.MarkFileSystemHeader(File);
|
||||
|
||||
// Notify the client, if desired, that we are in a new source file.
|
||||
if (Callbacks)
|
||||
Callbacks->FileChanged(TheLexer->getSourceLocation(TheLexer->BufferPtr),
|
||||
PPCallbacks::SystemHeaderPragma,
|
||||
DirectoryLookup::SystemHeaderDir);
|
||||
}
|
||||
|
||||
/// HandlePragmaDependency - Handle #pragma GCC dependency "foo" blah.
|
||||
///
|
||||
void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
|
||||
Token FilenameTok;
|
||||
CurLexer->LexIncludeFilename(FilenameTok);
|
||||
|
||||
// If the token kind is EOM, the error has already been diagnosed.
|
||||
if (FilenameTok.is(tok::eom))
|
||||
return;
|
||||
|
||||
// Reserve a buffer to get the spelling.
|
||||
llvm::SmallVector<char, 128> FilenameBuffer;
|
||||
FilenameBuffer.resize(FilenameTok.getLength());
|
||||
|
||||
const char *FilenameStart = &FilenameBuffer[0];
|
||||
unsigned Len = getSpelling(FilenameTok, FilenameStart);
|
||||
const char *FilenameEnd = FilenameStart+Len;
|
||||
bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(),
|
||||
FilenameStart, FilenameEnd);
|
||||
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
|
||||
// error.
|
||||
if (FilenameStart == 0)
|
||||
return;
|
||||
|
||||
// Search include directories for this file.
|
||||
const DirectoryLookup *CurDir;
|
||||
const FileEntry *File = LookupFile(FilenameStart, FilenameEnd,
|
||||
isAngled, 0, CurDir);
|
||||
if (File == 0)
|
||||
return Diag(FilenameTok, diag::err_pp_file_not_found,
|
||||
std::string(FilenameStart, FilenameEnd));
|
||||
|
||||
SourceLocation FileLoc = getCurrentFileLexer()->getFileLoc();
|
||||
const FileEntry *CurFile = SourceMgr.getFileEntryForLoc(FileLoc);
|
||||
|
||||
// If this file is older than the file it depends on, emit a diagnostic.
|
||||
if (CurFile && CurFile->getModificationTime() < File->getModificationTime()) {
|
||||
// Lex tokens at the end of the message and include them in the message.
|
||||
std::string Message;
|
||||
Lex(DependencyTok);
|
||||
while (DependencyTok.isNot(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 {
|
||||
/// PragmaOnceHandler - "#pragma once" marks the file as atomically included.
|
||||
struct PragmaOnceHandler : public PragmaHandler {
|
||||
PragmaOnceHandler(const IdentifierInfo *OnceID) : PragmaHandler(OnceID) {}
|
||||
virtual void HandlePragma(Preprocessor &PP, Token &OnceTok) {
|
||||
PP.CheckEndOfDirective("#pragma once");
|
||||
PP.HandlePragmaOnce(OnceTok);
|
||||
}
|
||||
};
|
||||
|
||||
/// PragmaMarkHandler - "#pragma mark ..." is ignored by the compiler, and the
|
||||
/// rest of the line is not lexed.
|
||||
struct PragmaMarkHandler : public PragmaHandler {
|
||||
PragmaMarkHandler(const IdentifierInfo *MarkID) : PragmaHandler(MarkID) {}
|
||||
virtual void HandlePragma(Preprocessor &PP, Token &MarkTok) {
|
||||
PP.HandlePragmaMark();
|
||||
}
|
||||
};
|
||||
|
||||
/// PragmaPoisonHandler - "#pragma poison x" marks x as not usable.
|
||||
struct PragmaPoisonHandler : public PragmaHandler {
|
||||
PragmaPoisonHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
|
||||
virtual void HandlePragma(Preprocessor &PP, Token &PoisonTok) {
|
||||
PP.HandlePragmaPoison(PoisonTok);
|
||||
}
|
||||
};
|
||||
|
||||
/// PragmaSystemHeaderHandler - "#pragma system_header" marks the current file
|
||||
/// as a system header, which silences warnings in it.
|
||||
struct PragmaSystemHeaderHandler : public PragmaHandler {
|
||||
PragmaSystemHeaderHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
|
||||
virtual void HandlePragma(Preprocessor &PP, Token &SHToken) {
|
||||
PP.HandlePragmaSystemHeader(SHToken);
|
||||
PP.CheckEndOfDirective("#pragma");
|
||||
}
|
||||
};
|
||||
struct PragmaDependencyHandler : public PragmaHandler {
|
||||
PragmaDependencyHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
|
||||
virtual void HandlePragma(Preprocessor &PP, Token &DepToken) {
|
||||
PP.HandlePragmaDependency(DepToken);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
/// RegisterBuiltinPragmas - Install the standard preprocessor pragmas:
|
||||
/// #pragma GCC poison/system_header/dependency and #pragma once.
|
||||
void Preprocessor::RegisterBuiltinPragmas() {
|
||||
AddPragmaHandler(0, new PragmaOnceHandler(getIdentifierInfo("once")));
|
||||
AddPragmaHandler(0, new PragmaMarkHandler(getIdentifierInfo("mark")));
|
||||
AddPragmaHandler("GCC", new PragmaPoisonHandler(getIdentifierInfo("poison")));
|
||||
AddPragmaHandler("GCC", new PragmaSystemHeaderHandler(
|
||||
getIdentifierInfo("system_header")));
|
||||
AddPragmaHandler("GCC", new PragmaDependencyHandler(
|
||||
getIdentifierInfo("dependency")));
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,71 +0,0 @@
|
||||
//===--- ScratchBuffer.cpp - Scratch space for forming tokens -------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the ScratchBuffer interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Lex/ScratchBuffer.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
using namespace clang;
|
||||
|
||||
// ScratchBufSize - The size of each chunk of scratch memory. Slightly less
|
||||
//than a page, almost certainly enough for anything. :)
|
||||
static const unsigned ScratchBufSize = 4060;
|
||||
|
||||
ScratchBuffer::ScratchBuffer(SourceManager &SM) : SourceMgr(SM), CurBuffer(0) {
|
||||
// Set BytesUsed so that the first call to getToken will require an alloc.
|
||||
BytesUsed = ScratchBufSize;
|
||||
FileID = 0;
|
||||
}
|
||||
|
||||
/// getToken - Splat the specified text into a temporary MemoryBuffer and
|
||||
/// return a SourceLocation that refers to the token. This is just like the
|
||||
/// method below, but returns a location that indicates the physloc of the
|
||||
/// token.
|
||||
SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len) {
|
||||
if (BytesUsed+Len > ScratchBufSize)
|
||||
AllocScratchBuffer(Len);
|
||||
|
||||
// Copy the token data into the buffer.
|
||||
memcpy(CurBuffer+BytesUsed, Buf, Len);
|
||||
|
||||
// Remember that we used these bytes.
|
||||
BytesUsed += Len;
|
||||
|
||||
assert(BytesUsed-Len < (1 << SourceLocation::FilePosBits) &&
|
||||
"Out of range file position!");
|
||||
|
||||
return SourceLocation::getFileLoc(FileID, BytesUsed-Len);
|
||||
}
|
||||
|
||||
|
||||
/// getToken - Splat the specified text into a temporary MemoryBuffer and
|
||||
/// return a SourceLocation that refers to the token. The SourceLoc value
|
||||
/// gives a virtual location that the token will appear to be from.
|
||||
SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len,
|
||||
SourceLocation SourceLoc) {
|
||||
// Map the physloc to the specified sourceloc.
|
||||
return SourceMgr.getInstantiationLoc(getToken(Buf, Len), SourceLoc);
|
||||
}
|
||||
|
||||
void ScratchBuffer::AllocScratchBuffer(unsigned RequestLen) {
|
||||
// Only pay attention to the requested length if it is larger than our default
|
||||
// page size. If it is, we allocate an entire chunk for it. This is to
|
||||
// support gigantic tokens, which almost certainly won't happen. :)
|
||||
if (RequestLen < ScratchBufSize)
|
||||
RequestLen = ScratchBufSize;
|
||||
|
||||
llvm::MemoryBuffer *Buf =
|
||||
llvm::MemoryBuffer::getNewMemBuffer(RequestLen, "<scratch space>");
|
||||
FileID = SourceMgr.createFileIDForMemBuffer(Buf);
|
||||
CurBuffer = const_cast<char*>(Buf->getBufferStart());
|
||||
BytesUsed = 0;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
LEVEL = ../..
|
||||
DIRS := Basic Lex Parse AST Sema CodeGen Analysis Rewrite 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:
|
||||
286
clang/NOTES.txt
286
clang/NOTES.txt
@@ -1,286 +0,0 @@
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Random Notes
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
C90/C99/C++ Comparisons:
|
||||
http://david.tribble.com/text/cdiffs.htm
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
Extensions:
|
||||
|
||||
* "#define_target X Y"
|
||||
This preprocessor directive works exactly the same was as #define, but it
|
||||
notes that 'X' is a target-specific preprocessor directive. When used, a
|
||||
diagnostic is emitted indicating that the translation unit is non-portable.
|
||||
|
||||
If a target-define is #undef'd before use, no diagnostic is emitted. If 'X'
|
||||
were previously a normal #define macro, the macro is tainted. If 'X' is
|
||||
subsequently #defined as a non-target-specific define, the taint bit is
|
||||
cleared.
|
||||
|
||||
* "#define_other_target X"
|
||||
The preprocessor directive takes a single identifier argument. It notes
|
||||
that this identifier is a target-specific #define for some target other than
|
||||
the current one. Use of this identifier will result in a diagnostic.
|
||||
|
||||
If 'X' is later #undef'd or #define'd, the taint bit is cleared. If 'X' is
|
||||
already defined, X is marked as a target-specific define.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
When we go to reimplement <tgmath.h>, we should do it more intelligently than
|
||||
the GCC-supplied header. EDG has an interesting __generic builtin that provides
|
||||
overloading for C:
|
||||
http://www.edg.com/docs/edg_cpp.pdf
|
||||
|
||||
For example, they have:
|
||||
#define sin(x) __generic(x,,, sin, sinf, sinl, csin, csinf,csinl)(x)
|
||||
|
||||
It's unclear to me why you couldn't just have a builtin like:
|
||||
__builtin_overload(1, arg1, impl1, impl2, impl3)
|
||||
__builtin_overload(2, arg1, arg2, impl1, impl2, impl3)
|
||||
__builtin_overload(3, arg1, arg2, arg3, impl1, impl2, impl3)
|
||||
|
||||
Where the compiler would just pick the right "impl" based on the arguments
|
||||
provided. One nasty detail is that some arithmetic promotions most be done for
|
||||
use by the tgmath.h stuff, but it would be nice to be able to handle vectors
|
||||
etc as well without huge globs of macros. With the above scheme, you could
|
||||
use:
|
||||
|
||||
#define sin(x) __builtin_overload(1, x, sin, sinf, sinl, csin, csinf,csinl)(x)
|
||||
|
||||
and not need to keep track of which argument to "__generic" corresponds to which
|
||||
type, etc.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
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.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Specifying targets: -triple and -arch
|
||||
===---------------------------------------------------------------------===//
|
||||
|
||||
The clang supports "-triple" and "-arch" options. At most one -triple option may
|
||||
be specified, while multiple -arch options can be specified. Both are optional.
|
||||
|
||||
The "selection of target" behavior is defined as follows:
|
||||
|
||||
(1) If the user does not specify -triple:
|
||||
|
||||
(a) If no -arch options are specified, the target triple used is the host
|
||||
triple (in llvm/Config/config.h).
|
||||
|
||||
(b) If one or more -arch's are specified (and no -triple), then there is
|
||||
one triple for each -arch, where the specified arch is substituted
|
||||
for the arch in the host triple. Example:
|
||||
|
||||
host triple = i686-apple-darwin9
|
||||
command: clang -arch ppc -arch ppc64 ...
|
||||
triples used: ppc-apple-darwin9 ppc64-apple-darwin9
|
||||
|
||||
(2) The user does specify a -triple (only one allowed):
|
||||
|
||||
(a) If no -arch options are specified, the triple specified by -triple
|
||||
is used. E.g clang -triple i686-apple-darwin9
|
||||
|
||||
(b) If one or more -arch options are specified, then the triple specified
|
||||
by -triple is used as the primary target, and the arch's specified
|
||||
by -arch are used to create secondary targets. For example:
|
||||
|
||||
clang -triple i686-apple-darwin9 -arch ppc -arch ppc64
|
||||
|
||||
has the following targets:
|
||||
|
||||
i686-apple-darwin9 (primary target)
|
||||
ppc-apple-darwin9 (secondary target)
|
||||
ppc64-apple-darwin9 (secondary target)
|
||||
|
||||
The secondary targets are used in the 'portability' model (see below).
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
The 'portability' model in clang is sufficient to catch translation units (or
|
||||
their parts) that are not portable, but it doesn't help if the system headers
|
||||
are non-portable and not fixed. An alternative model that would be easy to use
|
||||
is a 'tainting' scheme. Consider:
|
||||
|
||||
int32_t
|
||||
OSHostByteOrder(void) {
|
||||
#if defined(__LITTLE_ENDIAN__)
|
||||
return OSLittleEndian;
|
||||
#elif defined(__BIG_ENDIAN__)
|
||||
return OSBigEndian;
|
||||
#else
|
||||
return OSUnknownByteOrder;
|
||||
#endif
|
||||
}
|
||||
|
||||
It would be trivial to mark 'OSHostByteOrder' as being non-portable (tainted)
|
||||
instead of marking the entire translation unit. Then, if OSHostByteOrder is
|
||||
never called/used by the current translation unit, the t-u wouldn't be marked
|
||||
non-portable. However, there is no good way to handle stuff like:
|
||||
|
||||
extern int X, Y;
|
||||
|
||||
#ifndef __POWERPC__
|
||||
#define X Y
|
||||
#endif
|
||||
|
||||
int bar() { return X; }
|
||||
|
||||
When compiling for powerpc, the #define is skipped, so it doesn't know that bar
|
||||
uses a #define that is set on some other target. In practice, limited cases
|
||||
could be handled by scanning the skipped region of a #if, but the fully general
|
||||
case cannot be implemented efficiently. In this case, for example, the #define
|
||||
in the protected region could be turned into either a #define_target or
|
||||
#define_other_target as appropriate. The harder case is code like this (from
|
||||
OSByteOrder.h):
|
||||
|
||||
#if (defined(__ppc__) || defined(__ppc64__))
|
||||
#include <libkern/ppc/OSByteOrder.h>
|
||||
#elif (defined(__i386__) || defined(__x86_64__))
|
||||
#include <libkern/i386/OSByteOrder.h>
|
||||
#else
|
||||
#include <libkern/machine/OSByteOrder.h>
|
||||
#endif
|
||||
|
||||
The realistic way to fix this is by having an initial #ifdef __llvm__ that
|
||||
defines its contents in terms of the llvm bswap intrinsics. Other things should
|
||||
be handled on a case-by-case basis.
|
||||
|
||||
|
||||
We probably have to do something smarter like this in the future. The C++ header
|
||||
<limits> contains a lot of code like this:
|
||||
|
||||
static const int digits10 = __LDBL_DIG__;
|
||||
static const int min_exponent = __LDBL_MIN_EXP__;
|
||||
static const int min_exponent10 = __LDBL_MIN_10_EXP__;
|
||||
static const float_denorm_style has_denorm
|
||||
= bool(__LDBL_DENORM_MIN__) ? denorm_present : denorm_absent;
|
||||
|
||||
... since this isn't being used in an #ifdef, it should be easy enough to taint
|
||||
the decl for these ivars.
|
||||
|
||||
|
||||
/usr/include/sys/cdefs.h contains stuff like this:
|
||||
|
||||
#if defined(__ppc__)
|
||||
# if defined(__LDBL_MANT_DIG__) && defined(__DBL_MANT_DIG__) && \
|
||||
__LDBL_MANT_DIG__ > __DBL_MANT_DIG__
|
||||
# if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0 < 1040
|
||||
# define __DARWIN_LDBL_COMPAT(x) __asm("_" __STRING(x) "$LDBLStub")
|
||||
# else
|
||||
# define __DARWIN_LDBL_COMPAT(x) __asm("_" __STRING(x) "$LDBL128")
|
||||
# endif
|
||||
# define __DARWIN_LDBL_COMPAT2(x) __asm("_" __STRING(x) "$LDBL128")
|
||||
# define __DARWIN_LONG_DOUBLE_IS_DOUBLE 0
|
||||
# else
|
||||
# define __DARWIN_LDBL_COMPAT(x) /* nothing */
|
||||
# define __DARWIN_LDBL_COMPAT2(x) /* nothing */
|
||||
# define __DARWIN_LONG_DOUBLE_IS_DOUBLE 1
|
||||
# endif
|
||||
#elif defined(__i386__) || defined(__ppc64__) || defined(__x86_64__)
|
||||
# define __DARWIN_LDBL_COMPAT(x) /* nothing */
|
||||
# define __DARWIN_LDBL_COMPAT2(x) /* nothing */
|
||||
# define __DARWIN_LONG_DOUBLE_IS_DOUBLE 0
|
||||
#else
|
||||
# error Unknown architecture
|
||||
#endif
|
||||
|
||||
An ideal way to solve this issue is to mark __DARWIN_LDBL_COMPAT /
|
||||
__DARWIN_LDBL_COMPAT2 / __DARWIN_LONG_DOUBLE_IS_DOUBLE as being non-portable
|
||||
because they depend on non-portable macros. In practice though, this may end
|
||||
up being a serious problem: every use of printf will mark the translation unit
|
||||
non-portable if targetting ppc32 and something else.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
//===--- AttributeList.cpp --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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"
|
||||
using namespace clang;
|
||||
|
||||
AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc,
|
||||
IdentifierInfo *pName, SourceLocation pLoc,
|
||||
Action::ExprTy **elist, unsigned numargs,
|
||||
AttributeList *n)
|
||||
: AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc),
|
||||
NumArgs(numargs), Next(n) {
|
||||
Args = new Action::ExprTy*[numargs];
|
||||
for (unsigned i = 0; i != numargs; ++i)
|
||||
Args[i] = elist[i];
|
||||
}
|
||||
@@ -1,287 +0,0 @@
|
||||
//===--- SemaDeclSpec.cpp - Declaration Specifier Semantic Analysis -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements semantic analysis for declaration specifiers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Parse/DeclSpec.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
using namespace clang;
|
||||
|
||||
/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
|
||||
///
|
||||
unsigned DeclSpec::getParsedSpecifiers() const {
|
||||
unsigned Res = 0;
|
||||
if (StorageClassSpec != SCS_unspecified ||
|
||||
SCS_thread_specified)
|
||||
Res |= PQ_StorageClassSpecifier;
|
||||
|
||||
if (TypeQualifiers != TQ_unspecified)
|
||||
Res |= PQ_TypeQualifier;
|
||||
|
||||
if (hasTypeSpecifier())
|
||||
Res |= PQ_TypeSpecifier;
|
||||
|
||||
if (FS_inline_specified)
|
||||
Res |= PQ_FunctionSpecifier;
|
||||
return Res;
|
||||
}
|
||||
|
||||
const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) {
|
||||
switch (S) {
|
||||
default: assert(0 && "Unknown typespec!");
|
||||
case DeclSpec::SCS_unspecified: return "unspecified";
|
||||
case DeclSpec::SCS_typedef: return "typedef";
|
||||
case DeclSpec::SCS_extern: return "extern";
|
||||
case DeclSpec::SCS_static: return "static";
|
||||
case DeclSpec::SCS_auto: return "auto";
|
||||
case DeclSpec::SCS_register: return "register";
|
||||
}
|
||||
}
|
||||
|
||||
static bool BadSpecifier(DeclSpec::SCS S, const char *&PrevSpec) {
|
||||
PrevSpec = DeclSpec::getSpecifierName(S);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool BadSpecifier(DeclSpec::TSW W, const char *&PrevSpec) {
|
||||
switch (W) {
|
||||
case DeclSpec::TSW_unspecified: PrevSpec = "unspecified"; break;
|
||||
case DeclSpec::TSW_short: PrevSpec = "short"; break;
|
||||
case DeclSpec::TSW_long: PrevSpec = "long"; break;
|
||||
case DeclSpec::TSW_longlong: PrevSpec = "long long"; break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool BadSpecifier(DeclSpec::TSC C, const char *&PrevSpec) {
|
||||
switch (C) {
|
||||
case DeclSpec::TSC_unspecified: PrevSpec = "unspecified"; break;
|
||||
case DeclSpec::TSC_imaginary: PrevSpec = "imaginary"; break;
|
||||
case DeclSpec::TSC_complex: PrevSpec = "complex"; break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool BadSpecifier(DeclSpec::TSS S, const char *&PrevSpec) {
|
||||
switch (S) {
|
||||
case DeclSpec::TSS_unspecified: PrevSpec = "unspecified"; break;
|
||||
case DeclSpec::TSS_signed: PrevSpec = "signed"; break;
|
||||
case DeclSpec::TSS_unsigned: PrevSpec = "unsigned"; break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
|
||||
switch (T) {
|
||||
default: assert(0 && "Unknown typespec!");
|
||||
case DeclSpec::TST_unspecified: return "unspecified";
|
||||
case DeclSpec::TST_void: return "void";
|
||||
case DeclSpec::TST_char: return "char";
|
||||
case DeclSpec::TST_int: return "int";
|
||||
case DeclSpec::TST_float: return "float";
|
||||
case DeclSpec::TST_double: return "double";
|
||||
case DeclSpec::TST_bool: return "_Bool";
|
||||
case DeclSpec::TST_decimal32: return "_Decimal32";
|
||||
case DeclSpec::TST_decimal64: return "_Decimal64";
|
||||
case DeclSpec::TST_decimal128: return "_Decimal128";
|
||||
case DeclSpec::TST_enum: return "enum";
|
||||
case DeclSpec::TST_union: return "union";
|
||||
case DeclSpec::TST_struct: return "struct";
|
||||
case DeclSpec::TST_typedef: return "typedef";
|
||||
case DeclSpec::TST_typeofType:
|
||||
case DeclSpec::TST_typeofExpr: return "typeof";
|
||||
}
|
||||
}
|
||||
|
||||
static bool BadSpecifier(DeclSpec::TST T, const char *&PrevSpec) {
|
||||
PrevSpec = DeclSpec::getSpecifierName(T);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool BadSpecifier(DeclSpec::TQ T, const char *&PrevSpec) {
|
||||
switch (T) {
|
||||
case DeclSpec::TQ_unspecified: PrevSpec = "unspecified"; break;
|
||||
case DeclSpec::TQ_const: PrevSpec = "const"; break;
|
||||
case DeclSpec::TQ_restrict: PrevSpec = "restrict"; break;
|
||||
case DeclSpec::TQ_volatile: PrevSpec = "volatile"; break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
|
||||
const char *&PrevSpec) {
|
||||
if (StorageClassSpec != SCS_unspecified)
|
||||
return BadSpecifier( (SCS)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( (TSW)TypeSpecWidth, PrevSpec);
|
||||
TypeSpecWidth = W;
|
||||
TSWLoc = Loc;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc,
|
||||
const char *&PrevSpec) {
|
||||
if (TypeSpecComplex != TSC_unspecified)
|
||||
return BadSpecifier( (TSC)TypeSpecComplex, PrevSpec);
|
||||
TypeSpecComplex = C;
|
||||
TSCLoc = Loc;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc,
|
||||
const char *&PrevSpec) {
|
||||
if (TypeSpecSign != TSS_unspecified)
|
||||
return BadSpecifier( (TSS)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( (TST)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, SourceManager& SrcMgr,
|
||||
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, SrcMgr, diag::err_invalid_sign_spec,
|
||||
getSpecifierName( (TST)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, SrcMgr,
|
||||
TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec
|
||||
: diag::err_invalid_longlong_spec,
|
||||
getSpecifierName( (TST)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, SrcMgr, diag::err_invalid_long_spec,
|
||||
getSpecifierName( (TST)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, SrcMgr, 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, SrcMgr, diag::ext_integer_complex);
|
||||
} else if (TypeSpecType != TST_float && TypeSpecType != TST_double) {
|
||||
Diag(D, TSCLoc, SrcMgr, diag::err_invalid_complex_spec,
|
||||
getSpecifierName( (TST)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(), SrcMgr, diag::err_invalid_thread_spec,
|
||||
getSpecifierName( (SCS)StorageClassSpec));
|
||||
SCS_thread_specified = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, now we can infer the real type.
|
||||
|
||||
// TODO: return "auto function" and other bad things based on the real type.
|
||||
|
||||
// 'data definition has no type or storage class'?
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
##===- clang/Parse/Makefile --------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# This implements the Parser library for the C-Language front-end.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../..
|
||||
LIBRARYNAME := clangParse
|
||||
BUILD_ARCHIVE = 1
|
||||
CXXFLAGS = -fno-rtti
|
||||
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
//===--- MinimalAction.cpp - Implement the MinimalAction class ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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;
|
||||
}
|
||||
};
|
||||
|
||||
void MinimalAction:: ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
|
||||
TUScope = S;
|
||||
IdentifierInfo *II;
|
||||
TypeNameInfo *TI;
|
||||
|
||||
// recognize the ObjC built-in type identifiers.
|
||||
II = &Idents.get("id");
|
||||
TI = new TypeNameInfo(1, II->getFETokenInfo<TypeNameInfo>());
|
||||
II->setFETokenInfo(TI);
|
||||
II = &Idents.get("SEL");
|
||||
TI = new TypeNameInfo(1, II->getFETokenInfo<TypeNameInfo>());
|
||||
II->setFETokenInfo(TI);
|
||||
II = &Idents.get("Class");
|
||||
TI = new TypeNameInfo(1, II->getFETokenInfo<TypeNameInfo>());
|
||||
II->setFETokenInfo(TI);
|
||||
II = &Idents.get("Protocol");
|
||||
TI = new TypeNameInfo(1, II->getFETokenInfo<TypeNameInfo>());
|
||||
II->setFETokenInfo(TI);
|
||||
}
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
/// ActOnDeclarator - 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::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup) {
|
||||
IdentifierInfo *II = D.getIdentifier();
|
||||
|
||||
// If there is no identifier associated with this declarator, bail out.
|
||||
if (II == 0) return 0;
|
||||
|
||||
TypeNameInfo *weCurrentlyHaveTypeInfo = II->getFETokenInfo<TypeNameInfo>();
|
||||
bool isTypeName =
|
||||
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef;
|
||||
|
||||
// this check avoids creating TypeNameInfo objects for the common case.
|
||||
// It does need to handle the uncommon case of shadowing a typedef name with a
|
||||
// non-typedef name. e.g. { typedef int a; a xx; { int a; } }
|
||||
if (weCurrentlyHaveTypeInfo || isTypeName) {
|
||||
TypeNameInfo *TI = new TypeNameInfo(isTypeName, weCurrentlyHaveTypeInfo);
|
||||
|
||||
II->setFETokenInfo(TI);
|
||||
|
||||
// Remember that this needs to be removed when the scope is popped.
|
||||
S->AddDecl(II);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Action::DeclTy *
|
||||
MinimalAction::ActOnStartClassInterface(SourceLocation AtInterafceLoc,
|
||||
IdentifierInfo *ClassName, SourceLocation ClassLoc,
|
||||
IdentifierInfo *SuperName, SourceLocation SuperLoc,
|
||||
IdentifierInfo **ProtocolNames, unsigned NumProtocols,
|
||||
SourceLocation EndProtoLoc, AttributeList *AttrList) {
|
||||
TypeNameInfo *TI =
|
||||
new TypeNameInfo(1, ClassName->getFETokenInfo<TypeNameInfo>());
|
||||
|
||||
ClassName->setFETokenInfo(TI);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ActOnForwardClassDeclaration -
|
||||
/// Scope will always be top level file scope.
|
||||
Action::DeclTy *
|
||||
MinimalAction::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
|
||||
IdentifierInfo **IdentList, unsigned NumElts) {
|
||||
for (unsigned i = 0; i != NumElts; ++i) {
|
||||
TypeNameInfo *TI =
|
||||
new TypeNameInfo(1, IdentList[i]->getFETokenInfo<TypeNameInfo>());
|
||||
|
||||
IdentList[i]->setFETokenInfo(TI);
|
||||
|
||||
// Remember that this needs to be removed when the scope is popped.
|
||||
TUScope->AddDecl(IdentList[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ActOnPopScope - When a scope is popped, if any typedefs are now out-of-scope,
|
||||
/// they are removed from the IdentifierInfo::FETokenInfo field.
|
||||
void MinimalAction::ActOnPopScope(SourceLocation Loc, Scope *S) {
|
||||
for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end();
|
||||
I != E; ++I) {
|
||||
IdentifierInfo &II = *static_cast<IdentifierInfo*>(*I);
|
||||
TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>();
|
||||
assert(TI && "This decl didn't get pushed??");
|
||||
|
||||
if (TI) {
|
||||
TypeNameInfo *Next = TI->Prev;
|
||||
delete TI;
|
||||
|
||||
II.setFETokenInfo(Next);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,119 +0,0 @@
|
||||
//===--- ParseDeclCXX.cpp - C++ Declaration Parsing -----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the C++ Declaration portions of the Parser interfaces.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Parse/Parser.h"
|
||||
#include "clang/Parse/Scope.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
using namespace clang;
|
||||
|
||||
/// ParseNamespace - We know that the current token is a namespace keyword. This
|
||||
/// may either be a top level namespace or a block-level namespace alias.
|
||||
///
|
||||
/// namespace-definition: [C++ 7.3: basic.namespace]
|
||||
/// named-namespace-definition
|
||||
/// unnamed-namespace-definition
|
||||
///
|
||||
/// unnamed-namespace-definition:
|
||||
/// 'namespace' attributes[opt] '{' namespace-body '}'
|
||||
///
|
||||
/// named-namespace-definition:
|
||||
/// original-namespace-definition
|
||||
/// extension-namespace-definition
|
||||
///
|
||||
/// original-namespace-definition:
|
||||
/// 'namespace' identifier attributes[opt] '{' namespace-body '}'
|
||||
///
|
||||
/// extension-namespace-definition:
|
||||
/// 'namespace' original-namespace-name '{' namespace-body '}'
|
||||
///
|
||||
/// namespace-alias-definition: [C++ 7.3.2: namespace.alias]
|
||||
/// 'namespace' identifier '=' qualified-namespace-specifier ';'
|
||||
///
|
||||
Parser::DeclTy *Parser::ParseNamespace(unsigned Context) {
|
||||
assert(Tok.is(tok::kw_namespace) && "Not a namespace!");
|
||||
SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'.
|
||||
|
||||
SourceLocation IdentLoc;
|
||||
IdentifierInfo *Ident = 0;
|
||||
|
||||
if (Tok.is(tok::identifier)) {
|
||||
Ident = Tok.getIdentifierInfo();
|
||||
IdentLoc = ConsumeToken(); // eat the identifier.
|
||||
}
|
||||
|
||||
// Read label attributes, if present.
|
||||
DeclTy *AttrList = 0;
|
||||
if (Tok.is(tok::kw___attribute))
|
||||
// FIXME: save these somewhere.
|
||||
AttrList = ParseAttributes();
|
||||
|
||||
if (Tok.is(tok::equal)) {
|
||||
// FIXME: Verify no attributes were present.
|
||||
// FIXME: parse this.
|
||||
} else if (Tok.is(tok::l_brace)) {
|
||||
SourceLocation LBrace = ConsumeBrace();
|
||||
// FIXME: push a scope, push a namespace decl.
|
||||
|
||||
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
|
||||
// FIXME capture the decls.
|
||||
ParseExternalDeclaration();
|
||||
}
|
||||
|
||||
SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace);
|
||||
|
||||
// FIXME: act on this.
|
||||
} else {
|
||||
unsigned D = Ident ? diag::err_expected_lbrace :
|
||||
diag::err_expected_ident_lbrace;
|
||||
Diag(Tok.getLocation(), D);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ParseLinkage - We know that the current token is a string_literal
|
||||
/// and just before that, that extern was seen.
|
||||
///
|
||||
/// linkage-specification: [C++ 7.5p2: dcl.link]
|
||||
/// 'extern' string-literal '{' declaration-seq[opt] '}'
|
||||
/// 'extern' string-literal declaration
|
||||
///
|
||||
Parser::DeclTy *Parser::ParseLinkage(unsigned Context) {
|
||||
assert(Tok.is(tok::string_literal) && "Not a stringliteral!");
|
||||
llvm::SmallVector<char, 8> LangBuffer;
|
||||
// LangBuffer is guaranteed to be big enough.
|
||||
LangBuffer.resize(Tok.getLength());
|
||||
const char *LangBufPtr = &LangBuffer[0];
|
||||
unsigned StrSize = PP.getSpelling(Tok, LangBufPtr);
|
||||
|
||||
SourceLocation Loc = ConsumeStringToken();
|
||||
DeclTy *D = 0;
|
||||
SourceLocation LBrace, RBrace;
|
||||
|
||||
if (Tok.isNot(tok::l_brace)) {
|
||||
D = ParseDeclaration(Context);
|
||||
} else {
|
||||
LBrace = ConsumeBrace();
|
||||
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
|
||||
// FIXME capture the decls.
|
||||
D = ParseExternalDeclaration();
|
||||
}
|
||||
|
||||
RBrace = MatchRHSPunctuation(tok::r_brace, LBrace);
|
||||
}
|
||||
|
||||
if (!D)
|
||||
return 0;
|
||||
|
||||
return Actions.ActOnLinkageSpec(Loc, LBrace, RBrace, LangBufPtr, StrSize, D);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,78 +0,0 @@
|
||||
//===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file 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.isNot(tok::l_paren)) {
|
||||
Diag(Tok, diag::err_expected_lparen_after, CastName);
|
||||
return ExprResult(true);
|
||||
}
|
||||
|
||||
ExprResult Result = ParseSimpleParenExpression(RParenLoc);
|
||||
|
||||
if (!Result.isInvalid)
|
||||
Result = Actions.ActOnCXXCasts(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.ActOnCXXBoolLiteral(ConsumeToken(), Kind);
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
//===--- ParseInit.cpp - Initializer Parsing ------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements initializer parsing as specified by C99 6.7.8.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Parse/Parser.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
using namespace clang;
|
||||
|
||||
|
||||
/// MayBeDesignationStart - Return true if this token might be the start of a
|
||||
/// designator.
|
||||
static bool MayBeDesignationStart(tok::TokenKind K) {
|
||||
switch (K) {
|
||||
default: return false;
|
||||
case tok::period: // designator: '.' identifier
|
||||
case tok::l_square: // designator: array-designator
|
||||
case tok::identifier: // designation: identifier ':'
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
|
||||
/// checking to see if the token stream starts with a designator.
|
||||
///
|
||||
/// designation:
|
||||
/// designator-list '='
|
||||
/// [GNU] array-designator
|
||||
/// [GNU] identifier ':'
|
||||
///
|
||||
/// designator-list:
|
||||
/// designator
|
||||
/// designator-list designator
|
||||
///
|
||||
/// designator:
|
||||
/// array-designator
|
||||
/// '.' identifier
|
||||
///
|
||||
/// array-designator:
|
||||
/// '[' constant-expression ']'
|
||||
/// [GNU] '[' constant-expression '...' constant-expression ']'
|
||||
///
|
||||
/// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an
|
||||
/// initializer. We need to consider this case when parsing array designators.
|
||||
///
|
||||
Parser::ExprResult Parser::ParseInitializerWithPotentialDesignator() {
|
||||
// Parse each designator in the designator list until we find an initializer.
|
||||
while (1) {
|
||||
switch (Tok.getKind()) {
|
||||
case tok::equal:
|
||||
// We read some number (at least one due to the grammar we implemented)
|
||||
// of designators and found an '=' sign. The following tokens must be
|
||||
// the initializer.
|
||||
ConsumeToken();
|
||||
return ParseInitializer();
|
||||
|
||||
default: {
|
||||
// We read some number (at least one due to the grammar we implemented)
|
||||
// of designators and found something that isn't an = or an initializer.
|
||||
// If we have exactly one array designator [TODO CHECK], this is the GNU
|
||||
// 'designation: array-designator' extension. Otherwise, it is a parse
|
||||
// error.
|
||||
SourceLocation Loc = Tok.getLocation();
|
||||
ExprResult Init = ParseInitializer();
|
||||
if (Init.isInvalid) return Init;
|
||||
|
||||
Diag(Tok, diag::ext_gnu_missing_equal_designator);
|
||||
return Init;
|
||||
}
|
||||
case tok::period:
|
||||
// designator: '.' identifier
|
||||
ConsumeToken();
|
||||
if (ExpectAndConsume(tok::identifier, diag::err_expected_ident))
|
||||
return ExprResult(true);
|
||||
break;
|
||||
|
||||
case tok::l_square: {
|
||||
// array-designator: '[' constant-expression ']'
|
||||
// array-designator: '[' constant-expression '...' constant-expression ']'
|
||||
SourceLocation StartLoc = ConsumeBracket();
|
||||
|
||||
ExprResult Idx = ParseConstantExpression();
|
||||
if (Idx.isInvalid) {
|
||||
SkipUntil(tok::r_square);
|
||||
return Idx;
|
||||
}
|
||||
|
||||
// Handle the gnu array range extension.
|
||||
if (Tok.is(tok::ellipsis)) {
|
||||
Diag(Tok, diag::ext_gnu_array_range);
|
||||
ConsumeToken();
|
||||
|
||||
ExprResult RHS = ParseConstantExpression();
|
||||
if (RHS.isInvalid) {
|
||||
SkipUntil(tok::r_square);
|
||||
return RHS;
|
||||
}
|
||||
}
|
||||
|
||||
MatchRHSPunctuation(tok::r_square, StartLoc);
|
||||
break;
|
||||
}
|
||||
case tok::identifier: {
|
||||
// Due to the GNU "designation: identifier ':'" extension, we don't know
|
||||
// whether something starting with an identifier is an
|
||||
// assignment-expression or if it is an old-style structure field
|
||||
// designator.
|
||||
// TODO: Check that this is the first designator.
|
||||
Token Ident = Tok;
|
||||
ConsumeToken();
|
||||
|
||||
// If this is the gross GNU extension, handle it now.
|
||||
if (Tok.is(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.isNot(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.is(tok::r_brace)) {
|
||||
Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
|
||||
// Match the '}'.
|
||||
return Actions.ActOnInitList(LBraceLoc, 0, 0, ConsumeBrace());
|
||||
}
|
||||
llvm::SmallVector<ExprTy*, 8> InitExprs;
|
||||
bool InitExprsOk = true;
|
||||
|
||||
while (1) {
|
||||
// Parse: designation[opt] initializer
|
||||
|
||||
// If we know that this cannot be a designation, just parse the nested
|
||||
// initializer directly.
|
||||
ExprResult SubElt;
|
||||
if (!MayBeDesignationStart(Tok.getKind()))
|
||||
SubElt = ParseInitializer();
|
||||
else
|
||||
SubElt = ParseInitializerWithPotentialDesignator();
|
||||
|
||||
// If we couldn't parse the subelement, bail out.
|
||||
if (SubElt.isInvalid) {
|
||||
InitExprsOk = false;
|
||||
SkipUntil(tok::r_brace, false, true);
|
||||
break;
|
||||
} else
|
||||
InitExprs.push_back(SubElt.Val);
|
||||
|
||||
// If we don't have a comma continued list, we're done.
|
||||
if (Tok.isNot(tok::comma)) break;
|
||||
|
||||
// FIXME: save comma locations.
|
||||
ConsumeToken();
|
||||
|
||||
// Handle trailing comma.
|
||||
if (Tok.is(tok::r_brace)) break;
|
||||
}
|
||||
if (InitExprsOk && Tok.is(tok::r_brace))
|
||||
return Actions.ActOnInitList(LBraceLoc, &InitExprs[0], InitExprs.size(),
|
||||
ConsumeBrace());
|
||||
// Match the '}'.
|
||||
MatchRHSPunctuation(tok::r_brace, LBraceLoc);
|
||||
return ExprResult(true); // an error occurred.
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user