PCH support for a few very, very simple kinds of expressions. Hook up

expression (de-)serialization for VLAs, variable initializers,
enum constant initializers, and bitfield widths.

llvm-svn: 69075
This commit is contained in:
Douglas Gregor 2009-04-14 21:18:50 +00:00
parent a723ba97db
commit feb84b0074
19 changed files with 355 additions and 31 deletions

View File

@ -807,6 +807,8 @@ public:
bool isAnonymousStructOrUnion() const; bool isAnonymousStructOrUnion() const;
Expr *getBitWidth() const { return BitWidth; } Expr *getBitWidth() const { return BitWidth; }
void setBitWidth(Expr *BW) { BitWidth = BW; }
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { static bool classof(const Decl *D) {
return D->getKind() >= FieldFirst && D->getKind() <= FieldLast; return D->getKind() >= FieldFirst && D->getKind() <= FieldLast;

View File

@ -63,6 +63,9 @@ protected:
setType(T); setType(T);
} }
/// \brief Construct an empty expression.
explicit Expr(StmtClass SC, EmptyShell) : Stmt(SC) { }
public: public:
QualType getType() const { return TR; } QualType getType() const { return TR; }
void setType(QualType t) { void setType(QualType t) {
@ -88,6 +91,9 @@ public:
/// @endcode /// @endcode
bool isValueDependent() const { return ValueDependent; } bool isValueDependent() const { return ValueDependent; }
/// \brief Set whether this expression is value-dependent or not.
void setValueDependent(bool VD) { ValueDependent = VD; }
/// isTypeDependent - Determines whether this expression is /// isTypeDependent - Determines whether this expression is
/// type-dependent (C++ [temp.dep.expr]), which means that its type /// type-dependent (C++ [temp.dep.expr]), which means that its type
/// could change from one template instantiation to the next. For /// could change from one template instantiation to the next. For
@ -101,6 +107,9 @@ public:
/// @endcode /// @endcode
bool isTypeDependent() const { return TypeDependent; } bool isTypeDependent() const { return TypeDependent; }
/// \brief Set whether this expression is type-dependent or not.
void setTypeDependent(bool TD) { TypeDependent = TD; }
/// SourceLocation tokens are not useful in isolation - they are low level /// SourceLocation tokens are not useful in isolation - they are low level
/// value objects created/interpreted by SourceManager. We assume AST /// value objects created/interpreted by SourceManager. We assume AST
/// clients will have a pointer to the respective SourceManager. /// clients will have a pointer to the respective SourceManager.
@ -315,11 +324,16 @@ public:
DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, bool VD) : DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, bool VD) :
Expr(DeclRefExprClass, t, TD, VD), D(d), Loc(l) {} Expr(DeclRefExprClass, t, TD, VD), D(d), Loc(l) {}
/// \brief Construct an empty declaration reference expression.
explicit DeclRefExpr(EmptyShell Empty)
: Expr(DeclRefExprClass, Empty) { }
NamedDecl *getDecl() { return D; } NamedDecl *getDecl() { return D; }
const NamedDecl *getDecl() const { return D; } const NamedDecl *getDecl() const { return D; }
void setDecl(NamedDecl *NewD) { D = NewD; } void setDecl(NamedDecl *NewD) { D = NewD; }
SourceLocation getLocation() const { return Loc; } SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
virtual SourceRange getSourceRange() const { return SourceRange(Loc); } virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
static bool classof(const Stmt *T) { static bool classof(const Stmt *T) {
@ -381,6 +395,10 @@ public:
assert(type->isIntegerType() && "Illegal type in IntegerLiteral"); assert(type->isIntegerType() && "Illegal type in IntegerLiteral");
} }
/// \brief Construct an empty integer literal.
explicit IntegerLiteral(EmptyShell Empty)
: Expr(IntegerLiteralClass, Empty) { }
IntegerLiteral* Clone(ASTContext &C) const; IntegerLiteral* Clone(ASTContext &C) const;
const llvm::APInt &getValue() const { return Value; } const llvm::APInt &getValue() const { return Value; }
@ -389,6 +407,9 @@ public:
/// \brief Retrieve the location of the literal. /// \brief Retrieve the location of the literal.
SourceLocation getLocation() const { return Loc; } SourceLocation getLocation() const { return Loc; }
void setValue(const llvm::APInt &Val) { Value = Val; }
void setLocation(SourceLocation Location) { Loc = Location; }
static bool classof(const Stmt *T) { static bool classof(const Stmt *T) {
return T->getStmtClass() == IntegerLiteralClass; return T->getStmtClass() == IntegerLiteralClass;
} }
@ -411,6 +432,10 @@ public:
CharacterLiteral(unsigned value, bool iswide, QualType type, SourceLocation l) CharacterLiteral(unsigned value, bool iswide, QualType type, SourceLocation l)
: Expr(CharacterLiteralClass, type), Value(value), Loc(l), IsWide(iswide) { : Expr(CharacterLiteralClass, type), Value(value), Loc(l), IsWide(iswide) {
} }
/// \brief Construct an empty character literal.
CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { }
SourceLocation getLoc() const { return Loc; } SourceLocation getLoc() const { return Loc; }
bool isWide() const { return IsWide; } bool isWide() const { return IsWide; }
@ -418,6 +443,10 @@ public:
unsigned getValue() const { return Value; } unsigned getValue() const { return Value; }
void setLocation(SourceLocation Location) { Loc = Location; }
void setWide(bool W) { IsWide = W; }
void setValue(unsigned Val) { Value = Val; }
static bool classof(const Stmt *T) { static bool classof(const Stmt *T) {
return T->getStmtClass() == CharacterLiteralClass; return T->getStmtClass() == CharacterLiteralClass;
} }

