This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Determining if a FUNCTION_DECL node is a C++ template specialization


Hello,

I'm writing a plugin to print out the GENERIC tree of a C++ source file.

Here's the source code to be translated:

////////////
template <typename T>
struct S
{
    void f()
    {
    }
};


template <>
struct S<int>
{
    void f()
    {
    }
};


void g()
{
    S<float> v;
    v.f();

    S<int> u;
    u.f();
}
//////////


Here's the output of the plugin:

::S::f test_plugin2.cpp:14                           <-------- want to
see ::S<int>::f here
   parm_decl is unhandled NO LOC
   statement_list is unhandled NO LOC
::g test_plugin2.cpp:20
   bind_expr test_plugin2.cpp:26
      var_decl is unhandled NO LOC
      statement_list is unhandled NO LOC
      block is unhandled NO LOC
::S<_unexpected_real_type>::f test_plugin2.cpp:4  <---- plugin prints
S<float>::f, as expected
   parm_decl is unhandled NO LOC
   template_info is unhandled NO LOC
   statement_list is unhandled NO LOC


I've guessed at which tree fields would indicate if a node is a
specialized template definition, but have had no luck
(DECL_USE_TEMPLATE, DECL_TEMPLATE_PARM_P, DECL_ABSTRACT_ORIGIN,
DECL_TEMPLATE_INSTANTIATED).

Any advice on how to properly print the template parameters of a
specialized template would be much appreciated.

Thanks,
Joe



$ gcc48 --version

gcc48 (GCC) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++48 --std=c++11 -O0 -ggdb -I`g++48
-print-file-name=plugin`/include -fPIC -shared plugin4.cpp -o
plugin4.so
In file included from
/opt/gcc-4.8.1/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.8.1/plugin/include/tm.h:28:0,
                 from plugin4.cpp:15:
