Replacing constructor calls in a clang plugin; constructor not emitted


I’m working on a clang plugin that would replace some constructor calls with calls to other constructors.

Here’s a simplified example:

template struct C {
C() {}
C(int, int) {}
C c = {};
//C d = {0, 0};
int main() {}

I want to call the 2-argument constructor to initialize c to make it act like the initialization of the d variable below.

I wrote a plugin that runs before the main AST action and does the transformation in HandleTopLevelDecl. The problem is that the 2-argument constructor is not begin emitted and linking fails.

I’m doing the transformation this way:

void ChangeCtor(VarDecl *VD) {
auto &Sema = Instance.getSema();
auto &Context = Sema.getASTContext();
auto Loc = VD->getSourceRange().getBegin();
auto VarQT = VD->getType();
auto *Zero = clang::IntegerLiteral::Create(Context, llvm::APInt(32, 0),
Context.IntTy, Loc);
auto *RDecl = VarQT->getAsCXXRecordDecl();
CXXConstructorDecl *Ctor = nullptr;
for (auto *CD : RDecl->ctors())
if (CD->getNumParams() == 2)
Ctor = CD;

Expr *Params = {Zero, Zero};
auto *ConstructExpr = CXXConstructExpr::Create(
Context, VarQT, Loc, Ctor, false, Params, true, true, false, false,
CXXConstructExpr::CK_Complete, VD->getSourceRange());


(Here’s a gist with all the code:

When I uncomment the d variable, or insert a call to the 2-argument ctor somewhere else, it gets emitted and links fine - no surprise here.

What am I doing wrong? Any suggestion on how to make it work?


You need to mark the 2 argument constructor as ODR-used. I think you want to all Sema.MarkFunctionReferenced.

Works like charm, thanks!