зеркало из https://github.com/microsoft/clang-1.git
Various minor fixes to PCH reading and writing, with general
cleanup. Aside from a minor tweak to the PCH file format, no functionality change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68793 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
f04ad69fed
Коммит
8038d5182b
|
@ -549,6 +549,7 @@ public:
|
|||
/// this context.
|
||||
decl_iterator decls_begin(ASTContext &Context) const;
|
||||
decl_iterator decls_end(ASTContext &Context) const;
|
||||
bool decls_empty(ASTContext &Context) const;
|
||||
|
||||
/// specific_decl_iterator - Iterates over a subrange of
|
||||
/// declarations stored in a DeclContext, providing only those that
|
||||
|
|
|
@ -112,7 +112,7 @@ public:
|
|||
if (VectorTy *Vector = getAsVector())
|
||||
delete Vector;
|
||||
|
||||
if (Vec.size() == 0)
|
||||
if (Vec.empty())
|
||||
Data = 0;
|
||||
else
|
||||
Data = (Vec[0] << 2) | DK_DeclID;
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Decl;
|
||||
|
|
|
@ -22,8 +22,24 @@
|
|||
|
||||
namespace clang {
|
||||
namespace pch {
|
||||
const int IDBits = 32;
|
||||
typedef uint32_t ID;
|
||||
/// \brief An ID number that refers to a declaration in a PCH file.
|
||||
///
|
||||
/// The ID numbers of types are consecutive (in order of
|
||||
/// discovery) and start at 2. 0 is reserved for NULL, and 1 is
|
||||
/// reserved for the translation unit declaration.
|
||||
typedef uint32_t DeclID;
|
||||
|
||||
/// \brief An ID number that refers to a type in a PCH file.
|
||||
///
|
||||
/// The ID of a type is partitioned into two parts: the lower
|
||||
/// three bits are used to store the const/volatile/restrict
|
||||
/// qualifiers (as with QualType) and the upper bits provide a
|
||||
/// type index. The type index values are partitioned into two
|
||||
/// sets. The values below NUM_PREDEF_TYPE_IDs are predefined type
|
||||
/// IDs (based on the PREDEF_TYPE_*_ID constants), with 0 as a
|
||||
/// placeholder for "no type". Values from NUM_PREDEF_TYPE_IDs are
|
||||
/// other types that have serialized representations.
|
||||
typedef uint32_t TypeID;
|
||||
|
||||
/// \brief Describes the various kinds of blocks that occur within
|
||||
/// a PCH file.
|
||||
|
@ -48,23 +64,39 @@ namespace clang {
|
|||
/// types used within the PCH file.
|
||||
TYPES_BLOCK_ID,
|
||||
|
||||
/// \brief The block containing the offsets of all of the types
|
||||
/// used within the PCH.
|
||||
///
|
||||
/// The offsets in this block point into the block identified by
|
||||
/// TYPES_BLOCK_ID, and are indexed by the type ID.
|
||||
TYPE_OFFSETS_BLOCK_ID,
|
||||
|
||||
/// \brief The block containing the definitions of all of the
|
||||
/// declarations stored in the PCH file.
|
||||
DECLS_BLOCK_ID,
|
||||
DECLS_BLOCK_ID
|
||||
};
|
||||
|
||||
/// \brief The block containing the offsets of all of the
|
||||
/// declarations stored within the PCH file.
|
||||
/// \brief Record types that occur within the PCH block itself.
|
||||
enum PCHRecordTypes {
|
||||
/// \brief Offset of each type within the types block.
|
||||
///
|
||||
/// The offsets in this block point into the block identified by
|
||||
/// DECLS_BLOCK_ID, and are indexed by the decaration ID.
|
||||
DECL_OFFSETS_BLOCK_ID
|
||||
/// The TYPE_OFFSET constant describes the record that occurs
|
||||
/// within the block identified by TYPE_OFFSETS_BLOCK_ID within
|
||||
/// the PCH file. The record itself is an array of offsets that
|
||||
/// point into the types block (identified by TYPES_BLOCK_ID in
|
||||
/// the PCH file). The index into the array is based on the ID
|
||||
/// of a type. For a given type ID @c T, the lower three bits of
|
||||
/// @c T are its qualifiers (const, volatile, restrict), as in
|
||||
/// the QualType class. The upper bits, after being shifted and
|
||||
/// subtracting NUM_PREDEF_TYPE_IDS, are used to index into the
|
||||
/// TYPE_OFFSET block to determine the offset of that type's
|
||||
/// corresponding record within the TYPES_BLOCK_ID block.
|
||||
TYPE_OFFSET = 1,
|
||||
|
||||
/// \brief Record code for the offsets of each decl.
|
||||
///
|
||||
/// The DECL_OFFSET constant describes the record that occurs
|
||||
/// within the block identifier by DECL_OFFSETS_BLOCK_ID within
|
||||
/// the PCH file. The record itself is an array of offsets that
|
||||
/// point into the declarations block (identified by
|
||||
/// DECLS_BLOCK_ID). The declaration ID is an index into this
|
||||
/// record, after subtracting one to account for the use of
|
||||
/// declaration ID 0 for a NULL declaration pointer. Index 0 is
|
||||
/// reserved for the translation unit declaration.
|
||||
DECL_OFFSET = 2
|
||||
};
|
||||
|
||||
/// \brief Record types used within a source manager block.
|
||||
|
@ -209,20 +241,6 @@ namespace clang {
|
|||
|
||||
/// \brief Record code for the offsets of each type.
|
||||
///
|
||||
/// The TYPE_OFFSET constant describes the record that occurs
|
||||
/// within the block identified by TYPE_OFFSETS_BLOCK_ID within
|
||||
/// the PCH file. The record itself is an array of offsets that
|
||||
/// point into the types block (identified by TYPES_BLOCK_ID in
|
||||
/// the PCH file). The index into the array is based on the ID of
|
||||
/// a type. For a given type ID @c T, the lower three bits of @c T
|
||||
/// are its qualifiers (const, volatile, restrict), as in the
|
||||
/// QualType class. The upper bits, after being shifted and
|
||||
/// subtracting NUM_PREDEF_TYPE_IDS, are used to index into the
|
||||
/// TYPE_OFFSET block to determine the offset of that type's
|
||||
/// corresponding record within the TYPES_BLOCK_ID block.
|
||||
enum TypeOffsetCode {
|
||||
TYPE_OFFSET = 1
|
||||
};
|
||||
|
||||
/// \brief Record codes for each kind of declaration.
|
||||
///
|
||||
|
@ -255,21 +273,6 @@ namespace clang {
|
|||
/// into a DeclContext via DeclContext::lookup.
|
||||
DECL_CONTEXT_VISIBLE
|
||||
};
|
||||
|
||||
/// \brief Record code for the offsets of each decl.
|
||||
///
|
||||
/// The DECL_OFFSET constant describes the record that occurs
|
||||
/// within the block identifier by DECL_OFFSETS_BLOCK_ID within
|
||||
/// the PCH file. The record itself is an array of offsets that
|
||||
/// point into the declarations block (identified by
|
||||
/// DECLS_BLOCK_ID). The declaration ID is an index into this
|
||||
/// record, after subtracting one to account for the use of
|
||||
/// declaration ID 0 for a NULL declaration pointer. Index 0 is
|
||||
/// reserved for the translation unit declaration.
|
||||
enum DeclOffsetCode {
|
||||
DECL_OFFSET = 1
|
||||
};
|
||||
|
||||
/// @}
|
||||
}
|
||||
} // end namespace clang
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/ExternalASTSource.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Frontend/PCHBitCodes.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
@ -100,8 +101,6 @@ class PCHReader : public ExternalASTSource {
|
|||
|
||||
bool ReadPCHBlock();
|
||||
bool ReadSourceManagerBlock();
|
||||
bool ReadTypeOffsets();
|
||||
bool ReadDeclOffsets();
|
||||
|
||||
QualType ReadTypeRecord(uint64_t Offset);
|
||||
void LoadedDecl(unsigned Index, Decl *D);
|
||||
|
@ -122,11 +121,11 @@ public:
|
|||
|
||||
/// \brief Resolve a type ID into a type, potentially building a new
|
||||
/// type.
|
||||
virtual QualType GetType(unsigned ID);
|
||||
virtual QualType GetType(pch::TypeID ID);
|
||||
|
||||
/// \brief Resolve a declaration ID into a declaration, potentially
|
||||
/// building a new declaration.
|
||||
virtual Decl *GetDecl(unsigned ID);
|
||||
virtual Decl *GetDecl(pch::DeclID ID);
|
||||
|
||||
/// \brief Read all of the declarations lexically stored in a
|
||||
/// declaration context.
|
||||
|
|
|
@ -50,7 +50,7 @@ class PCHWriter {
|
|||
/// The ID numbers of declarations are consecutive (in order of
|
||||
/// discovery) and start at 2. 1 is reserved for the translation
|
||||
/// unit, while 0 is reserved for NULL.
|
||||
llvm::DenseMap<const Decl *, pch::ID> DeclIDs;
|
||||
llvm::DenseMap<const Decl *, pch::DeclID> DeclIDs;
|
||||
|
||||
/// \brief Offset of each declaration in the bitstream, indexed by
|
||||
/// the declaration's ID.
|
||||
|
@ -67,14 +67,14 @@ class PCHWriter {
|
|||
/// and start at 1. 0 is reserved for NULL. When types are actually
|
||||
/// stored in the stream, the ID number is shifted by 3 bits to
|
||||
/// allow for the const/volatile/restrict qualifiers.
|
||||
llvm::DenseMap<const Type *, pch::ID> TypeIDs;
|
||||
llvm::DenseMap<const Type *, pch::TypeID> TypeIDs;
|
||||
|
||||
/// \brief Offset of each type in the bitstream, indexed by
|
||||
/// the type's ID.
|
||||
llvm::SmallVector<uint64_t, 16> TypeOffsets;
|
||||
|
||||
/// \brief The type ID that will be assigned to the next new type.
|
||||
unsigned NextTypeID;
|
||||
pch::TypeID NextTypeID;
|
||||
|
||||
void WriteSourceManagerBlock(SourceManager &SourceMgr);
|
||||
void WritePreprocessor(Preprocessor &PP);
|
||||
|
|
|
@ -519,6 +519,13 @@ DeclContext::decl_iterator DeclContext::decls_end(ASTContext &Context) const {
|
|||
return decl_iterator();
|
||||
}
|
||||
|
||||
bool DeclContext::decls_empty(ASTContext &Context) const {
|
||||
if (hasExternalLexicalStorage())
|
||||
LoadLexicalDeclsFromExternalStorage(Context);
|
||||
|
||||
return !FirstDecl;
|
||||
}
|
||||
|
||||
void DeclContext::addDecl(ASTContext &Context, Decl *D) {
|
||||
assert(D->getLexicalDeclContext() == this &&
|
||||
"Decl inserted into wrong lexical context");
|
||||
|
|
|
@ -192,95 +192,12 @@ bool PCHReader::ReadSourceManagerBlock() {
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief Read the type-offsets block.
|
||||
bool PCHReader::ReadTypeOffsets() {
|
||||
if (Stream.EnterSubBlock(pch::TYPE_OFFSETS_BLOCK_ID))
|
||||
return Error("Malformed block record");
|
||||
|
||||
RecordData Record;
|
||||
while (true) {
|
||||
unsigned Code = Stream.ReadCode();
|
||||
if (Code == llvm::bitc::END_BLOCK) {
|
||||
if (Stream.ReadBlockEnd())
|
||||
return Error("Error at end of TYPE_OFFSETS block");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
|
||||
// No known subblocks, always skip them.
|
||||
Stream.ReadSubBlockID();
|
||||
if (Stream.SkipBlock())
|
||||
return Error("Malformed block record");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Code == llvm::bitc::DEFINE_ABBREV) {
|
||||
Stream.ReadAbbrevRecord();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read a record.
|
||||
Record.clear();
|
||||
switch (Stream.ReadRecord(Code, Record)) {
|
||||
default: // Default behavior: ignore.
|
||||
break;
|
||||
case pch::TYPE_OFFSET:
|
||||
if (!TypeOffsets.empty())
|
||||
return Error("Duplicate TYPE_OFFSETS block");
|
||||
TypeOffsets.swap(Record);
|
||||
TypeAlreadyLoaded.resize(TypeOffsets.size(), false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Read the decl-offsets block.
|
||||
bool PCHReader::ReadDeclOffsets() {
|
||||
if (Stream.EnterSubBlock(pch::DECL_OFFSETS_BLOCK_ID))
|
||||
return Error("Malformed block record");
|
||||
|
||||
RecordData Record;
|
||||
while (true) {
|
||||
unsigned Code = Stream.ReadCode();
|
||||
if (Code == llvm::bitc::END_BLOCK) {
|
||||
if (Stream.ReadBlockEnd())
|
||||
return Error("Error at end of DECL_OFFSETS block");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
|
||||
// No known subblocks, always skip them.
|
||||
Stream.ReadSubBlockID();
|
||||
if (Stream.SkipBlock())
|
||||
return Error("Malformed block record");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Code == llvm::bitc::DEFINE_ABBREV) {
|
||||
Stream.ReadAbbrevRecord();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read a record.
|
||||
Record.clear();
|
||||
switch (Stream.ReadRecord(Code, Record)) {
|
||||
default: // Default behavior: ignore.
|
||||
break;
|
||||
case pch::DECL_OFFSET:
|
||||
if (!DeclOffsets.empty())
|
||||
return Error("Duplicate DECL_OFFSETS block");
|
||||
DeclOffsets.swap(Record);
|
||||
DeclAlreadyLoaded.resize(DeclOffsets.size(), false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PCHReader::ReadPCHBlock() {
|
||||
if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID))
|
||||
return Error("Malformed block record");
|
||||
|
||||
// Read all of the records and blocks for the PCH file.
|
||||
RecordData Record;
|
||||
while (!Stream.AtEndOfStream()) {
|
||||
unsigned Code = Stream.ReadCode();
|
||||
if (Code == llvm::bitc::END_BLOCK) {
|
||||
|
@ -302,17 +219,34 @@ bool PCHReader::ReadPCHBlock() {
|
|||
if (ReadSourceManagerBlock())
|
||||
return Error("Malformed source manager block");
|
||||
break;
|
||||
|
||||
case pch::TYPE_OFFSETS_BLOCK_ID:
|
||||
if (ReadTypeOffsets())
|
||||
return Error("Malformed type-offsets block");
|
||||
break;
|
||||
|
||||
case pch::DECL_OFFSETS_BLOCK_ID:
|
||||
if (ReadDeclOffsets())
|
||||
return Error("Malformed decl-offsets block");
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Code == llvm::bitc::DEFINE_ABBREV) {
|
||||
Stream.ReadAbbrevRecord();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read and process a record.
|
||||
Record.clear();
|
||||
switch ((pch::PCHRecordTypes)Stream.ReadRecord(Code, Record)) {
|
||||
default: // Default behavior: ignore.
|
||||
break;
|
||||
|
||||
case pch::TYPE_OFFSET:
|
||||
if (!TypeOffsets.empty())
|
||||
return Error("Duplicate TYPE_OFFSET record in PCH file");
|
||||
TypeOffsets.swap(Record);
|
||||
TypeAlreadyLoaded.resize(TypeOffsets.size(), false);
|
||||
break;
|
||||
|
||||
case pch::DECL_OFFSET:
|
||||
if (!DeclOffsets.empty())
|
||||
return Error("Duplicate DECL_OFFSET record in PCH file");
|
||||
DeclOffsets.swap(Record);
|
||||
DeclAlreadyLoaded.resize(DeclOffsets.size(), false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -426,7 +360,7 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
|
|||
|
||||
// FIXME: Several other kinds of types to deserialize here!
|
||||
default:
|
||||
assert("Unable to deserialize this type");
|
||||
assert(false && "Unable to deserialize this type");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -500,7 +434,7 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
|
|||
return D;
|
||||
}
|
||||
|
||||
QualType PCHReader::GetType(unsigned ID) {
|
||||
QualType PCHReader::GetType(pch::TypeID ID) {
|
||||
unsigned Quals = ID & 0x07;
|
||||
unsigned Index = ID >> 3;
|
||||
|
||||
|
@ -550,7 +484,7 @@ QualType PCHReader::GetType(unsigned ID) {
|
|||
return QualType(reinterpret_cast<Type *>(TypeOffsets[Index]), Quals);
|
||||
}
|
||||
|
||||
Decl *PCHReader::GetDecl(unsigned ID) {
|
||||
Decl *PCHReader::GetDecl(pch::DeclID ID) {
|
||||
if (ID == 0)
|
||||
return 0;
|
||||
|
||||
|
@ -563,7 +497,7 @@ Decl *PCHReader::GetDecl(unsigned ID) {
|
|||
}
|
||||
|
||||
bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
|
||||
llvm::SmallVectorImpl<unsigned> &Decls) {
|
||||
llvm::SmallVectorImpl<pch::DeclID> &Decls) {
|
||||
assert(DC->hasExternalLexicalStorage() &&
|
||||
"DeclContext has no lexical decls in storage");
|
||||
uint64_t Offset = DeclContextOffsets[DC].first;
|
||||
|
|
|
@ -490,7 +490,7 @@ void PCHWriter::WritePreprocessor(Preprocessor &PP) {
|
|||
|
||||
/// \brief Write the representation of a type to the PCH stream.
|
||||
void PCHWriter::WriteType(const Type *T) {
|
||||
pch::ID &ID = TypeIDs[T];
|
||||
pch::TypeID &ID = TypeIDs[T];
|
||||
if (ID == 0) // we haven't seen this type before.
|
||||
ID = NextTypeID++;
|
||||
|
||||
|
@ -547,10 +547,8 @@ void PCHWriter::WriteTypesBlock(ASTContext &Context) {
|
|||
// Exit the types block
|
||||
S.ExitBlock();
|
||||
|
||||
// Write the type offsets block
|
||||
S.EnterSubblock(pch::TYPE_OFFSETS_BLOCK_ID, 2);
|
||||
// Write the type offsets record
|
||||
S.EmitRecord(pch::TYPE_OFFSET, TypeOffsets);
|
||||
S.ExitBlock();
|
||||
}
|
||||
|
||||
/// \brief Write the block containing all of the declaration IDs
|
||||
|
@ -560,7 +558,7 @@ void PCHWriter::WriteTypesBlock(ASTContext &Context) {
|
|||
/// bistream, or 0 if no block was written.
|
||||
uint64_t PCHWriter::WriteDeclContextLexicalBlock(ASTContext &Context,
|
||||
DeclContext *DC) {
|
||||
if (DC->decls_begin(Context) == DC->decls_end(Context))
|
||||
if (DC->decls_empty(Context))
|
||||
return 0;
|
||||
|
||||
uint64_t Offset = S.GetCurrentBitNo();
|
||||
|
@ -638,7 +636,7 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) {
|
|||
}
|
||||
|
||||
// Determine the ID for this declaration
|
||||
pch::ID ID = DeclIDs[D];
|
||||
pch::DeclID ID = DeclIDs[D];
|
||||
if (ID == 0)
|
||||
ID = DeclIDs.size();
|
||||
|
||||
|
@ -664,10 +662,8 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) {
|
|||
// Exit the declarations block
|
||||
S.ExitBlock();
|
||||
|
||||
// Write the declaration offsets block
|
||||
S.EnterSubblock(pch::DECL_OFFSETS_BLOCK_ID, 2);
|
||||
// Write the declaration offsets record
|
||||
S.EmitRecord(pch::DECL_OFFSET, DeclOffsets);
|
||||
S.ExitBlock();
|
||||
}
|
||||
|
||||
PCHWriter::PCHWriter(llvm::BitstreamWriter &S)
|
||||
|
@ -720,7 +716,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
|
|||
}
|
||||
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) {
|
||||
pch::ID ID;
|
||||
pch::TypeID ID;
|
||||
switch (BT->getKind()) {
|
||||
case BuiltinType::Void: ID = pch::PREDEF_TYPE_VOID_ID; break;
|
||||
case BuiltinType::Bool: ID = pch::PREDEF_TYPE_BOOL_ID; break;
|
||||
|
@ -748,7 +744,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
|
|||
return;
|
||||
}
|
||||
|
||||
pch::ID &ID = TypeIDs[T.getTypePtr()];
|
||||
pch::TypeID &ID = TypeIDs[T.getTypePtr()];
|
||||
if (ID == 0) // we haven't seen this type before
|
||||
ID = NextTypeID++;
|
||||
|
||||
|
@ -762,7 +758,7 @@ void PCHWriter::AddDeclRef(const Decl *D, RecordData &Record) {
|
|||
return;
|
||||
}
|
||||
|
||||
pch::ID &ID = DeclIDs[D];
|
||||
pch::DeclID &ID = DeclIDs[D];
|
||||
if (ID == 0) {
|
||||
// We haven't seen this declaration before. Give it a new ID and
|
||||
// enqueue it in the list of declarations to emit.
|
||||
|
|
|
@ -526,6 +526,16 @@ bool Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
|
|||
|
||||
// __builtin_va_list gets redeclared in the built-in definitions
|
||||
// buffer when using PCH. Don't complain about such redefinitions.
|
||||
//
|
||||
// FIXME: The problem here is that the __builtin_va_list declaration
|
||||
// comes in as target-specific text in the predefines buffer, both
|
||||
// in the generation of the PCH file and in the source file. Thus,
|
||||
// we end up with two typedefs for the same type, which is an error
|
||||
// in C. Our hackish solution is to allow redundant typedefs *to the
|
||||
// same type* if the types are defined in the predefined buffer. We
|
||||
// would like to eliminate this ugliness, perhaps by making
|
||||
// __builtin_va_list a real, Sema-supplied declaration rather than
|
||||
// putting its text into the predefines buffer.
|
||||
if (Context.getExternalSource() &&
|
||||
strcmp(SourceMgr.getBufferName(New->getLocation()), "<built-in>") == 0)
|
||||
return false;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: clang-cc -emit-pch -o %t %S/variables.h &&
|
||||
// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
|
||||
// RUN: clang-cc -emit-pch -triple=i686-apple-darwin9 -o %t %S/variables.h &&
|
||||
// RUN: clang-cc -triple=i686-apple-darwin9 -include-pch %t -fsyntax-only -verify %s
|
||||
|
||||
int *ip2 = &x;
|
||||
float *fp = &ip; // expected-warning{{incompatible pointer types}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче