Skip to content

[libcudacxx] Add cuda::std::__stringize for compile-time values including function names#9299

Open
andralex wants to merge 14 commits into
NVIDIA:mainfrom
andralex:andralex/pretty-func-nameof
Open

[libcudacxx] Add cuda::std::__stringize for compile-time values including function names#9299
andralex wants to merge 14 commits into
NVIDIA:mainfrom
andralex:andralex/pretty-func-nameof

Conversation

@andralex

@andralex andralex commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

cuda::std::__pretty_nameof<T>() gives the spelling of a type (e.g. "int"),
but there was no equivalent for non-type template parameters. This PR adds a
single helper:

  • cuda::std::__stringize<V>() — returns the compiler's spelling of any value
    passed as a non-type template parameter (integral constants, enums, bools,
    pointers, functions, ...). When the value is a function it transparently
    produces the function's name.
cuda::std::__stringize<42>();                      // -> "42"
cuda::std::__stringize<true>();                    // -> "true"  (gcc/clang; MSVC may differ)
cuda::std::__stringize<cudaStreamSynchronize>();   // -> "cudaStreamSynchronize"
cuda::std::__stringize<&cudaStreamSynchronize>();  // -> "cudaStreamSynchronize"

(Original function-name proof of concept: https://godbolt.org/z/vM9f37zrr)

Implementation

The value is wrapped in a class-template NTTP (__stringize_wrapper<V>) and
__pretty_nameof is reused on that wrapper type, so the helper automatically
inherits the same compiler support and quirk handling
as __pretty_nameof:

  • GCC < 9 static-storage workaround for constexpr __PRETTY_FUNCTION__,
  • broken MSVC __FUNCSIG__ (_CCCL_BROKEN_MSVC_FUNCSIG) fallback,
  • old-GCC device-code path (_CCCL_NO_CONSTEXPR_PRETTY_NAMEOF).

After trimming the wrapper, function arguments are detected via type traits
(is_function / is_member_function_pointer) and the leading & that
clang/cudafe prepend is dropped, so functions yield just their name. Namespace
qualifiers are kept, matching __pretty_nameof for types; the qualification the
compiler emits is relative to the wrapper's namespace, so global functions (e.g.
CUDA runtime APIs) come out unqualified. The result is constexpr wherever
__pretty_nameof is.

Caveat on value spellings

The exact spelling of a non-function value is whatever the compiler emits and is
not guaranteed identical across compilers — e.g. an unsigned literal can be
"42" (g++) or "42U" (nvcc/EDG at constexpr time), a char may be quoted, a
bool may be "true" or "1" (MSVC), and enumerators may be spelled by name or
by a cast. Integer literals are spelled identically everywhere; the tests check
those exactly and use distinctness / substring checks otherwise.

Test plan

  • New lit test std/utilities/utility/typeid/stringize.pass.cpp (integers,
    bools, distinctness, free function, &function pointer form, kept namespace
    qualifier, overload-via-cast on host compilers) passes locally with nvcc 13.2
    • g++ 14.2 under -fno-rtti and -Werror=all-warnings (C++17/20).
  • In-header smoke static_asserts.
  • Existing typeid.pass.cpp still passes (shared header).
  • pre-commit (clang-format, codespell) clean.
  • Full CI (clang host/device, MSVC, NVRTC).

Add `cuda::std::__pretty_nameof_fn<Fn>()`, the function-name counterpart of
`__pretty_nameof<T>()`, returning the unqualified spelling of a function passed
as a non-type template parameter (e.g. `"cudaStreamSynchronize"` for
`cudaStreamSynchronize`).

It is implemented by wrapping the function value in a class-template NTTP and
reusing `__pretty_nameof` on that wrapper type, so it automatically inherits the
same compiler support and quirk handling (GCC < 9 static storage, broken MSVC
__FUNCSIG__, old-GCC device code). A leading `&` (clang/cudafe) and any namespace
qualifier are trimmed, matching the proof of concept.

Includes an in-header smoke test and a dedicated lit test.
@andralex andralex requested a review from a team as a code owner June 8, 2026 18:17
@andralex andralex requested a review from Jacobfaib June 8, 2026 18:17
@github-project-automation github-project-automation Bot moved this to Todo in CCCL Jun 8, 2026
@copy-pr-bot

copy-pr-bot Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@andralex

andralex commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 2a766dc

@cccl-authenticator-app cccl-authenticator-app Bot moved this from Todo to In Review in CCCL Jun 8, 2026
andralex added 2 commits June 8, 2026 14:26
Do not strip the namespace qualifier from the function name, matching
__pretty_nameof for types. The namespace qualification the compiler emits is
relative to the wrapper's namespace, so global functions (e.g. CUDA runtime
APIs) still come out unqualified.

Make the in-header smoke test robust to compiler-dependent spelling of the
inline ABI namespace (substring check), and update the lit test to expect the
qualified spelling for a namespaced function.
@andralex