View File

@ -210,7 +210,12 @@ public:
const_child_iterator child_end() const { const_child_iterator child_end() const {
return const_child_iterator(const_cast<Stmt*>(this)->child_end()); return const_child_iterator(const_cast<Stmt*>(this)->child_end());
} }
/// \brief A placeholder type used to construct an empty shell of a
/// type, that will be filled in later (e.g., by some
/// de-serialization).
struct EmptyShell { };
void Emit(llvm::Serializer& S) const; void Emit(llvm::Serializer& S) const;
static Stmt* Create(llvm::Deserializer& D, ASTContext& C); static Stmt* Create(llvm::Deserializer& D, ASTContext& C);

View File

@ -359,6 +359,24 @@ namespace clang {
/// into a DeclContext via DeclContext::lookup. /// into a DeclContext via DeclContext::lookup.
DECL_CONTEXT_VISIBLE DECL_CONTEXT_VISIBLE
}; };
/// \brief Record codes for each kind of statement or expression.
///
/// These constants describe the records that describe statements
/// or expressions. These records can occur within either the type
/// or declaration blocks, so they begin with record values of
/// 100. Each constant describes a record for a specific
/// statement or expression class in the AST.
enum StmtCode {
/// \brief A NULL expression.
EXPR_NULL = 100,
/// \brief A DeclRefExpr record.
EXPR_DECL_REF,
/// \brief An IntegerLiteral record.
EXPR_INTEGER_LITERAL,
/// \brief A CharacterLiteral record.
EXPR_CHARACTER_LITERAL
};
/// @} /// @}
} }
} // end namespace clang } // end namespace clang

View File

@ -221,6 +221,9 @@ public:
/// \brief Read a signed integral value /// \brief Read a signed integral value
llvm::APSInt ReadAPSInt(const RecordData &Record, unsigned &Idx); llvm::APSInt ReadAPSInt(const RecordData &Record, unsigned &Idx);
/// \brief Reads an expression from the current stream position.
Expr *ReadExpr();
/// \brief Retrieve the AST context that this PCH reader /// \brief Retrieve the AST context that this PCH reader
/// supplements. /// supplements.
ASTContext &getContext() { return Context; } ASTContext &getContext() { return Context; }

View File

