Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

__func__ (, __PRETTY_FUNCTION__, __FUNCSIG__) does not resolve to directly-containing *function-body* when appearing in lambda's trailing return type #122657

Open
jhcarl0814 opened this issue Jan 13, 2025 · 1 comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" lambda C++11 lambda expressions

Comments

@jhcarl0814
Copy link

Compiler Explorer, x64-64 clang (trunk), -std=c++26 -O2 -Wall -pedantic -pthread:

#include<array>
template<std::size_t n>
struct template_str_t: public std::array<char, n>
{
    consteval template_str_t(char const (&str)[n + 1]) noexcept
    {
        std::copy(std::begin(str), std::begin(str) + n, std::begin(*this));
    }
};
template<std::size_t n>
template_str_t(char const (&str)[n]) -> template_str_t<n - 1>;

#include<iostream>
template<template_str_t s>
struct c1_t
{
    c1_t() { std::cout << s.data() << std::endl; }
};

int main()
{
    []() -> c1_t<__func__> { return {}; }();
    []<typename return_t = c1_t<__func__>>() -> return_t { return {}; }();
}

Program returned: 0
Program stdout

operator()
main

As shown in above example, a workaround can be to access the correct __func__/__PRETTY_FUNCTION__/__FUNCSIG__ when in lambda's template parameter list.
Use scenario (for having the correct value of __func__/__PRETTY_FUNCTION__/__FUNCSIG__ in lambda's trailing return type):

  1. Write a macro that expands to a stream object that contains __func__ and flushes its content to std::cout/std::cerr on destruction (like qDebug()). But unlike qDebug() which uses __func__ only for printing and has no knowledge of the following parameters, this stream object also uses expression template to capture all the following parameters, so that when their types (including __func__'s type) are available, it knows how much memory should be allocated in advance (or, when records of same size are grouped together, it knows which bucket to send its output to).
  2. Write a macro that takes an expression denoting a stream object that is of unknown flavor (e.g. lvalue std::cout which outputs ASAP, rvalue std::osyncstream(std::cout)/qDebug().noquote().nospace() which outputs on destruction), expands to a guard object definitioin that stores the stream object and does something before its construction and after its destruction. The definition/does something part needs a data_member/variable that is of type T& if stream_expression is lvalue and T otherwise, then at some point the use case [](decltype((stream_expression)) s)->???<my::remove_rvalue_reference_t<decltype((stream_expression))>>{...}(stream_expression) which needs correct __func__ appears.
@frederick-vs-ja frederick-vs-ja added clang:frontend Language frontend issues, e.g. anything involving "Sema" lambda C++11 lambda expressions and removed new issue labels Jan 13, 2025
@llvmbot
Copy link
Member

llvmbot commented Jan 13, 2025

@llvm/issue-subscribers-clang-frontend

Author: Han Jiang (jhcarl0814)

[Compiler Explorer, x64-64 clang (trunk), -std=c++26 -O2 -Wall -pedantic -pthread](https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:50,endLineNumber:17,positionColumn:50,positionLineNumber:17,selectionStartColumn:50,selectionStartLineNumber:17,startColumn:50,startLineNumber:17),source:'%23include%3Carray%3E%0Atemplate%3Cstd::size_t+n%3E%0Astruct+template_str_t:+public+std::array%3Cchar,+n%3E%0A%7B%0A++++consteval+template_str_t(char+const+(%26str)%5Bn+%2B+1%5D)+noexcept%0A++++%7B%0A++++++++std::copy(std::begin(str),+std::begin(str)+%2B+n,+std::begin(*this))%3B%0A++++%7D%0A%7D%3B%0Atemplate%3Cstd::size_t+n%3E%0Atemplate_str_t(char+const+(%26str)%5Bn%5D)+-%3E+template_str_t%3Cn+-+1%3E%3B%0A%0A%23include%3Ciostream%3E%0Atemplate%3Ctemplate_str_t+s%3E%0Astruct+c1_t%0A%7B%0A++++c1_t()+%7B+std::cout+%3C%3C+s.data()+%3C%3C+std::endl%3B+%7D%0A%7D%3B%0A%0Aint+main()%0A%7B%0A++++%5B%5D()+-%3E+c1_t%3C__func__%3E+%7B+return+%7B%7D%3B+%7D()%3B%0A++++%5B%5D%3Ctypename+return_t+%3D+c1_t%3C__func__%3E%3E()+-%3E+return_t+%7B+return+%7B%7D%3B+%7D()%3B%0A%7D%0A'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',m:65.07009345794393,n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:clang_trunk,filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1',verboseDemangling:'0'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!(),options:'-std%3Dc%2B%2B23+-O2+-Wall+-pedantic+-pthread',overrides:!(),selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'+x86-64+clang+(trunk)+(Editor+%231)',t:'0'),(h:executor,i:(argsPanelShown:'1',compilationPanelShown:'0',compiler:clang_trunk,compilerName:'',compilerOutShown:'0',execArgs:'',execStdin:'',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!(),options:'-std%3Dc%2B%2B26+-O2+-Wall+-pedantic+-pthread',overrides:!(),runtimeTools:!(),source:1,stdinPanelShown:'1',tree:'1',wrap:'1'),l:'5',n:'0',o:'Executor+x86-64+clang+(trunk)+(C%2B%2B,+Editor+%231)',t:'0')),header:(),l:'4',m:34.929906542056074,n:'0',o:'',s:1,t:'0')),k:100,l:'3',n:'0',o:'',t:'0')),version:4): ```cpp #include<array> template<std::size_t n> struct template_str_t: public std::array<char, n> { consteval template_str_t(char const (&str)[n + 1]) noexcept { std::copy(std::begin(str), std::begin(str) + n, std::begin(*this)); } }; template<std::size_t n> template_str_t(char const (&str)[n]) -> template_str_t<n - 1>;

#include<iostream>
template<template_str_t s>
struct c1_t
{
c1_t() { std::cout << s.data() << std::endl; }
};

int main()
{
-> c1_t<func> { return {}; }();
[]<typename return_t = c1_t<func>>() -> return_t { return {}; }();
}

Program returned: 0
Program stdout

operator()
main

As shown in above example, a workaround can be to access the correct `__func__`/`__PRETTY_FUNCTION__`/`__FUNCSIG__` when in lambda's template parameter list.
Use scenario (for having the correct value of `__func__`/`__PRETTY_FUNCTION__`/`__FUNCSIG__` in lambda's trailing return type):
1. Write a macro that expands to a stream object that contains `__func__` and flushes its content to `std::cout`/`std::cerr` on destruction (like `qDebug()`). But unlike `qDebug()` which uses `__func__` only for printing and has no knowledge of the following parameters, this stream object also uses expression template to capture all the following parameters, so that when their types (including `__func__`'s type) are available, it knows how much memory should be allocated in advance (or, when records of same size are grouped together, it knows which bucket to send its output to).
2. Write a macro that takes an expression denoting a stream object that is of unknown flavor (e.g. lvalue `std::cout` which outputs ASAP, rvalue `std::osyncstream(std::cout)`/`qDebug().noquote().nospace()` which outputs on destruction), expands to a guard object definitioin that stores the stream object and does something before its construction and after its destruction. The `definition`/`does something` part needs a data_member/variable that is of type `T&amp;` if `stream_expression` is lvalue and `T` otherwise, then at some point the use case `[](decltype((stream_expression)) s)-&gt;???&lt;my::remove_rvalue_reference_t&lt;decltype((stream_expression))&gt;&gt;{...}(stream_expression)` which needs correct `__func__` appears.
</details>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" lambda C++11 lambda expressions
Projects
None yet
Development

No branches or pull requests

3 participants