andralex commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 6002c07

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

suggestion:

Walkthrough

Adds constexpr extraction of NTTP value spellings via __pretty_nameof_v<_Vp>(), trimming the compiler wrapper and removing a leading & for function/function-pointer NTTPs. Includes guarded compile-time and host runtime tests for integral/boolean values and function-name extraction.

Changes

Value pretty-name extraction for NTTPs

Layer / File(s) Summary
Type-trait includes for function detection
libcudacxx/include/cuda/std/__utility/typeid.h
Adds is_function, is_member_function_pointer, and remove_pointer includes to support function/function-pointer NTTP detection during spelling extraction.
Wrapper type and trimming helper
libcudacxx/include/cuda/std/__utility/typeid.h
Introduces __pretty_nameof_v_wrapper<_Vp> template and __find_pretty_nameof_v function that strips the wrapper template prefix/suffix from the compiler-generated pretty-name string to recover the value's spelling.
Public API implementation with function-pointer handling
libcudacxx/include/cuda/std/__utility/typeid.h
Adds __pretty_nameof_v<_Vp>() which applies __pretty_nameof to the wrapper, trims the result, and conditionally removes a leading & for function/function-pointer NTTPs.
Test coverage: compile-time assertions and runtime validation
libcudacxx/include/cuda/std/__utility/typeid.h, libcudacxx/test/libcudacxx/std/utilities/utility/typeid/pretty_nameof_v.pass.cpp
Adds guarded constexpr static_assert checks and a host-side main() that validate exact spellings for integral/boolean NTTPs, distinctness of different values, and function-name extraction (including overloads and qualified names).

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
libcudacxx/include/cuda/std/__utility/typeid.h (1)

225-237: ⚡ Quick win

suggestion: Add missing @return tag to Doxygen comment.

The function has a detailed @brief but lacks the mandatory @return tag. As per coding guidelines, Doxygen-documented functions with non-void return types must include //! @return``.

Suggested addition

After line 231, add:

 //! This is the function-name counterpart of `__pretty_nameof`. It supports the
 //! same set of compilers and the same compiler quirks, because it is implemented
 //! on top of `__pretty_nameof`.
+//! `@return` A string view containing the function name, preserving namespace qualifiers.
 template <auto _Fn>

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e9d9739c-8568-4032-a1da-94647ebb652b

📥 Commits

Reviewing files that changed from the base of the PR and between f29d7fd and 6002c07.

📒 Files selected for processing (2)
  • libcudacxx/include/cuda/std/__utility/typeid.h
  • libcudacxx/test/libcudacxx/std/utilities/utility/typeid/pretty_nameof_fn.pass.cpp

@github-actions

This comment has been minimized.

…value

The function-name wrapper trick generalizes to any value passed as a non-type
template parameter. Add `cuda::std::__pretty_nameof_v<V>()`, the value
counterpart of `__pretty_nameof<T>()`, returning the compiler's spelling of V
(e.g. `"42"` for `42`, `"true"` for `true`).

`__pretty_nameof_fn` is now implemented on top of `__pretty_nameof_v`, only
adding the leading-'&' trim for function arguments. The exact spelling of a
value is not guaranteed to be identical across compilers (e.g. unsigned suffix,
char quoting, enumerator spelling); integral and boolean values are stable.

Add a dedicated pretty_nameof_v lit test and a header smoke test.
@andralex

andralex commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test b781579

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
libcudacxx/include/cuda/std/__utility/typeid.h (1)

244-246: ⚡ Quick win

suggestion: constrain __pretty_nameof_fn to function/function-pointer NTTPs (e.g., via requires/SFINAE + function traits) so non-function values fail at compile time instead of silently behaving like __pretty_nameof_v.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 1d4fff2e-44af-488f-aa5c-6c111b14dc65

📥 Commits

Reviewing files that changed from the base of the PR and between 6002c07 and b781579.

📒 Files selected for processing (2)
  • libcudacxx/include/cuda/std/__utility/typeid.h
  • libcudacxx/test/libcudacxx/std/utilities/utility/typeid/pretty_nameof_v.pass.cpp

Comment thread libcudacxx/include/cuda/std/__utility/typeid.h Outdated
Minimize the API surface to a single entry point. __pretty_nameof_v now detects
function (and function-pointer / member-function-pointer) arguments via type
traits and drops the leading '&' that clang and cudafe prepend, so callers no
longer need a separate __pretty_nameof_fn.

Consolidate the function-name tests into pretty_nameof_v.pass.cpp and drop the
now-redundant pretty_nameof_fn.pass.cpp.
@andralex

andralex commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 6995224

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
libcudacxx/include/cuda/std/__utility/typeid.h (1)

247-250: 💤 Low value

suggestion: The substr call on line 249 passes ptrdiff_t(__sv.size()) as the count argument when removing the first character. Since substr(pos) with no count argument means "to the end," you can simplify to __sv = __sv.substr(1); for clarity.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: f2419596-05c6-40ff-bac0-a598aafc30b8

📥 Commits

Reviewing files that changed from the base of the PR and between b781579 and 6995224.

📒 Files selected for processing (2)
  • libcudacxx/include/cuda/std/__utility/typeid.h
  • libcudacxx/test/libcudacxx/std/utilities/utility/typeid/pretty_nameof_v.pass.cpp

@andralex andralex changed the title [libcudacxx] Add cuda::std::__pretty_nameof_fn for function names [libcudacxx] Add cuda::std::__pretty_nameof_v for compile-time values including function names Jun 8, 2026
Add coverage for an overloaded function, where the desired overload is selected
with a cast in the template argument. The check is at namespace scope: inside a
function body cudafe++ rewrites the cast back to the ambiguous bare name, so the
disambiguating cast must be applied where the value is used as a template
argument directly.
@andralex

andralex commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test d9c1636

@andralex andralex enabled auto-merge (squash) June 8, 2026 21:58
@andralex

andralex commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 13a5551

andralex added 2 commits June 8, 2026 18:49
Two CI failures:

- MSVC spells a bool NTTP as something other than "true"/"false", which broke
  the in-header smoke static_assert (and therefore every MSVC build that
  transitively includes typeid.h). Drop the bool exact-match; only integer
  literals are spelled identically across all compilers. Use a distinctness
  check instead.

- The cast-disambiguated overload test failed under nvcc on CTK 12.0/12.9/13.0/
  13.3: cudafe++ rewrites static_cast<...>(overload) back to the ambiguous
  &overload (it happened to survive on the locally-tested CTK 13.2). Guard that
  case to non-CUDA compilation.

Make the test robust to compiler-dependent value spellings: exact matches only
for integer literals, distinctness for bool, substring checks for function
names everywhere, and exact function-name matches gated to non-MSVC.
@andralex

andralex commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test e085586

Rename the generalized value-spelling facility to cuda::std::__stringize (and
its internals __stringize_wrapper / __find_stringize), and rename the test to
stringize.pass.cpp. The type-based __pretty_nameof is unchanged.
@andralex andralex changed the title [libcudacxx] Add cuda::std::__pretty_nameof_v for compile-time values including function names [libcudacxx] Add cuda::std::__stringize for compile-time values including function names Jun 8, 2026
@andralex

andralex commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test fb8f675

Add an explicit @return tag to satisfy libcudacxx documentation requirements.
@andralex

andralex commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 30cd5bc

@github-actions

This comment has been minimized.

@andralex

andralex commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 9f38b2b

@github-actions

This comment has been minimized.

@andralex

andralex commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 9f38b2b

{
// Trim the surrounding "__stringize_wrapper<" ... ">".
return __sv.substr(::cuda::std::__add_string_view_position(
__sv.find("__stringize_wrapper<"), ptrdiff_t(sizeof("__stringize_wrapper<")) - 1),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
__sv.find("__stringize_wrapper<"), ptrdiff_t(sizeof("__stringize_wrapper<")) - 1),
__sv.find("__stringize_wrapper<"), static_cast<ptrdiff_t>(sizeof("__stringize_wrapper<")) - 1),

{
if (__sv.size() != 0 && __sv[0] == '&')
{
__sv = __sv.substr(1, ptrdiff_t(__sv.size()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
__sv = __sv.substr(1, ptrdiff_t(__sv.size()));
__sv = __sv.substr(1, static_cast<ptrdiff_t>(__sv.size()));

//! template parameter, e.g. `__stringize<42>()` yields `"42"` and
//! `__stringize<cudaStreamSynchronize>()` yields `"cudaStreamSynchronize"`.
//!
//! @return A string view containing the compiler's spelling of `_Vp`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should document @tparam as well

return __sv;
}

#if !defined(_CCCL_NO_CONSTEXPR_PRETTY_NAMEOF) && !defined(_CCCL_BROKEN_MSVC_FUNCSIG)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's gate this behind _CCCL_ENABLE_DEBUG_MODE as well, no point wasting the compilers time in release builds as well.

// unqualified name is present rather than matching it exactly.
static_assert(::cuda::std::__stringize<&::cuda::std::__add_string_view_position>().find("__add_string_view_position")
!= -1);
#endif

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs #endif comment

[[nodiscard]] _CCCL_API constexpr __string_view __stringize() noexcept
{
__string_view __sv =
::cuda::std::__find_stringize(::cuda::std::__pretty_nameof<::cuda::std::__stringize_wrapper<_Vp>>());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need the wrapper? Can we not do decltype()?

@andralex

andralex commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 0fd6c30

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

🥳 CI Workflow Results

🟩 Finished in 1h 55m: Pass: 100%/118 | Total: 2d 17h | Max: 1h 15m | Hits: 61%/547971

See results here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

2 participants