@ -21,7 +21,6 @@
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include <queue> #include <queue>
#include <vector>
namespace llvm { namespace llvm {
class APInt; class APInt;
@ -43,6 +42,10 @@ class TargetInfo;
/// data structures. This bitstream can be de-serialized via an /// data structures. This bitstream can be de-serialized via an
/// instance of the PCHReader class. /// instance of the PCHReader class.
class PCHWriter { class PCHWriter {
public:
typedef llvm::SmallVector<uint64_t, 64> RecordData;
private:
/// \brief The bitstream writer used to emit this precompiled header. /// \brief The bitstream writer used to emit this precompiled header.
llvm::BitstreamWriter &S; llvm::BitstreamWriter &S;
@ -100,6 +103,13 @@ class PCHWriter {
/// record. /// record.
llvm::SmallVector<uint64_t, 16> ExternalDefinitions; llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
/// \brief Expressions that we've encountered while serializing a
/// declaration or type.
///
/// The expressions in this queue will be emitted following the
/// declaration or type.
std::queue<Expr *> ExprsToEmit;
void WriteTargetTriple(const TargetInfo &Target); void WriteTargetTriple(const TargetInfo &Target);
void WriteLanguageOptions(const LangOptions &LangOpts); void WriteLanguageOptions(const LangOptions &LangOpts);
void WriteSourceManagerBlock(SourceManager &SourceMgr); void WriteSourceManagerBlock(SourceManager &SourceMgr);
@ -112,8 +122,6 @@ class PCHWriter {
void WriteIdentifierTable(); void WriteIdentifierTable();
public: public:
typedef llvm::SmallVector<uint64_t, 64> RecordData;
/// \brief Create a new precompiled header writer that outputs to /// \brief Create a new precompiled header writer that outputs to
/// the given bitstream. /// the given bitstream.
PCHWriter(llvm::BitstreamWriter &S); PCHWriter(llvm::BitstreamWriter &S);
@ -141,6 +149,14 @@ public:
/// \brief Emit a declaration name. /// \brief Emit a declaration name.
void AddDeclarationName(DeclarationName Name, RecordData &Record); void AddDeclarationName(DeclarationName Name, RecordData &Record);
/// \brief Add the given expression to the queue of expressions to
/// emit.
void AddExpr(Expr *E) { ExprsToEmit.push(E); }
/// \brief Flush all of the expressions that have been added to the
/// queue via AddExpr().
void FlushExprs();
}; };
} // end namespace clang } // end namespace clang

View File

@ -16,6 +16,8 @@
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h" #include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h" #include "clang/AST/DeclGroup.h"
#include "clang/AST/Expr.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Type.h" #include "clang/AST/Type.h"
#include "clang/Lex/MacroInfo.h" #include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h" #include "clang/Lex/Preprocessor.h"
@ -127,7 +129,8 @@ void PCHDeclReader::VisitValueDecl(ValueDecl *VD) {
void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
VisitValueDecl(ECD); VisitValueDecl(ECD);
// FIXME: read the initialization expression if (Record[Idx++])
ECD->setInitExpr(Reader.ReadExpr());
ECD->setInitVal(Reader.ReadAPSInt(Record, Idx)); ECD->setInitVal(Reader.ReadAPSInt(Record, Idx));
} }
@ -155,7 +158,8 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) { void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) {
VisitValueDecl(FD); VisitValueDecl(FD);
FD->setMutable(Record[Idx++]); FD->setMutable(Record[Idx++]);
// FIXME: Read the bit width. if (Record[Idx++])
FD->setBitWidth(Reader.ReadExpr());
} }
void PCHDeclReader::VisitVarDecl(VarDecl *VD) { void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
@ -167,6 +171,8 @@ void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
VD->setPreviousDeclaration( VD->setPreviousDeclaration(
cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
VD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); VD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
if (Record[Idx++])
VD->setInit(Reader.ReadExpr());
} }
void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
@ -204,6 +210,53 @@ PCHDeclReader::VisitDeclContext(DeclContext *DC) {
return std::make_pair(LexicalOffset, VisibleOffset); return std::make_pair(LexicalOffset, VisibleOffset);
} }
//===----------------------------------------------------------------------===//
// Statement/expression deserialization
//===----------------------------------------------------------------------===//
namespace {
class VISIBILITY_HIDDEN PCHStmtReader
: public StmtVisitor<PCHStmtReader, void> {
PCHReader &Reader;
const PCHReader::RecordData &Record;
unsigned &Idx;
public:
PCHStmtReader(PCHReader &Reader, const PCHReader::RecordData &Record,
unsigned &Idx)
: Reader(Reader), Record(Record), Idx(Idx) { }
void VisitExpr(Expr *E);
void VisitDeclRefExpr(DeclRefExpr *E);
void VisitIntegerLiteral(IntegerLiteral *E);
void VisitCharacterLiteral(CharacterLiteral *E);
};
}
void PCHStmtReader::VisitExpr(Expr *E) {
E->setType(Reader.GetType(Record[Idx++]));
E->setTypeDependent(Record[Idx++]);
E->setValueDependent(Record[Idx++]);
}
void PCHStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
VisitExpr(E);
E->setDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
void PCHStmtReader::VisitIntegerLiteral(IntegerLiteral *E) {
VisitExpr(E);
E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
E->setValue(Reader.ReadAPInt(Record, Idx));
}
void PCHStmtReader::VisitCharacterLiteral(CharacterLiteral *E) {
VisitExpr(E);
E->setValue(Record[Idx++]);
E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
E->setWide(Record[Idx++]);
}
// FIXME: use the diagnostics machinery // FIXME: use the diagnostics machinery
static bool Error(const char *Str) { static bool Error(const char *Str) {
std::fprintf(stderr, "%s\n", Str); std::fprintf(stderr, "%s\n", Str);
@ -755,6 +808,26 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
return Success; return Success;
} }
namespace {
/// \brief Helper class that saves the current stream position and
/// then restores it when destroyed.
struct VISIBILITY_HIDDEN SavedStreamPosition {
explicit SavedStreamPosition(llvm::BitstreamReader &Stream)
: Stream(Stream), Offset(Stream.GetCurrentBitNo()),
EndOfStream(Stream.AtEndOfStream()){ }
~SavedStreamPosition() {
if (!EndOfStream)
Stream.JumpToBit(Offset);
}
private:
llvm::BitstreamReader &Stream;
uint64_t Offset;
bool EndOfStream;
};
}
/// \brief Parse the record that corresponds to a LangOptions data /// \brief Parse the record that corresponds to a LangOptions data
/// structure. /// structure.
/// ///
@ -850,6 +923,10 @@ bool PCHReader::ParseLanguageOptions(
/// at the given offset in the bitstream. It is a helper routine for /// at the given offset in the bitstream. It is a helper routine for
/// GetType, which deals with reading type IDs. /// GetType, which deals with reading type IDs.
QualType PCHReader::ReadTypeRecord(uint64_t Offset) { QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
// Keep track of where we are in the stream, then jump back there
// after reading this type.
SavedStreamPosition SavedPosition(Stream);
Stream.JumpToBit(Offset); Stream.JumpToBit(Offset);
RecordData Record; RecordData Record;
unsigned Code = Stream.ReadCode(); unsigned Code = Stream.ReadCode();
@ -918,9 +995,11 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
} }
case pch::TYPE_VARIABLE_ARRAY: { case pch::TYPE_VARIABLE_ARRAY: {
// FIXME: implement this QualType ElementType = GetType(Record[0]);
assert(false && "Unable to de-serialize variable-length array type"); ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
return QualType(); unsigned IndexTypeQuals = Record[2];
return Context.getVariableArrayType(ElementType, ReadExpr(),
ASM, IndexTypeQuals);
} }
case pch::TYPE_VECTOR: { case pch::TYPE_VECTOR: {
@ -972,9 +1051,7 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
return Context.getTypeDeclType(cast<TypedefDecl>(GetDecl(Record[0]))); return Context.getTypeDeclType(cast<TypedefDecl>(GetDecl(Record[0])));
case pch::TYPE_TYPEOF_EXPR: case pch::TYPE_TYPEOF_EXPR:
// FIXME: Deserialize TypeOfExprType return Context.getTypeOfExprType(ReadExpr());
assert(false && "Cannot de-serialize typeof(expr) from a PCH file");
return QualType();
case pch::TYPE_TYPEOF: { case pch::TYPE_TYPEOF: {
if (Record.size() != 1) { if (Record.size() != 1) {
@ -1032,12 +1109,17 @@ inline void PCHReader::LoadedDecl(unsigned Index, Decl *D) {
/// \brief Read the declaration at the given offset from the PCH file. /// \brief Read the declaration at the given offset from the PCH file.
Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
// Keep track of where we are in the stream, then jump back there
// after reading this declaration.
SavedStreamPosition SavedPosition(Stream);
Decl *D = 0; Decl *D = 0;
Stream.JumpToBit(Offset); Stream.JumpToBit(Offset);
RecordData Record; RecordData Record;
unsigned Code = Stream.ReadCode(); unsigned Code = Stream.ReadCode();
unsigned Idx = 0; unsigned Idx = 0;
PCHDeclReader Reader(*this, Record, Idx); PCHDeclReader Reader(*this, Record, Idx);
switch ((pch::DeclCode)Stream.ReadRecord(Code, Record)) { switch ((pch::DeclCode)Stream.ReadRecord(Code, Record)) {
case pch::DECL_TRANSLATION_UNIT: case pch::DECL_TRANSLATION_UNIT:
assert(Index == 0 && "Translation unit must be at index 0"); assert(Index == 0 && "Translation unit must be at index 0");
@ -1237,6 +1319,10 @@ bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
uint64_t Offset = DeclContextOffsets[DC].first; uint64_t Offset = DeclContextOffsets[DC].first;
assert(Offset && "DeclContext has no lexical decls in storage"); assert(Offset && "DeclContext has no lexical decls in storage");
// Keep track of where we are in the stream, then jump back there
// after reading this context.
SavedStreamPosition SavedPosition(Stream);
// Load the record containing all of the declarations lexically in // Load the record containing all of the declarations lexically in
// this context. // this context.
Stream.JumpToBit(Offset); Stream.JumpToBit(Offset);
@ -1258,6 +1344,10 @@ bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC,
uint64_t Offset = DeclContextOffsets[DC].second; uint64_t Offset = DeclContextOffsets[DC].second;
assert(Offset && "DeclContext has no visible decls in storage"); assert(Offset && "DeclContext has no visible decls in storage");
// Keep track of where we are in the stream, then jump back there
// after reading this context.
SavedStreamPosition SavedPosition(Stream);
// Load the record containing all of the declarations visible in // Load the record containing all of the declarations visible in
// this context. // this context.
Stream.JumpToBit(Offset); Stream.JumpToBit(Offset);
@ -1394,6 +1484,44 @@ llvm::APSInt PCHReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) {
return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned); return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned);
} }
Expr *PCHReader::ReadExpr() {
RecordData Record;
unsigned Code = Stream.ReadCode();
unsigned Idx = 0;
PCHStmtReader Reader(*this, Record, Idx);
Stmt::EmptyShell Empty;
Expr *E = 0;
switch ((pch::StmtCode)Stream.ReadRecord(Code, Record)) {
case pch::EXPR_NULL:
E = 0;
break;
case pch::EXPR_DECL_REF:
E = new (Context) DeclRefExpr(Empty);
break;
case pch::EXPR_INTEGER_LITERAL:
E = new (Context) IntegerLiteral(Empty);
break;
case pch::EXPR_CHARACTER_LITERAL:
E = new (Context) CharacterLiteral(Empty);
break;
default:
assert(false && "Unhandled expression kind");
break;
}
if (E)
Reader.Visit(E);
assert(Idx == Record.size() && "Invalid deserialization of expression");
return E;
}
DiagnosticBuilder PCHReader::Diag(unsigned DiagID) { DiagnosticBuilder PCHReader::Diag(unsigned DiagID) {
return Diag(SourceLocation(), DiagID); return Diag(SourceLocation(), DiagID);
} }

View File

@ -16,6 +16,8 @@
#include "clang/AST/Decl.h" #include "clang/AST/Decl.h"
#include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclVisitor.h" #include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Type.h" #include "clang/AST/Type.h"
#include "clang/Lex/MacroInfo.h" #include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h" #include "clang/Lex/Preprocessor.h"
@ -122,8 +124,7 @@ void PCHTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) {
void PCHTypeWriter::VisitVariableArrayType(const VariableArrayType *T) { void PCHTypeWriter::VisitVariableArrayType(const VariableArrayType *T) {
VisitArrayType(T); VisitArrayType(T);
// FIXME: Serialize array size expression. Writer.AddExpr(T->getSizeExpr());
assert(false && "Cannot serialize variable-length arrays");
Code = pch::TYPE_VARIABLE_ARRAY; Code = pch::TYPE_VARIABLE_ARRAY;
} }
@ -163,8 +164,7 @@ void PCHTypeWriter::VisitTypedefType(const TypedefType *T) {
} }
void PCHTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) { void PCHTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) {
// FIXME: serialize the typeof expression Writer.AddExpr(T->getUnderlyingExpr());
assert(false && "Cannot serialize typeof(expr)");
Code = pch::TYPE_TYPEOF_EXPR; Code = pch::TYPE_TYPEOF_EXPR;
} }
@ -327,7 +327,9 @@ void PCHDeclWriter::VisitValueDecl(ValueDecl *D) {
void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
VisitValueDecl(D); VisitValueDecl(D);
// FIXME: Writer.AddExprRef(D->getInitExpr()); Record.push_back(D->getInitExpr()? 1 : 0);
if (D->getInitExpr())
Writer.AddExpr(D->getInitExpr());
Writer.AddAPSInt(D->getInitVal(), Record); Writer.AddAPSInt(D->getInitVal(), Record);
Code = pch::DECL_ENUM_CONSTANT; Code = pch::DECL_ENUM_CONSTANT;
} }
@ -354,7 +356,9 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) { void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) {
VisitValueDecl(D); VisitValueDecl(D);
Record.push_back(D->isMutable()); Record.push_back(D->isMutable());
// FIXME: Writer.AddExprRef(D->getBitWidth()); Record.push_back(D->getBitWidth()? 1 : 0);
if (D->getBitWidth())
Writer.AddExpr(D->getBitWidth());
Code = pch::DECL_FIELD; Code = pch::DECL_FIELD;
} }
@ -366,7 +370,9 @@ void PCHDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->isDeclaredInCondition()); Record.push_back(D->isDeclaredInCondition());
Writer.AddDeclRef(D->getPreviousDeclaration(), Record); Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
Writer.AddSourceLocation(D->getTypeSpecStartLoc(), Record); Writer.AddSourceLocation(D->getTypeSpecStartLoc(), Record);
// FIXME: emit initializer Record.push_back(D->getInit()? 1 : 0);
if (D->getInit())
Writer.AddExpr(D->getInit());
Code = pch::DECL_VAR; Code = pch::DECL_VAR;
} }
@ -419,6 +425,57 @@ void PCHDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
Record.push_back(VisibleOffset); Record.push_back(VisibleOffset);
} }
//===----------------------------------------------------------------------===//
// Statement/expression serialization
//===----------------------------------------------------------------------===//
namespace {
class VISIBILITY_HIDDEN PCHStmtWriter
: public StmtVisitor<PCHStmtWriter, void> {
PCHWriter &Writer;
PCHWriter::RecordData &Record;
public:
pch::StmtCode Code;
PCHStmtWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
: Writer(Writer), Record(Record) { }
void VisitExpr(Expr *E);
void VisitDeclRefExpr(DeclRefExpr *E);
void VisitIntegerLiteral(IntegerLiteral *E);
void VisitCharacterLiteral(CharacterLiteral *E);
};
}
void PCHStmtWriter::VisitExpr(Expr *E) {
Writer.AddTypeRef(E->getType(), Record);
Record.push_back(E->isTypeDependent());
Record.push_back(E->isValueDependent());
}
void PCHStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
VisitExpr(E);
Writer.AddDeclRef(E->getDecl(), Record);
Writer.AddSourceLocation(E->getLocation(), Record);
Code = pch::EXPR_DECL_REF;
}
void PCHStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) {
VisitExpr(E);
Writer.AddSourceLocation(E->getLocation(), Record);
Writer.AddAPInt(E->getValue(), Record);
Code = pch::EXPR_INTEGER_LITERAL;
}
void PCHStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) {
VisitExpr(E);
Record.push_back(E->getValue());
Writer.AddSourceLocation(E->getLoc(), Record);
Record.push_back(E->isWide());
Code = pch::EXPR_CHARACTER_LITERAL;
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// PCHWriter Implementation // PCHWriter Implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -513,8 +570,6 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &S) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
// FIXME: Need an actual encoding for the line directives; maybe
// this should be an array?
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
return S.EmitAbbrev(Abbrev); return S.EmitAbbrev(Abbrev);
} }
@ -805,6 +860,9 @@ void PCHWriter::WriteType(const Type *T) {
// Emit the serialized record. // Emit the serialized record.
S.EmitRecord(W.Code, Record); S.EmitRecord(W.Code, Record);
// Flush any expressions that were written as part of this type.
FlushExprs();
} }
/// \brief Write a block containing all of the types. /// \brief Write a block containing all of the types.
@ -937,6 +995,9 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) {
assert(W.Code && "Unhandled declaration kind while generating PCH"); assert(W.Code && "Unhandled declaration kind while generating PCH");
S.EmitRecord(W.Code, Record); S.EmitRecord(W.Code, Record);
// Flush any expressions that were written as part of this declaration.
FlushExprs();
// Note external declarations so that we can add them to a record // Note external declarations so that we can add them to a record
// in the PCH file later. // in the PCH file later.
if (isa<FileScopeAsmDecl>(D)) if (isa<FileScopeAsmDecl>(D))
@ -1160,3 +1221,26 @@ void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) {
break; break;
} }
} }
/// \brief Flush all of the expressions that have been added to the
/// queue via AddExpr().
void PCHWriter::FlushExprs() {
RecordData Record;
PCHStmtWriter Writer(*this, Record);
while (!ExprsToEmit.empty()) {
Expr *E = ExprsToEmit.front();
ExprsToEmit.pop();
Record.clear();
if (!E) {
S.EmitRecord(pch::EXPR_NULL, Record);
continue;
}
Writer.Code = pch::EXPR_NULL;
Writer.Visit(E);
assert(Writer.Code != pch::EXPR_NULL &&
"Unhandled expression writing PCH file");
S.EmitRecord(Writer.Code, Record);
}
}

