Problem with linking modules which use a shared type


I stumbled upon a strange thing regarding types and module linking, which I don't quite get, so maybe someone around here can enlighten me.

Consider the following code, which will create 2 modules m1 and m2, and a named structured type %T = { i32 }; m1 contains only a function definition f(%T), m2 contains a function declaration f(%T) and a function definition h(%T), where h will call f in its body. Note that all functions in m1 and m2 are based upon the same structured type %T:

     LLVMContext context;
     BasicBlock* b;

     // modules
     Module *m1 = new Module( "m1", context ),
            *m2 = new Module( "m2", context );

     // types
     vector<Type*> types;

     types.push_back( IntegerType::get( context, 32 ) );

     Type* sType = StructType::create( types, "T" );

     types.push_back( sType );

     FunctionType* ft = FunctionType::get( Type::getVoidTy( context ), types, false );

     // m1
     Function* f = Function::Create( ft, GlobalValue::ExternalLinkage, "f", m1 );

     b = BasicBlock::Create( context, "b", f );
     ReturnInst::Create( context, b );


     // m2
     Function* fDecl = Function::Create( ft, GlobalValue::ExternalLinkage, "f", m2 );
     Function* h = Function::Create( ft, GlobalValue::ExternalLinkage, "h", m2 );

     vector<Value*> args;
     args.push_back( h->arg_begin() );

     b = BasicBlock::Create( context, "b", h );
     CallInst::Create( fDecl, args, "", b );
     ReturnInst::Create( context, b );


Each module for itself is okay and passes the verification, leading to the following IR code:

     ; ModuleID = 'm1'

     %T = type { i32 }

     define void @f(%T) {
       ret void

I’ve tripped over this behaviour as well. I ended up working around the problem by creating a new context every time I wanted to link modules together. Which led to me accidently generating one module using two different contexts. Which isn’t an error that is detected by module verification. It only causes issues for comparisons like Type equality that compare pointers, and those types of problems can be tricky to debug.

I tried that also, but got some errors out of it, probably due to running the interpreter directly on the module instead of just generating bytecode from it. So there is currently no proper way to avoid the problem at all?