如何检查给定呼叫站点的重载决策集

时间:2013-11-20 09:59:02

标签: c++ debugging gcc clang overload-resolution

如何检查过载分辨率设置?

我在多个呼叫站点中使用了4个竞争功能。在一个调用站点中,我期望调用一个函数,但编译器会选择另一个函数。我不知道为什么/它不是微不足道的。要了解正在发生的事情,我正在使用enable_if/disable_if来打开/关闭功能,但这实在是很慢/乏味/烦人。

所以我希望编译器告诉我“为什么?”。也就是说,对于这个单一呼叫站点:

  • ADL找到的所有功能,
  • 重载决策集中的所有函数
  • 从重载决策集中拒绝的所有函数以及它们被拒绝的原因,
  • 重载决策集中函数的排名以及排名的原因。

不需要有关访问控制的信息。

基本上我希望用#pragma或类似的__builtin ...标记呼叫网站。但libclang也是一种选择。

我可以访问tip-of-trunk clang和gcc,但如果需要可以安装其他编译器/工具。

1 个答案:

答案 0 :(得分:5)

我可以想象编写一个clang插件来检查正在调用哪个函数以及其他人在重载集中是什么。我认为跟踪查找规则并找出为什么来自重载集的候选被丢弃以及为什么所选择的函数是重载集中的最佳候选者,这是完全不同的。

我没有玩过确定过载集等等。但是,下面是一个简单的起点:一个clang插件,它打印一个函数,如果一个具有特定名称的函数被调用(当前硬编码为{{找到1}})。它还会打印发现的重载。

我正在编译代码并使用命令运行它(显然,这些代码存储在"foo"文件中):

make

使用的clang版本是使用调试信息构建的:否则它似乎找不到调试符号。我应该知道如何直接构建工具而不是从clang中运行。

/opt/llvm-debug/bin/clang -I/usr/include/c++/4.2.1 -I/opt/llvm-debug/include -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -g -fno-exceptions -fno-rtti -c -o MacOS/overloads.o overloads.cpp
/opt/llvm-debug/bin/clang -L/opt/llvm-debug/lib -Wl,-undefined,dynamic_lookup -dynamiclib -o MacOS/overloads.dylib MacOS/overloads.o 
/opt/llvm-debug/bin/clang -cc1 -load MacOS/overloads.dylib -plugin overloads -plugin-arg-overloads argument -fexceptions tst.cpp

代码不漂亮,并没有真正做你想要的。但是,我认为,将函数声明格式化得更好,可能会调查#include <clang/Frontend/FrontendPluginRegistry.h> #include <clang/Frontend/CompilerInstance.h> #include <clang/Lex/Preprocessor.h> #include <clang/Lex/PPCallbacks.h> #include <clang/AST/ASTConsumer.h> #include <clang/AST/AST.h> #include <clang/AST/RecursiveASTVisitor.h> #include <clang/Sema/Sema.h> #include <clang/Sema/Lookup.h> #include <llvm/Support/raw_ostream.h> #include <string> using namespace clang; using namespace llvm; typedef clang::CompilerInstance CI; typedef clang::DeclGroupRef DGR; typedef clang::DiagnosticsEngine DE; // ---------------------------------------------------------------------------- namespace { struct Consumer: clang::ASTConsumer { Consumer(CI& c, std::string const& name): c_(&c), name_(name) {} bool HandleTopLevelDecl(clang::DeclGroupRef DG); CI* c_; std::string name_; }; } // ---------------------------------------------------------------------------- struct Visitor: RecursiveASTVisitor<Visitor> { CI* c_; std::string name_; Visitor(CI* c, std::string const& name): c_(c), name_(name) {} bool VisitCallExpr(CallExpr* d); }; bool Visitor::VisitCallExpr(CallExpr* c) { FunctionDecl* fun = c->getDirectCallee(); if (fun && fun->getNameAsString() == this->name_) { SourceLocation w(c->getExprLoc()); DE &de(this->c_->getDiagnostics()); int id = de.getCustomDiagID(DE::Warning, "function call: %0"); int info = de.getCustomDiagID(DE::Note, "function called"); DiagnosticBuilder(de.Report(w, id)) << fun->getNameAsString() ; DiagnosticBuilder(de.Report(fun->getLocStart(), info)) << fun->getNameAsString() ; Sema& sema = this->c_->getSema(); LookupResult result(sema, fun->getDeclName(), w, Sema::LookupOrdinaryName); DeclContext* context = fun->getDeclContext(); if (sema.LookupName(result, sema.getScopeForContext(context))) { int over = de.getCustomDiagID(DE::Note, "function overload"); LookupResult::Filter filter = result.makeFilter(); while (filter.hasNext()) { DiagnosticBuilder(de.Report(filter.next()->getLocStart(), over)) ; } filter.done(); } } //else { // // I think the callee was a function object or a function pointer //} return true; } void doDecl(Consumer* c, Decl* d) { Visitor(c->c_, c->name_).TraverseDecl(d); } // ---------------------------------------------------------------------------- bool Consumer::HandleTopLevelDecl(DeclGroupRef DG) { std::for_each(DG.begin(), DG.end(), std::bind1st(std::ptr_fun(&doDecl), this)); return true; } // ---------------------------------------------------------------------------- namespace { class Plug : public clang::PluginASTAction { protected: ASTConsumer* CreateASTConsumer(CompilerInstance& c, llvm::StringRef); bool ParseArgs(clang::CompilerInstance const&, std::vector<std::string> const&) { return true; } }; } ASTConsumer* Plug::CreateASTConsumer(CompilerInstance& c, llvm::StringRef) { return new Consumer(c, "foo"); } static clang::FrontendPluginRegistry::Add<Plug> registerPlugin("overloads", "report overloads of a function at a call"); 对象为什么它不匹配等等,可以使代码合理地接近您正在寻找的工具。< / p>