N3439
__self_func

Published Proposal,

Authors:
Latest:
https://thephd.dev/_vendor/future_cxx/papers/C%20-%20__self_func.html
Previous Revisions:
None
Paper Source:
GitHub ThePhD/future_cxx
Project:
ISO/IEC 9899 Programming Languages — C, ISO/IEC JTC1/SC22/WG14

Abstract

This is a proposal to allow for a function to refer to itself, useful in macros and within statement expressions.

1. Changelog

1.1. Revision 0 - December 23rd, 2024

2. Introduction and Motivation

C99 introduced __func__, which is the string name of the function. Microsoft added __FUNCSIG__ and __FUNCDNAME__ to provide another way to get the string name of the function call. But, none of the compilers ever added a way to refer to the current function directly, despite the need for it appearing it macros and other places that wished to implement e.g. Tail Recursion or other traits in a function name-agnostic ways. Macro authors forced users to pass in the name of the function so it could be properly recursed on, but this is slightly cumbersome.

Recently, _Self and -- at the behest of the Community to rename it -- _Recur have both shown up in Celeste’s "C Extensions to Support Generalized Functions Calls, v3.5" [N3315]. Its specification is there in the wording but it only exists to describe tail-calling. Some support was expressed for lifting it out and making it its own entity rather than something that existed purely in the wording itself.

This paper is the lift out, implementing __self_func as a keyword.

3. Design

The design for this is, thankfully, very simple and easy: __self_func is a keyword/identifier that represents the current function invocation the compiler is in. This is implementable very simple in the compiler frontend by simply performing an identifier substitution for the name of the function being translated, and erroring if at file scope. __self_func is a "function designator" in C Standardese terms, that represents the current function. It is a constraint violation for it to be used at any non-block scope. The wording tries to make this easy by making it part of the block grammar, banning it for existing at file scope.

3.1. Keyword Name

We do not care what this is called. This has 3 popular names:

__self and _Self are common identifiers in some places. _Recur and __recur are fine and N3315 changed its nomenclature to that to follow feedback from the C community about what it could be named. __func__, unfortunately, already exists as a predefined identifier in C (it should have been called __func_name__ but we can’t fix that now). __self_func is what this proposal settled on, using the double underscores to have it exist in a space similar to an identifier, even if the intent is to exist as a keyword.

As stated earlier, we do not care what it is called, so long as it exists. Suggestions are welcome and any name will do just fine.

4. Wording

This wording is relative to C’s latest working draft.

📝 Editor’s Note: The ✨ characters are intentional. They represent stand-ins to be replaced by the editor.

4.1. Take all of the current "Predefined identifiers" (6.4.3.2) wording and place it under a new header underneath named "§6.4.3.2.1 __func__" "__self_func

OPTIONAL: Furthermore:

4.2. Add a new section §6.4.3.2.✨ "__self_func

6.4.3.2.✨ __self_func
Semantics

The identifier __self_func shall be implicitly declared by the translator as if, immediately following the opening brace of each function definition, the declaration

static const constexpr auto __self_func = function-name;

appeared, where function-name is the name of the lexically-enclosing function.

EXAMPLE A program refers to the enclosing function even when the name is not directly known.

#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
bool f (int tries, const char* fn) {

#define MAX_TRIES 30
#define RE_DO(TRIES, ...) if (TRIES >= MAX_TRIES) goto TOO_MANY_TRIES;\
                           return __self_func(TRIES + 1 __VA_OPT__(,) __VA_ARGS__);

  if (fn == nullptr) return false;
  size_t fnlen = strlen(fn);
  if (fnlen < 1) return false;
  FILE* f = fopen(fn);
  if (!f) {
    fn[fnlen - 1] = '0' + tries;
    RE_DO(tries, fn);
  }
  // found the first proper f,
  // use it
  fclose(f);
  return true;

  TOO_MANY_TRIES:
  if (f) fclose(f);
  return false;
}

References

Informative References

[N3315]
Alex Celeste. C Extensions to support Generalized Function Calls, v3.5. August 19th, 2024. URL: https://www.open-std.org/JTC1/SC22/WG14/www/docs/n3315.htm