문제

How can I inspect the overload resolution set?

I have 4 competing functions used in multiple call sites. In one call site, I'm expecting one function to be called, but another one is picked up by the compiler. I don't know why/it's not trivial. To learn what is going on, I'm using enable_if/disable_if to turn functions on/off but this is really slow/tedious/annoying.

So I would like the compiler to tell me "Why?". That is, for this single call site:

  • all functions found by ADL,
  • all functions in the overload resolution set,
  • all functions rejected from the overload resolution set and why they were rejected, and
  • the ranks of the functions in the overload resolution set as well as the reason for their ranks.

Information about access control is not required.

Basically I'm hoping for marking the call site with a #pragma or similar (__builtin...). But libclang would also be an option.

I have access to tip-of-trunk clang and gcc but can install other compiler/tools if necessary.

도움이 되었습니까?

해결책

I can imagine writing a clang plug-in inspecting which function is being called and what others are in the overload set. I'd think tracing the look-up rules and finding out why the candidates from the overload set are discarded and why the chosen function is the best candidate in the overload set is something quite different, though.

I haven't played with determining overload sets, etc. However, below is a simple starting point: a clang plug-in which prints the function called if a function with a specific name (currently hard-coded to be "foo") is found. It also print the found overloads.

I'm compiling the code and running it with the commands (obviously, these are stored in a make file):

/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

The version of clang used is built with debug information: otherwise it doesn't seem to find a debug symbol. I should probably find out how to build a tool directly and not run from within 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");

The code isn't pretty and isn't really doing what you are looking for. However, formatting the function declarations a bit nicer, possibly investigating a bit with the Sema object why it isn't a match, etc. could get the code reasonably close to the tool you are looking for, I think.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top