简体   繁体   English

如何通过Clang编译模板实例化?

[英]How do template instantiations get compiled by Clang?

I am using Clang as a library to compile some templated code: 我使用Clang作为库来编译一些模板化代码:

template<typename T>
T getSevenTemplated() {
  return 7;
}

int getSeven() {
  return getSevenTemplated<int>();
}

Unfortunately, the compiled LLVM IR does not actually contain the implementation of getSevenTemplated<int> : 不幸的是,编译的LLVM IR实际上并不包含getSevenTemplated<int>

; ModuleID = './test.cpp'
source_filename = "./test.cpp"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.12.0"

; Function Attrs: ssp uwtable
define i32 @_Z8getSevenv() #0 {
entry:
  %call = call i32 @_Z17getSevenTemplatedIiET_v()
  ret i32 %call
}

declare i32 @_Z17getSevenTemplatedIiET_v() #1

attributes #0 = { ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 5.0.0 (trunk 292778)"}

Here is the code I am using to generate the LLVM module: 这是我用来生成LLVM模块的代码:

auto* context = new llvm::LLVMContext(); // TODO: Fix leak 

auto codeGenerator =
  std::shared_ptr<clang::CodeGenerator>(
    clang::CreateLLVMCodeGen(
      compilerInstance.getDiagnostics(), 
      filePath,
      compilerInstance.getHeaderSearchOpts(), 
      preprocessor.getPreprocessorOpts(),
      compilerInstance.getCodeGenOpts(), 
      *context, 
      nullptr));

codeGenerator->Initialize(compilerInstance.getASTContext());

// declGroups are found by calling ParseAST with a special ASTConsumer earlier
for (auto declGroup : declGroups) { 
  codeGenerator->HandleTopLevelDecl(declGroup);
}

codeGenerator->HandleTranslationUnit(compilerInstance.getASTContext());

To investigate why, I looked through the source-code and I found that the CodeGenerator has specific logic for handling templates: it seems to skip function template instantiations! 为了研究原因,我查看了源代码 ,发现CodeGenerator具有处理模板的特定逻辑:它似乎跳过了函数模板实例化! I presume that it handles the generated functions instead, but I don't know how it really works. 我认为它处理生成的函数,但我不知道它是如何工作的。

My questions are: 我的问题是:

  1. At a high level, how does Clang go about instantiating templates and passing them to the ASTConsumer for code generation? 在高层次上,Clang如何实例化模板并将它们传递给ASTConsumer以生成代码?
  2. Are there any special tricks for enabling the generation of function bodies for instantiated templates? 是否有任何特殊技巧可以为实例化模板生成函数体? What am I missing from the code above? 我在上面的代码中遗漏了什么?

The problem was that I had incremental parsing turned on. 问题是我打开了增量解析。 With this setting enabled, the ParseAST function does not call clang::Sema::ActOnEndOfTranslationUnit , which triggers the instantiation of templates. 启用此设置后, ParseAST函数不会调用clang::Sema::ActOnEndOfTranslationUnit ,这会触发模板的实例化。

The trick is to add this call after processing your decls: 诀窍是在处理你的decl后添加这个调用:

// This triggers the instantiation of templated functions
sema.ActOnEndOfTranslationUnit();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM