SmallPtrSet<StructType*, 16> DstResolvedOpaqueTypes;
public:
- TypeMapTy() {}
+ TypeMapTy(TypeSet &Set) : DstStructTypesSet(Set) {}
+ TypeSet &DstStructTypesSet;
/// Indicate that the specified type in the destination module is conceptually
/// equivalent to the specified type in the source module.
void addTypeMapping(Type *DstTy, Type *SrcTy);
}
Type *TypeMapTy::get(Type *Ty) {
+#ifndef NDEBUG
+ for (auto &Pair : MappedTypes) {
+ assert(!(Pair.first != Ty && Pair.second == Ty) &&
+ "mapping to a source type");
+ }
+#endif
+
// If we already have an entry for this type, return it.
Type **Entry = &MappedTypes[Ty];
if (*Entry)
if (STy->isOpaque()) {
// A named structure type from src module is used. Add it to the Set of
// identified structs in the destination module.
+ DstStructTypesSet.insert(STy);
return *Entry = STy;
}
StructType *DTy = StructType::create(STy->getContext());
// A new identified structure type was created. Add it to the set of
// identified structs in the destination module.
+ DstStructTypesSet.insert(DTy);
*Entry = DTy;
SmallVector<Type*, 4> ElementTypes;
Linker::DiagnosticHandlerFunction DiagnosticHandler;
public:
- ModuleLinker(Module *dstM, Module *srcM,
+ ModuleLinker(Module *dstM, TypeSet &Set, Module *srcM,
Linker::DiagnosticHandlerFunction DiagnosticHandler)
- : DstM(dstM), SrcM(srcM),
+ : DstM(dstM), SrcM(srcM), TypeMap(Set),
ValMaterializer(TypeMap, DstM, LazilyLinkFunctions),
DiagnosticHandler(DiagnosticHandler) {}
// we prefer to take the '%C' version. So we are then left with both
// '%C.1' and '%C' being used for the same types. This leads to some
// variables using one type and some using the other.
- if (!SrcStructTypesSet.count(DST))
+ if (!SrcStructTypesSet.count(DST) && TypeMap.DstStructTypesSet.count(DST))
TypeMap.addTypeMapping(DST, ST);
}
void Linker::init(Module *M, DiagnosticHandlerFunction DiagnosticHandler) {
this->Composite = M;
this->DiagnosticHandler = DiagnosticHandler;
+
+ TypeFinder StructTypes;
+ StructTypes.run(*M, true);
+ IdentifiedStructTypes.insert(StructTypes.begin(), StructTypes.end());
}
Linker::Linker(Module *M, DiagnosticHandlerFunction DiagnosticHandler) {
}
bool Linker::linkInModule(Module *Src) {
- ModuleLinker TheLinker(Composite, Src, DiagnosticHandler);
+ ModuleLinker TheLinker(Composite, IdentifiedStructTypes, Src,
+ DiagnosticHandler);
return TheLinker.run();
}
--- /dev/null
+; RUN: llvm-as %s -o %t.bc
+; RUN: llvm-link -S %t.bc -o - | FileCheck %s
+; RUN: llvm-link -S %s -o - | FileCheck %s
+
+; Test that we don't try to map %C.0 and C and then try to map %C to a new type.
+; This used to happen when lazy loading since we wouldn't then identify %C
+; as a destination type until it was too late.
+
+; CHECK: %C.0 = type { %B }
+; CHECK-NEXT: %B = type { %A }
+; CHECK-NEXT: %A = type { i8 }
+; CHECK-NEXT: %C = type { %B }
+
+%A = type { i8 }
+%B = type { %A }
+%C = type { %B }
+%C.0 = type { %B }
+define void @f1() {
+ getelementptr %C* null, i64 0, i32 0, i32 0
+ ret void
+}
+@g1 = external global %C.0