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

gnz*_*lbg 15 c++ debugging gcc clang overload-resolution

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

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

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

  • ADL发现的所有功能,
  • 重载决策集中的所有函数,
  • 从重载决策集中拒绝的所有函数以及它们被拒绝的原因,以及
  • 重载决策集中的函数行列以及它们的排名原因.

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

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

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

Die*_*ühl 5

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

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

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

/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
Run Code Online (Sandbox Code Playgroud)

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

#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");
Run Code Online (Sandbox Code Playgroud)

代码不漂亮,并没有真正做你想要的.但是,我认为,将函数声明格式化得更好一点,可能会调查一下Sema对象为什么它不匹配等,可以使代码合理地接近你正在寻找的工具.