View File

@ -8,9 +8,9 @@ enum Color {
enum Shape { enum Shape {
Square, Square,
Triangle, Triangle = 17,
Rhombus, Rhombus,
Circle Circle
}; };
enum Shape aRoundShape = Circle; enum Shape aRoundShape;// FIXME: = Circle;

19
clang/test/PCH/exprs.c Normal file
View File

@ -0,0 +1,19 @@
// Test this without pch.
// RUN: clang-cc -fblocks -include %S/exprs.h -fsyntax-only -verify %s
// Test with pch.
// RUN: clang-cc -emit-pch -fblocks -o %t %S/exprs.h &&
// RUN: clang-cc -fblocks -include-pch %t -fsyntax-only -verify %s
int integer;
long long_integer;
// DeclRefExpr
int_decl_ref *int_ptr1 = &integer;
enum_decl_ref *enum_ptr1 = &integer;
// IntegerLiteralExpr
integer_literal *int_ptr2 = &integer;
long_literal *long_ptr1 = &long_integer;
// CharacterLiteralExpr
char_literal *int_ptr3 = &integer;

14
clang/test/PCH/exprs.h Normal file
View File

@ -0,0 +1,14 @@
// Header for PCH test exprs.c
// DeclRefExpr
int i = 17;
enum Enum { Enumerator = 18 };
typedef typeof(i) int_decl_ref;
typedef typeof(Enumerator) enum_decl_ref;
// IntegerLiteralExpr
typedef typeof(17) integer_literal;
typedef typeof(17l) long_literal;
// CharacterLiteralExpr
typedef typeof('a') char_literal;

View File

@ -3,8 +3,7 @@
// RUN: clang-cc -triple x86_64-apple-darwin9 -include-pch %t.pch -emit-llvm -o %t %s && // RUN: clang-cc -triple x86_64-apple-darwin9 -include-pch %t.pch -emit-llvm -o %t %s &&
// RUN: grep "@x = common global i32 0" %t | count 1 && // RUN: grep "@x = common global i32 0" %t | count 1 &&
// FIXME below: should be i32 17, but we don't serialize y's value yet // RUN: grep "@y = global i32 17" %t | count 1 &&
// RUN: grep "@y = common global i32 0" %t | count 1 &&
// RUN: grep "@z" %t | count 0 && // RUN: grep "@z" %t | count 0 &&
// RUN: grep "@x2 = global i32 19" %t | count 1 && // RUN: grep "@x2 = global i32 19" %t | count 1 &&

View File

@ -4,7 +4,7 @@
int x; int x;
int x2; int x2;
// FIXME: check this, once we actually serialize it // Definitions
int y = 17; int y = 17;
// Should not show up // Should not show up

View File

@ -23,6 +23,8 @@ int get_very_fun() {
return fun2->very_fun; return fun2->very_fun;
} }
int *int_ptr_fail = &fun->is_ptr; // expected-error{{address of bit-field requested}}
/* FIXME: DeclContexts aren't yet able to find "struct Nested" nested /* FIXME: DeclContexts aren't yet able to find "struct Nested" nested
within "struct S", so causing the following to fail. When not using within "struct S", so causing the following to fail. When not using
PCH, this works because Sema puts the nested struct onto the PCH, this works because Sema puts the nested struct onto the

View File

@ -13,7 +13,7 @@ struct Fun;
struct Fun *fun; struct Fun *fun;
struct Fun { struct Fun {
int is_ptr; int is_ptr : 1;
union { union {
void *ptr; void *ptr;

View File

@ -56,7 +56,10 @@ proto *p2 = p1;
// TYPE_TYPEDEF // TYPE_TYPEDEF
int_ptr_ptr ipp = &int_value_ptr; int_ptr_ptr ipp = &int_value_ptr;
// FIXME: TYPE_TYPEOF_EXPR // TYPE_TYPEOF_EXPR
typeof_17 *t17 = &int_value;
struct S { int x, y; };
typeof_17 t17_2 = (struct S){1, 2}; // expected-error{{incompatible type initializing}}
// TYPE_TYPEOF // TYPE_TYPEOF
int_ptr_ptr2 ipp2 = &int_value_ptr; int_ptr_ptr2 ipp2 = &int_value_ptr;

View File

@ -35,7 +35,8 @@ typedef float proto(float, float, ...);
// TYPE_TYPEDEF // TYPE_TYPEDEF
typedef int_ptr * int_ptr_ptr; typedef int_ptr * int_ptr_ptr;
// FIXME: TYPE_TYPEOF_EXPR // TYPE_TYPEOF_EXPR
typedef typeof(17) typeof_17;
// TYPE_TYPEOF // TYPE_TYPEOF
typedef typeof(int_ptr *) int_ptr_ptr2; typedef typeof(int_ptr *) int_ptr_ptr2;

View File

@ -9,7 +9,8 @@ int *ip2 = &x;
float *fp = &ip; // expected-warning{{incompatible pointer types}} float *fp = &ip; // expected-warning{{incompatible pointer types}}
// FIXME:variables.h expected-note{{previous}} // FIXME:variables.h expected-note{{previous}}
double z; // expected-error{{redefinition}} double z; // expected-error{{redefinition}}
// FIXME:variables.h expected-note{{previous}}
int z2 = 18; // expected-error{{redefinition}}
//double VeryHappy; // FIXME: xpected-error{{redefinition}} //double VeryHappy; // FIXME: xpected-error{{redefinition}}

View File

@ -9,7 +9,7 @@ extern int *ip, x;
float z; float z;
int z2 = 17;
#define MAKE_HAPPY(X) X##Happy #define MAKE_HAPPY(X) X##Happy
int MAKE_HAPPY(Very); int MAKE_HAPPY(Very);