forked from OSchip/llvm-project
Fix a marvelous chained AST writing bug, where we end up with the
following amusing sequence: - AST writing schedules writing a type X* that it had never seen before - AST writing starts writing another declaration, ends up deserializing X* from a prior AST file. Now we have two type IDs for the same type! - AST writer tries to write X*. It only has the lower-numbered ID from the the prior AST file, so references to the higher-numbered ID that was scheduled for writing go off into lalaland. To fix this, keep the higher-numbered ID so we end up writing the type twice. Since this issue occurs so rarely, and type records are generally rather small, I deemed this better than the alternative: to keep a separate mapping from the higher-numbered IDs to the lower-numbered IDs, which we would end up having to check whenever we want to deserialize any type. Fixes <rdar://problem/8511624>, I think. llvm-svn: 115647
This commit is contained in:
parent
e929899a3f
commit
9b3932c0bc
|
@ -3115,6 +3115,9 @@ QualType ASTReader::GetType(TypeID ID) {
|
|||
assert(Index < TypesLoaded.size() && "Type index out-of-range");
|
||||
if (TypesLoaded[Index].isNull()) {
|
||||
TypesLoaded[Index] = ReadTypeRecord(Index);
|
||||
if (TypesLoaded[Index].isNull())
|
||||
return QualType();
|
||||
|
||||
TypesLoaded[Index]->setFromAST();
|
||||
TypeIdxs[TypesLoaded[Index]] = TypeIdx::fromTypeID(ID);
|
||||
if (DeserializationListener)
|
||||
|
|
|
@ -1419,10 +1419,7 @@ void ASTWriter::WriteType(QualType T) {
|
|||
if (Idx.getIndex() == 0) // we haven't seen this type before.
|
||||
Idx = TypeIdx(NextTypeID++);
|
||||
|
||||
// If this type comes from a previously-loaded PCH/AST file, don't try to
|
||||
// write the type again.
|
||||
if (Idx.getIndex() < FirstTypeID)
|
||||
return;
|
||||
assert(Idx.getIndex() >= FirstTypeID && "Re-writing a type from a prior AST");
|
||||
|
||||
// Record the offset for this type.
|
||||
unsigned Index = Idx.getIndex() - FirstTypeID;
|
||||
|
@ -2872,7 +2869,7 @@ DeclID ASTWriter::GetDeclRef(const Decl *D) {
|
|||
if (D == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(!(reinterpret_cast<uintptr_t>(D) & 0x01) && "Invalid decl pointer");
|
||||
DeclID &ID = DeclIDs[D];
|
||||
if (ID == 0) {
|
||||
// We haven't seen this declaration before. Give it a new ID and
|
||||
|
@ -3130,7 +3127,14 @@ void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) {
|
|||
}
|
||||
|
||||
void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
|
||||
TypeIdxs[T] = Idx;
|
||||
// Always take the highest-numbered type index. This copes with an interesting
|
||||
// case for chained AST writing where we schedule writing the type and then,
|
||||
// later, deserialize the type from another AST. In this case, we want to
|
||||
// keep the higher-numbered entry so that we can properly write it out to
|
||||
// the AST file.
|
||||
TypeIdx &StoredIdx = TypeIdxs[T];
|
||||
if (Idx.getIndex() >= StoredIdx.getIndex())
|
||||
StoredIdx = Idx;
|
||||
}
|
||||
|
||||
void ASTWriter::DeclRead(DeclID ID, const Decl *D) {
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
@class X;
|
||||
|
||||
struct Y {
|
||||
X *my_X;
|
||||
};
|
||||
|
||||
@interface X {
|
||||
}
|
||||
@property X *prop;
|
||||
@end
|
|
@ -0,0 +1,8 @@
|
|||
void h(X*);
|
||||
|
||||
@interface X (Blah) {
|
||||
}
|
||||
@end
|
||||
|
||||
void g(X*);
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// RUN: %clang_cc1 -emit-pch -x objective-c-header -o %t1 %S/Inputs/chain-remap-types1.h
|
||||
// RUN: %clang_cc1 -emit-pch -x objective-c-header -o %t2 %S/Inputs/chain-remap-types2.h -include-pch %t1 -chained-pch
|
||||
// RUN: %clang_cc1 -include-pch %t2 -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -ast-print -include-pch %t2 %s | FileCheck %s
|
||||
|
||||
// CHECK: @class X;
|
||||
// CHECK: struct Y
|
||||
// CHECK: @property ( assign,readwrite ) X * prop
|
||||
// CHECK: void h(X *);
|
||||
// CHECK: @interface X(Blah)
|
||||
// CHECK: void g(X *);
|
||||
|
|
@ -699,7 +699,8 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
|
|||
break;
|
||||
|
||||
case TemplateArgument::Declaration:
|
||||
Visit(Arg.getAsDecl());
|
||||
if (Decl *D = Arg.getAsDecl())
|
||||
Visit(D);
|
||||
break;
|
||||
|
||||
case TemplateArgument::Template:
|
||||
|
|
Loading…
Reference in New Issue