https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83324

            Bug ID: 83324
           Summary: [feature request] Pragma or special syntax for
                    guaranteed tail calls
           Product: gcc
           Version: 7.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: m...@daniel-mendler.de
  Target Milestone: ---

I've seen that gcc7 supports the CALL_EXPR_MUST_TAIL_CALL flag internally.
Unfortunately it is not exposed to the frontend.

As of now it seems only possible to use the flag via a plugin (See below).
Regarding the plugin I couldn't figure out quickly how to register a pragma
which annotates the subsequent call. Therefore I used a variable named
__musttail as marker. Is there some documentation on how to create such a
pragma properly?

test.c:

#include <stdio.h>

#define MUSTTAIL(f) ({                                \
      __attribute__ ((unused)) int __musttail;        \
      return f;                                       \
    })

void g() {
  printf("g called\n");
}

void f() {
  printf("f called\n");
  MUSTTAIL(g());
}

int main() {
  f();
  return 0;
}

musttail.cc:

#include <gcc-plugin.h>
#include <plugin-version.h>
#include <tree.h>
#include <c-family/c-pragma.h>
#include <stdio.h>

int plugin_is_GPL_compatible;

static tree process_musttail(tree* tp, int* walk_subtrees, void* data
ATTRIBUTE_UNUSED) {
  static bool musttail = false;
  const char* name = get_name(*tp);
  if (name) {
    if (!strcmp(name, "__musttail"))
      musttail = true;
  }
  if (musttail && TREE_CODE(*tp) == CALL_EXPR) {
    CALL_EXPR_MUST_TAIL_CALL(*tp) = true;
    musttail = false;
  }
  return NULL_TREE;
}

static void callback(void *gcc_data, void *user_data) {
  tree fndecl = (tree)gcc_data;
  gcc_assert(TREE_CODE(fndecl) == FUNCTION_DECL);
  walk_tree(&DECL_SAVED_TREE(fndecl), process_musttail, NULL, NULL);
}

int plugin_init(plugin_name_args *plugin_info, plugin_gcc_version *version) {
  if (!plugin_default_version_check(version, &gcc_version))
    return 1;
  const char *plugin_name = plugin_info->base_name;
  register_callback(plugin_name, PLUGIN_PRE_GENERICIZE, callback, NULL);
  return 0;
}

Reply via email to