From: Douglas Gregor Date: Tue, 14 Apr 2009 21:18:50 +0000 (+0000) Subject: PCH support for a few very, very simple kinds of expressions. Hook up X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0b7489194f9f89fac39d57211c1e7953ae50251f;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69075 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index fd6e210104..3f4ea122bd 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -807,6 +807,8 @@ public: bool isAnonymousStructOrUnion() const; Expr *getBitWidth() const { return BitWidth; } + void setBitWidth(Expr *BW) { BitWidth = BW; } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= FieldFirst && D->getKind() <= FieldLast; diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 6fd2970153..7001e290fc 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -63,6 +63,9 @@ protected: setType(T); } + /// \brief Construct an empty expression. + explicit Expr(StmtClass SC, EmptyShell) : Stmt(SC) { } + public: QualType getType() const { return TR; } void setType(QualType t) { @@ -88,6 +91,9 @@ public: /// @endcode 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 /// type-dependent (C++ [temp.dep.expr]), which means that its type /// could change from one template instantiation to the next. For @@ -101,6 +107,9 @@ public: /// @endcode 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 /// value objects created/interpreted by SourceManager. We assume AST /// 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) : 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; } const NamedDecl *getDecl() const { return D; } void setDecl(NamedDecl *NewD) { D = NewD; } SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } virtual SourceRange getSourceRange() const { return SourceRange(Loc); } static bool classof(const Stmt *T) { @@ -381,6 +395,10 @@ public: 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; const llvm::APInt &getValue() const { return Value; } @@ -389,6 +407,9 @@ public: /// \brief Retrieve the location of the literal. 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) { return T->getStmtClass() == IntegerLiteralClass; } @@ -411,6 +432,10 @@ public: CharacterLiteral(unsigned value, bool iswide, QualType type, SourceLocation l) : 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; } bool isWide() const { return IsWide; } @@ -418,6 +443,10 @@ public: 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) { return T->getStmtClass() == CharacterLiteralClass; } diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index c99f0a9b2f..c20d602a7c 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -210,7 +210,12 @@ public: const_child_iterator child_end() const { return const_child_iterator(const_cast(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; static Stmt* Create(llvm::Deserializer& D, ASTContext& C); diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index bda1370c6f..54f686bbb0 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -359,6 +359,24 @@ namespace clang { /// into a DeclContext via DeclContext::lookup. 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 diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 6928d26b0c..b9596b6de2 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -221,6 +221,9 @@ public: /// \brief Read a signed integral value 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 /// supplements. ASTContext &getContext() { return Context; } diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index a887e71899..4713b1e490 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -21,7 +21,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include -#include namespace llvm { class APInt; @@ -43,6 +42,10 @@ class TargetInfo; /// data structures. This bitstream can be de-serialized via an /// instance of the PCHReader class. class PCHWriter { +public: + typedef llvm::SmallVector RecordData; + +private: /// \brief The bitstream writer used to emit this precompiled header. llvm::BitstreamWriter &S; @@ -100,6 +103,13 @@ class PCHWriter { /// record. llvm::SmallVector 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 ExprsToEmit; + void WriteTargetTriple(const TargetInfo &Target); void WriteLanguageOptions(const LangOptions &LangOpts); void WriteSourceManagerBlock(SourceManager &SourceMgr); @@ -112,8 +122,6 @@ class PCHWriter { void WriteIdentifierTable(); public: - typedef llvm::SmallVector RecordData; - /// \brief Create a new precompiled header writer that outputs to /// the given bitstream. PCHWriter(llvm::BitstreamWriter &S); @@ -141,6 +149,14 @@ public: /// \brief Emit a declaration name. 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 diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index f5f6f5d41c..909ecdb100 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -16,6 +16,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclGroup.h" +#include "clang/AST/Expr.h" +#include "clang/AST/StmtVisitor.h" #include "clang/AST/Type.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" @@ -127,7 +129,8 @@ void PCHDeclReader::VisitValueDecl(ValueDecl *VD) { void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { VisitValueDecl(ECD); - // FIXME: read the initialization expression + if (Record[Idx++]) + ECD->setInitExpr(Reader.ReadExpr()); ECD->setInitVal(Reader.ReadAPSInt(Record, Idx)); } @@ -155,7 +158,8 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) { VisitValueDecl(FD); FD->setMutable(Record[Idx++]); - // FIXME: Read the bit width. + if (Record[Idx++]) + FD->setBitWidth(Reader.ReadExpr()); } void PCHDeclReader::VisitVarDecl(VarDecl *VD) { @@ -167,6 +171,8 @@ void PCHDeclReader::VisitVarDecl(VarDecl *VD) { VD->setPreviousDeclaration( cast_or_null(Reader.GetDecl(Record[Idx++]))); VD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + if (Record[Idx++]) + VD->setInit(Reader.ReadExpr()); } void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { @@ -204,6 +210,53 @@ PCHDeclReader::VisitDeclContext(DeclContext *DC) { return std::make_pair(LexicalOffset, VisibleOffset); } +//===----------------------------------------------------------------------===// +// Statement/expression deserialization +//===----------------------------------------------------------------------===// +namespace { + class VISIBILITY_HIDDEN PCHStmtReader + : public StmtVisitor { + 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(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 static bool Error(const char *Str) { std::fprintf(stderr, "%s\n", Str); @@ -755,6 +808,26 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { 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 /// structure. /// @@ -850,6 +923,10 @@ bool PCHReader::ParseLanguageOptions( /// at the given offset in the bitstream. It is a helper routine for /// GetType, which deals with reading type IDs. 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); RecordData Record; unsigned Code = Stream.ReadCode(); @@ -918,9 +995,11 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { } case pch::TYPE_VARIABLE_ARRAY: { - // FIXME: implement this - assert(false && "Unable to de-serialize variable-length array type"); - return QualType(); + QualType ElementType = GetType(Record[0]); + ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; + unsigned IndexTypeQuals = Record[2]; + return Context.getVariableArrayType(ElementType, ReadExpr(), + ASM, IndexTypeQuals); } case pch::TYPE_VECTOR: { @@ -972,9 +1051,7 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context.getTypeDeclType(cast(GetDecl(Record[0]))); case pch::TYPE_TYPEOF_EXPR: - // FIXME: Deserialize TypeOfExprType - assert(false && "Cannot de-serialize typeof(expr) from a PCH file"); - return QualType(); + return Context.getTypeOfExprType(ReadExpr()); case pch::TYPE_TYPEOF: { 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. 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; Stream.JumpToBit(Offset); RecordData Record; unsigned Code = Stream.ReadCode(); unsigned Idx = 0; PCHDeclReader Reader(*this, Record, Idx); + switch ((pch::DeclCode)Stream.ReadRecord(Code, Record)) { case pch::DECL_TRANSLATION_UNIT: 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; 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 // this context. Stream.JumpToBit(Offset); @@ -1258,6 +1344,10 @@ bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC, uint64_t Offset = DeclContextOffsets[DC].second; 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 // this context. Stream.JumpToBit(Offset); @@ -1394,6 +1484,44 @@ llvm::APSInt PCHReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) { 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) { return Diag(SourceLocation(), DiagID); } diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index c7bfa0b74e..1cf98cea9c 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -16,6 +16,8 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/StmtVisitor.h" #include "clang/AST/Type.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" @@ -122,8 +124,7 @@ void PCHTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) { void PCHTypeWriter::VisitVariableArrayType(const VariableArrayType *T) { VisitArrayType(T); - // FIXME: Serialize array size expression. - assert(false && "Cannot serialize variable-length arrays"); + Writer.AddExpr(T->getSizeExpr()); Code = pch::TYPE_VARIABLE_ARRAY; } @@ -163,8 +164,7 @@ void PCHTypeWriter::VisitTypedefType(const TypedefType *T) { } void PCHTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) { - // FIXME: serialize the typeof expression - assert(false && "Cannot serialize typeof(expr)"); + Writer.AddExpr(T->getUnderlyingExpr()); Code = pch::TYPE_TYPEOF_EXPR; } @@ -327,7 +327,9 @@ void PCHDeclWriter::VisitValueDecl(ValueDecl *D) { void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *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); Code = pch::DECL_ENUM_CONSTANT; } @@ -354,7 +356,9 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) { VisitValueDecl(D); 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; } @@ -366,7 +370,9 @@ void PCHDeclWriter::VisitVarDecl(VarDecl *D) { Record.push_back(D->isDeclaredInCondition()); Writer.AddDeclRef(D->getPreviousDeclaration(), 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; } @@ -419,6 +425,57 @@ void PCHDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, Record.push_back(VisibleOffset); } +//===----------------------------------------------------------------------===// +// Statement/expression serialization +//===----------------------------------------------------------------------===// +namespace { + class VISIBILITY_HIDDEN PCHStmtWriter + : public StmtVisitor { + + 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 //===----------------------------------------------------------------------===// @@ -513,8 +570,6 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &S) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic 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 return S.EmitAbbrev(Abbrev); } @@ -805,6 +860,9 @@ void PCHWriter::WriteType(const Type *T) { // Emit the serialized 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. @@ -937,6 +995,9 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) { assert(W.Code && "Unhandled declaration kind while generating PCH"); 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 // in the PCH file later. if (isa(D)) @@ -1160,3 +1221,26 @@ void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) { 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); + } +} diff --git a/test/PCH/enum.h b/test/PCH/enum.h index cfa8d6f3d8..c94e314eb0 100644 --- a/test/PCH/enum.h +++ b/test/PCH/enum.h @@ -8,9 +8,9 @@ enum Color { enum Shape { Square, - Triangle, + Triangle = 17, Rhombus, Circle }; -enum Shape aRoundShape = Circle; +enum Shape aRoundShape;// FIXME: = Circle; diff --git a/test/PCH/exprs.c b/test/PCH/exprs.c new file mode 100644 index 0000000000..d1cd5636b8 --- /dev/null +++ b/test/PCH/exprs.c @@ -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; diff --git a/test/PCH/exprs.h b/test/PCH/exprs.h new file mode 100644 index 0000000000..db6513c35b --- /dev/null +++ b/test/PCH/exprs.h @@ -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; diff --git a/test/PCH/external-defs.c b/test/PCH/external-defs.c index fd14c4fa8b..5af21af517 100644 --- a/test/PCH/external-defs.c +++ b/test/PCH/external-defs.c @@ -3,8 +3,7 @@ // 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 && -// FIXME below: should be i32 17, but we don't serialize y's value yet -// RUN: grep "@y = common global i32 0" %t | count 1 && +// RUN: grep "@y = global i32 17" %t | count 1 && // RUN: grep "@z" %t | count 0 && // RUN: grep "@x2 = global i32 19" %t | count 1 && diff --git a/test/PCH/external-defs.h b/test/PCH/external-defs.h index 4ac9077d12..06c4601ccb 100644 --- a/test/PCH/external-defs.h +++ b/test/PCH/external-defs.h @@ -4,7 +4,7 @@ int x; int x2; -// FIXME: check this, once we actually serialize it +// Definitions int y = 17; // Should not show up diff --git a/test/PCH/struct.c b/test/PCH/struct.c index 220f079465..5ea9fe2757 100644 --- a/test/PCH/struct.c +++ b/test/PCH/struct.c @@ -23,6 +23,8 @@ int get_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 within "struct S", so causing the following to fail. When not using PCH, this works because Sema puts the nested struct onto the diff --git a/test/PCH/struct.h b/test/PCH/struct.h index 6c256221fa..2ffdd4aea5 100644 --- a/test/PCH/struct.h +++ b/test/PCH/struct.h @@ -13,7 +13,7 @@ struct Fun; struct Fun *fun; struct Fun { - int is_ptr; + int is_ptr : 1; union { void *ptr; diff --git a/test/PCH/types.c b/test/PCH/types.c index e62a4bbe3b..425305c584 100644 --- a/test/PCH/types.c +++ b/test/PCH/types.c @@ -56,7 +56,10 @@ proto *p2 = p1; // TYPE_TYPEDEF 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 int_ptr_ptr2 ipp2 = &int_value_ptr; diff --git a/test/PCH/types.h b/test/PCH/types.h index 3713e0b690..54ab2152d7 100644 --- a/test/PCH/types.h +++ b/test/PCH/types.h @@ -35,7 +35,8 @@ typedef float proto(float, float, ...); // TYPE_TYPEDEF typedef int_ptr * int_ptr_ptr; -// FIXME: TYPE_TYPEOF_EXPR +// TYPE_TYPEOF_EXPR +typedef typeof(17) typeof_17; // TYPE_TYPEOF typedef typeof(int_ptr *) int_ptr_ptr2; diff --git a/test/PCH/variables.c b/test/PCH/variables.c index 4f42e50481..afd45461d0 100644 --- a/test/PCH/variables.c +++ b/test/PCH/variables.c @@ -9,7 +9,8 @@ int *ip2 = &x; float *fp = &ip; // expected-warning{{incompatible pointer types}} // FIXME:variables.h expected-note{{previous}} double z; // expected-error{{redefinition}} - +// FIXME:variables.h expected-note{{previous}} +int z2 = 18; // expected-error{{redefinition}} //double VeryHappy; // FIXME: xpected-error{{redefinition}} diff --git a/test/PCH/variables.h b/test/PCH/variables.h index 82e87aaf4b..70aec65180 100644 --- a/test/PCH/variables.h +++ b/test/PCH/variables.h @@ -9,7 +9,7 @@ extern int *ip, x; float z; - +int z2 = 17; #define MAKE_HAPPY(X) X##Happy int MAKE_HAPPY(Very);