From: Joe Doyle <joe@tanner-doyle.net>
To: gcc-help@gcc.gnu.org
Subject: Determining if a FUNCTION_DECL node is a C++ template specialization
Date: Sat, 15 Mar 2014 05:49:00 -0000 [thread overview]
Message-ID: <CAJsXkDTik9zNUinVjFtiErFG1i-r_erQH9f1E5D7kfAN+1vZxw@mail.gmail.com> (raw)
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;
}
reply other threads:[~2014-03-14 20:17 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAJsXkDTik9zNUinVjFtiErFG1i-r_erQH9f1E5D7kfAN+1vZxw@mail.gmail.com \
--to=joe@tanner-doyle.net \
--cc=gcc-help@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).