/opt/gcc-4.8.1/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.8.1/plugin/include/config/elfos.h:102:21:
warning: invalid suffix on literal; C++11 requires a space between
literal and identifier [-Wliteral-suffix]
    fprintf ((FILE), "%s"HOST_WIDE_INT_PRINT_UNSIGNED"\n",\
                     ^
/opt/gcc-4.8.1/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.8.1/plugin/include/config/elfos.h:170:24:
warning: invalid suffix on literal; C++11 requires a space between
literal and identifier [-Wliteral-suffix]
       fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n",  \
                        ^
In file included from
/opt/gcc-4.8.1/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.8.1/plugin/include/tm.h:42:0,
                 from plugin4.cpp:15:
/opt/gcc-4.8.1/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.8.1/plugin/include/defaults.h:126:24:
warning: invalid suffix on literal; C++11 requires a space between
literal and identifier [-Wliteral-suffix]
       fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n",  \
                        ^
$ g++48 -S -fplugin=./plugin4.so test_plugin2.cpp
::S::f test_plugin2.cpp:14
   parm_decl is unhandled NO LOC
   statement_list is unhandled NO LOC
::g test_plugin2.cpp:20
   bind_expr test_plugin2.cpp:26
      var_decl is unhandled NO LOC
      statement_list is unhandled NO LOC
      block is unhandled NO LOC
::S<_unexpected_real_type>::f test_plugin2.cpp:4
   parm_decl is unhandled NO LOC
   template_info is unhandled NO LOC
   statement_list is unhandled NO LOC



////// plugin4.cpp

#include <stdlib.h>
#include <gmp.h>

#include <cstdlib>

#include "gcc-plugin.h"

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "intl.h"

#include "tm.h"

#include "cp/cp-tree.h"
#include "c-family/c-common.h"
#include "c-family/c-pragma.h"
#include "diagnostic.h"
#include "tree-iterator.h"

#include <iostream>
#include <sstream>
#include <string>

int plugin_is_GPL_compatible;


const char* indent_spaces =
    "                                                                       "
    "                                                                       "
    "                                                                       "
    "                                                                       "
    "                                                                       "
    "                                                                       "
    "                                                                       "
    "                                                                       "
    "                                                                       "
    "                                                                       "
    "                                                                       "
    ;

int indent_cnt = 3;

std::string expr_loc (tree decl)
{
    if (EXPR_HAS_LOCATION(decl))
    {
        std::ostringstream ostr;
        ostr << EXPR_FILENAME(decl) << ':' << EXPR_LINENO(decl);
        return ostr.str();
    }

    return "NO LOC";
}


tree build_scope_string (tree scope, std::string& s)
{
    if (TREE_CODE(scope) == RECORD_TYPE ||
        TREE_CODE(scope) == ENUMERAL_TYPE)
    {
        if (TYPE_NAME (scope))
            scope = TYPE_NAME (scope);
        //tmp_scope = TYPE_CANONICAL(scope);
        else
            scope = TYPE_NAME (TYPE_CANONICAL(scope));
        // if (tmp_scope)
        //     scope
    }
    tree id = 0;
    if (scope)
        id = DECL_NAME (scope);

    const char* id_ptr = (id != 0 ? IDENTIFIER_POINTER (id) : "<unnamed>");
    id_ptr = id_ptr ? id_ptr : "<nullptr>";

    int name_len = strlen (id_ptr);
    while (name_len > 0 && id_ptr[name_len-1] == ' ') --name_len;

    // namespaces.push_back (id_ptr);

    std::string tmp = "::";
    tmp += std::string (id_ptr, name_len);
    tmp += s;
    s.swap (tmp);

    return scope;
}


std::string
decl_scope (tree decl)
{
    std::string s;

    for (tree scope (CP_DECL_CONTEXT (decl));
         scope != global_namespace && scope;
         scope = CP_DECL_CONTEXT (scope))
    {
        scope = build_scope_string (scope, s);
        if (!scope)
            break;
    }

    return s;
}


std::string
type_scope (tree decl)
{
    std::string s;

    for (tree scope (CP_TYPE_CONTEXT (decl));
         scope != global_namespace && scope;
         scope = CP_TYPE_CONTEXT (scope))
    {
        scope = build_scope_string (scope, s);
        if (!scope)
            break;
    }

    return s;
}


void print_type (tree type, std::ostream& ostr);


void
print_decl (tree decl, std::ostream& ostr)
{
    // int tc (TREE_CODE (decl));
    tree id (DECL_NAME (decl));
    const char* name (id ? IDENTIFIER_POINTER (id) : "<unnamed>");

    if (!name) name = "null_name";

    std::string scope_name = decl_scope (decl);
    ostr << scope_name;

    if (DECL_LANG_SPECIFIC(decl) && DECL_TEMPLATE_INFO(decl))
    {
        tree ti = DECL_TEMPLATE_INFO(decl);
        ostr << '<';
        bool first = true;
        tree tparm = TI_ARGS(ti);
        while (tparm != 0)
        {
            for (int i = 0; i < TREE_VEC_LENGTH(tparm); ++i)
            {
                if (!first)
                    ostr << ',';

                first = false;
                print_type (TREE_VEC_ELT (tparm, i), ostr);
            }

            tparm = TREE_CHAIN (tparm);
        }
        ostr << '>';
    }

    ostr << "::" << name;
}


void print_type (tree type, std::ostream& ostr)
{
    if (TREE_CODE (type) == POINTER_TYPE)
    {
        print_type (TREE_TYPE(type), ostr);
        ostr << '*';
    }
    else if (TREE_CODE (type) == REFERENCE_TYPE)
    {
        print_type (TREE_TYPE(type), ostr);
        ostr << '&';
    }
    else if (RECORD_OR_UNION_TYPE_P (type))
    {
        tree type_name = TYPE_NAME (type);
        if (!type_name)
        {
            ostr << "_NULL_type_name_";
        }
        else if (TREE_CODE(type_name) == TYPE_DECL)
        {
            print_decl (type_name, ostr);
        }
        else if (TREE_CODE(type_name) == IDENTIFIER_NODE)
        {
            ostr << type_scope (type) << "::";

            const char* name (type_name ? IDENTIFIER_POINTER (type_name) :
                              "<unnamed>");
            if (!name) name = "null_name";
            int name_len = strlen (name);
            while (name_len > 0 && name[name_len-1] == ' ') --name_len;
            ostr.write (name, name_len);
        }
    }
    else if (TREE_CODE(type) == INTEGER_TYPE)
    {
        ostr << "_int_" << TYPE_MIN_VALUE(type) << '_' << TYPE_PRECISION(type);
    }
    else
    {
        int tc (TREE_CODE (type));
        ostr << "_unexpected_" << tree_code_name[tc];
    }
}


void print_tree (tree decl, int level)
{
    if (!decl)
        return;

    if (TREE_CODE(decl) == FUNCTION_DECL)
    {
        // std::cout.write (indent_spaces, indent_cnt * level);
        // std::cout << "decl_use_template " << (DECL_USE_TEMPLATE(decl))
        //           << std::endl;
        // std::cout.write (indent_spaces, indent_cnt * level);
        // std::cout << "decl_templ_parm_p " << (DECL_TEMPLATE_PARM_P(decl))
        //           << std::endl;
        // std::cout.write (indent_spaces, indent_cnt * level);
        // std::cout << "decl_abstract_origin "
        //           << (DECL_ABSTRACT_ORIGIN(decl))
        //           << std::endl;
        // std::cout.write (indent_spaces, indent_cnt * level);
        // std::cout << "decl_template_instantiated "
        //           << (DECL_TEMPLATE_INSTANTIATED(decl))
        //           << std::endl;
        // std::cout.write (indent_spaces, indent_cnt * level);
        print_decl (decl, std::cout);
        std::cout << " " << DECL_SOURCE_FILE (decl) << ":"
                  << DECL_SOURCE_LINE (decl) << std::endl;
        for (tree parm = DECL_ARGUMENTS(decl);
             parm != 0; parm = TREE_CHAIN (parm))
        {
            print_tree (parm, level+1);
        }
        if (DECL_TEMPLATE_INFO(decl))
        {
            print_tree (DECL_TEMPLATE_INFO(decl), level+1);
        }

        if (DECL_SAVED_TREE(decl))
        {
            // print_decl (decl, std::cout);

            // std::cout << ' ' << DECL_SOURCE_FILE (decl) << ':'
            //           << DECL_SOURCE_LINE (decl);

            // std::cout << std::endl;

            tree init_stmt = DECL_SAVED_TREE(decl);
            print_tree (init_stmt, level+1);
        }
        return;
    }

    if (EXPRESSION_CLASS_P(decl) ||
        UNARY_CLASS_P(decl) ||
        VL_EXP_CLASS_P(decl) ||
        EXPRESSION_CLASS_P(decl) ||
        REFERENCE_CLASS_P(decl))
    {
        std::cout.write (indent_spaces, indent_cnt * level);
        std::cout << tree_code_name[TREE_CODE(decl)] << ' '
                  << expr_loc(decl) << std::endl;

        for (int i = 0; i < TREE_OPERAND_LENGTH(decl); ++i)
        {
            tree operand = TREE_OPERAND (decl, i);
            print_tree (operand, level+1);
        }
        return;
    }

    std::cout.write (indent_spaces, indent_cnt * level);
    std::cout << tree_code_name[TREE_CODE(decl)] << " is unhandled "
              << expr_loc(decl) << std::endl;

    return;
}

extern "C" void
gate_callback (void* arg1, void* arg2)
{
    // If there were errors during compilation,
    // let GCC handle the exit.
    //
    if (errorcount || sorrycount)
        return;

    tree tree_arg = (tree) arg1;
    print_tree (tree_arg, 0);
}


extern "C" int
plugin_init (plugin_name_args* info,
             plugin_gcc_version* ver)
{
    // Disable assembly output.
    //
    asm_file_name = HOST_BIT_BUCKET;

    // Register callbacks.
    //
    register_callback (info->base_name,
                       //PLUGIN_OVERRIDE_GATE,
                       PLUGIN_PRE_GENERICIZE,
                       &gate_callback,
                       0);
    return 0;
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]