__PRETTY_FUNCTION__ changes depending on template instantiation
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
```cpp
template
[[nodiscard]] constexpr
auto PrettyValueFn() {
return __PRETTY_FUNCTION__;
}
template
struct TestTemplate {
enum class TestScopedEnum { X, Y, Z };
};
#include
int main() {
// (void) TestTemplate::TestScopedEnum::X; // Access value first and the output is as expected
(void) PrettyValueFn::TestScopedEnum{}>(); // Changes __PRETTY_FUNCTION__ for given index
std::cout << PrettyValueFn::TestScopedEnum::X>() << '\n';
std::cout << PrettyValueFn::TestScopedEnum::Y>() << '\n';
std::cout << PrettyValueFn::TestScopedEnum::Z>() << '\n';
}
```
Output:
```
auto PrettyValueFn() [V = (TestTemplate::TestScopedEnum)0]
auto PrettyValueFn() [V = TestTemplate::TestScopedEnum::Y]
auto PrettyValueFn() [V = TestTemplate::TestScopedEnum::Z]
```
Expected output:
```
auto PrettyValueFn() [V = TestTemplate::TestScopedEnum::X]
auto PrettyValueFn() [V = TestTemplate::TestScopedEnum::Y]
auto PrettyValueFn() [V = TestTemplate::TestScopedEnum::Z]
```
This happens if you use a scoped enum in a template.
It works as expected, if you use a non-scoped enum or if your scoped enum is not defined in a template.
[Compiler Explorer](https://gcc.godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:1,endLineNumber:21,positionColumn:1,positionLineNumber:21,selectionStartColumn:1,selectionStartLineNumber:21,startColumn:1,startLineNumber:21),source:'template+%3Cauto+V%3E%0A%5B%5Bnodiscard%5D%5D+constexpr%0Aauto+PrettyValueFn()+%7B%0A++++return+__PRETTY_FUNCTION__%3B%0A%7D%0A%0Atemplate+%3Ctypename%3E%0Astruct+TestTemplate+%7B%0A++++enum+class+TestScopedEnum+%7B+X,+Y,+Z+%7D%3B%0A%7D%3B%0A%0A%0A%23include+%3Ciostream%3E%0A%0Aint+main()+%7B%0A++++(void)+PrettyValueFn%3Cstatic_cast%3CTestTemplate%3Cint%3E::TestScopedEnum%3E(0)%3E()%3B+//+Changes+__PRETTY_FUNCTION__+for+given+index%0A++++std::cout+%3C%3C+PrettyValueFn%3CTestTemplate%3Cint%3E::TestScopedEnum::X%3E()+%3C%3C+!'%5Cn!'%3B%0A++++std::cout+%3C%3C+PrettyValueFn%3CTestTemplate%3Cint%3E::TestScopedEnum::Y%3E()+%3C%3C+!'%5Cn!'%3B%0A++++std::cout+%3C%3C+PrettyValueFn%3CTestTemplate%3Cint%3E::TestScopedEnum::Z%3E()+%3C%3C+!'%5Cn!'%3B%0A%7D%0A'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:33.333333333333336,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:clang2110,filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'0',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%2B17',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+21.1.0+(Editor+%231)',t:'0')),k:33.333333333333336,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:output,i:(compilerName:'x86-64+clang+21.1.0',editorid:1,fontScale:14,fontUsePx:'0',j:1,wrap:'1'),l:'5',n:'0',o:'Output+of+x86-64+clang+21.1.0+(Compiler+%231)',t:'0')),k:33.33333333333333,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4)
All versions of Clang up to the current HEAD are affected.
Contributor guide
Research direction
Start with the reduced C++ reproducer in the issue and compare Clang's __PRETTY_FUNCTION__ output for scoped enums defined inside and outside templates, including the non-scoped enum case. Trace the compiler handling of the non-type template argument and add a regression test if the relevant test location can be identified. Done means the X, Y, and Z instantiations all produce their enumerator names rather than an underlying numeric value.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100