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; }