2013-11-20 2 views
14

オーバーロードの解像度を調べるにはどうすればよいですか?特定のコールサイトに設定されているオーバーロードの解像度を調べる方法

私は、複数のコールサイトで4つの競合する機能を使用しています。あるコールサイトでは、ある関数が呼び出されることを期待していますが、もう1つはコンパイラによって呼び出されます。私はなぜそれが些細なことではないか分からない。何が起こっているのかを知るために、私はenable_if/disable_ifを使って機能をオン/オフにしていますが、これは本当に遅く/退屈で迷惑です。

私はコンパイラに「なぜ?」と教えてほしいと思います。それは、この単一の呼び出しサイトのため、次のとおりです。

  • ADLで見つかったすべての機能、
  • オーバーロードの解決セットのすべての機能、
  • 設定し、なぜ彼らが拒否されたオーバーロードの解決から拒否されたすべての機能、および
  • オーバーロード解決セット内の関数のランクとランクの理由。

アクセス制御に関する情報は必要ありません。

基本的には、#pragmaなど(__builtin ...)のコールサイトをマークしたいと考えています。しかし、libclangもオプションになります。

私はtip-of-trunk clangとgccにアクセスできますが、必要に応じて他のコンパイラ/ツールをインストールできます。

+2

多少オフフックですが、オーバーロードされた束からどのような特定の関数が呼び出されるかを着実に予測できない場合、それは貧弱な設計です。あなたのオーバーロードバージョンは明らかに区別されるべきです。 – Mikhail

+1

@Mikhail私は正しい過負荷を予測していました。それはconstオブジェクト内で非constメンバ関数を呼び出したので取り上げられませんでした(私はconstのオーバーロードを追加するのを忘れていました...)。私は知っている、普遍的な参照+オーバーロードを混在させないでください...その適切なことをしない限り。コンパイラはそれをもっと簡単に扱うことができます。 – gnzlbg

答えて

5

私は、clangプラグインを書いて、どの機能が呼び出されているのか、他のものが過負荷設定にあるのかを調べることができます。ルックアップ・ルールをトレースして、なぜオーバーロード・セットの候補が破棄され、なぜオーバーロード・セットの中で最良の候補であるのかを知ることができます。

私はオーバーロードセットなどを決定するのにはプレイしていませんが、以下は簡単な出発点です:特定の名前の関数(現在ハードコードされている ) 見つかった。また、検出されたオーバーロードも印刷されます。

私は(当然、これらは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 

使用打ち鳴らすのバージョンは、デバッグ情報を使用して構築されています。それ以外の場合は」doesnのデバッグシンボルが見つかったようです。おそらく、ツールを直接構築し、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"); 

コードがきれいでなく、あなたが探しているものを実際に実行していません。しかし、関数宣言の書式を少し整えて、Semaオブジェクトで少し調べてみると、それがマッチしないなどの理由で、あなたが探しているツールに合理的に近いコードが得られる可能性があります。

関連する問題