Skip to content

refactor(Storage): collapse at<T>/back<T>/data<T> into single template bodies#979

Merged
ianmccul merged 6 commits into
masterfrom
claude/strange-kowalevski-89d35a
Jul 11, 2026
Merged

refactor(Storage): collapse at<T>/back<T>/data<T> into single template bodies#979
ianmccul merged 6 commits into
masterfrom
claude/strange-kowalevski-89d35a

Conversation

@yingjerkao

Copy link
Copy Markdown
Collaborator

Summary

Each of Storage_base::at<T>, back<T>, and data<T> was 11 hand-written explicit specializations with identical bodies, differing only in the dtype enum and the type spelling inside the error message. That copy-paste already let one dtype check drift out of sync (#965, fixed by #978). This collapses each family into a single template body:

  • The expected dtype comes from the existing compile-time trait Type_class::cy_typeid_v<T>, so the dtype check now exists in exactly one place per function and cannot drift per-type again.
  • A file-local type_spelling<T> trait supplies the C++ type spelling embedded in the error messages ("<float>", "< std::complex<double> >", ...), preserving the existing wording byte-for-byte.
  • Explicit instantiations for the same 11 types keep the exported symbols and the header declaration (include/backend/Storage.hpp) unchanged.
  • The GPU-only data<cuDoubleComplex> / data<cuFloatComplex> specializations keep their extra device check and remain hand-written.

Net: −413/+82 lines, no functional change.

Stacked on #978 (base: fix/storage-at-unconditional-dtype-check) since it touches the same lines; retarget to master after that merges.

Verification

  • nm diff of the old vs new object file: all 33 mangled symbols identical (binding goes strong → weak, the normal consequence of explicit instantiation definitions; the body is only visible in this TU, so these remain the only definitions).
  • Error-message check: a probe triggering all 11 dtype mismatches plus the out-of-bound, empty-back, and data mismatch errors, linked against both the old and new implementation — what() message lines are byte-identical in every case. Only the # Cytnx error occur at ... diagnostic line changes rendering (template pretty-function instead of the specialization's), which nothing asserts on.
  • Storage test suite: 284 passed / 11 pre-existing skips / 0 failed (exit 0), including StorageTest.AtDtypeMismatchThrows* and StorageTest.AtOutOfBoundMessageReportsIndexAndSize run explicitly; Tensor suite 9/9.
  • clang-format 14 (the CI-pinned version) reports no violations.

🤖 Generated with Claude Code

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request refactors Storage_base.cpp by replacing repetitive explicit template specializations of data<T>, at<T>, and back<T> with unified template implementations and explicit instantiations, utilizing a type_spelling variable template for error messages. Feedback suggests enforcing compile-time safety for type_spelling using a helper struct with static_assert to prevent potential runtime undefined behavior if an unspecialized type is instantiated.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/backend/Storage_base.cpp Outdated
Comment on lines +497 to +498
template <typename T>
constexpr const char *type_spelling = nullptr;

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.

medium

Currently, the primary template of type_spelling defaults to nullptr. If a new type is added to the explicit instantiations of data<T>, at<T>, or back<T> but is not specialized in type_spelling, it will compile successfully but result in undefined behavior at runtime when cytnx_error_msg attempts to format a nullptr with %s.

To prevent this, we can enforce compile-time safety by making the primary template trigger a compilation error if it is instantiated. Since always_false_v is already defined in Type.hpp, we can use a helper struct with a static_assert to block unspecialized types at compile time.

Suggested change
template <typename T>
constexpr const char *type_spelling = nullptr;
template <typename T>
struct type_spelling_holder {
static_assert(always_false_v<T>, "type_spelling is not specialized for this type");
static constexpr const char *value = nullptr;
};
template <typename T>
constexpr const char *type_spelling = type_spelling_holder<T>::value;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done in 79fb7d0. Routed the primary type_spelling template through a type_spelling_holder<T> with static_assert(always_false_v<T>, ...), so any type that reaches the at/back/data dtype-mismatch message without an explicit spelling is now a hard compile error instead of a silent nullptr fed to %s. The 11 specialized types are unchanged, and the hand-written GPU data<cuDoubleComplex>/data<cuFloatComplex> specializations never reference type_spelling, so they're unaffected. Verified: the CPU TU compiles clean with the real build flags, and an isolated probe confirms an unspecialized type now fails with "type_spelling is not specialized for this type".

@ianmccul

ianmccul commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Add to include/Type.hpp:

template <typename T> concept CytnxType = variant_contains_v<T, Type_list>;

Then the functions can use

template <CytnxType T>
T* Storage_base::data() const { ... }

and attempt to convert to a type that has no corresponding dtype will not compile. Not sure how that works with the cuDoubleComplex / cuFloatComplex specializations, since I don't think you can add a specialization to a template where the primary declaration is a concept but the specialization is not part of the concept. But I think you can probably do

template <typename T>
T* Storage_base:::data() const = delete; // unsupported T: compile-time error

template <CytnxType T>
T* Storage_base::data() const { ... }

#ifdef UNI_GPU
template <>
cuDoubleComplex* Storage_base::data<cuDoubleComplex>() const { ... }
template <>
cuFloatComplex* Storage_base::data<cuFloatComplex>() const { ... }
#endif

Base automatically changed from fix/storage-at-unconditional-dtype-check to master July 6, 2026 12:16
@yingjerkao

Copy link
Copy Markdown
Collaborator Author

Add to include/Type.hpp:

template <typename T> concept CytnxType = variant_contains_v<T, Type_list>;

Then the functions can use

template <CytnxType T>
T* Storage_base::data() const { ... }

and attempt to convert to a type that has no corresponding dtype will not compile. Not sure how that works with the cuDoubleComplex / cuFloatComplex specializations, since I don't think you can add a specialization to a template where the primary declaration is a concept but the specialization is not part of the concept. But I think you can probably do

template <typename T>
T* Storage_base:::data() const = delete; // unsupported T: compile-time error

template <CytnxType T>
T* Storage_base::data() const { ... }

#ifdef UNI_GPU
template <>
cuDoubleComplex* Storage_base::data<cuDoubleComplex>() const { ... }
template <>
cuFloatComplex* Storage_base::data<cuFloatComplex>() const { ... }
#endif

Are these in #1004

yingjerkao added a commit that referenced this pull request Jul 7, 2026
…cialized

Address @gemini-code-assist review on #979. The primary template of
type_spelling defaulted to nullptr, so adding a new at<T>/back<T>/data<T>
instantiation without a matching spelling would compile and then feed a null
pointer to the "%s" conversion in cytnx_error_msg — runtime UB.

Route the primary template through a type_spelling_holder<T> whose body is
static_assert(always_false_v<T>). Any type that reaches the dtype-mismatch
message without an explicit spelling is now rejected at compile time. The 11
specialized types are unchanged, and the hand-written GPU data<cuDoubleComplex>/
data<cuFloatComplex> specializations never reference type_spelling, so they are
unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yingjerkao
yingjerkao force-pushed the claude/strange-kowalevski-89d35a branch from 66fae90 to 79fb7d0 Compare July 7, 2026 06:51
@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 55.67%. Comparing base (d6dcd16) to head (f346f7b).
⚠️ Report is 101 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/backend/Storage_base.cpp 66.66% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master     #979       +/-   ##
===========================================
+ Coverage   31.82%   55.67%   +23.84%     
===========================================
  Files         230      230               
  Lines       33124    32979      -145     
  Branches    13852       77    -13775     
===========================================
+ Hits        10543    18360     +7817     
+ Misses      15539    14594      -945     
+ Partials     7042       25     -7017     
Flag Coverage Δ
cpp 55.59% <66.66%> (+24.13%) ⬆️
python 61.84% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
C++ backend 53.34% <66.66%> (+20.79%) ⬆️
Python bindings 70.35% <ø> (+46.33%) ⬆️
Python package 61.84% <ø> (ø)
Files with missing lines Coverage Δ
include/Type.hpp 97.56% <ø> (+43.90%) ⬆️
include/backend/Storage.hpp 95.26% <ø> (+14.20%) ⬆️
src/backend/Storage_base.cpp 27.84% <66.66%> (+3.47%) ⬆️

... and 172 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d6dcd16...f346f7b. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ianmccul

ianmccul commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

No, they would be an addition to this PR, they are not connected with #1004. Except with #1004 the overloads for the GPU types should be Storage_base::data<cuda::std::complex<T>>() -- actually you could have both the cuda::std::complex and cuComplex versions, and it probably makes sense to do this.

yingjerkao and others added 3 commits July 7, 2026 17:22
…e bodies

Each of at<T>, back<T>, and data<T> was 11 hand-written explicit
specializations with identical bodies, differing only in the dtype enum
and the type spelling inside the error message. That copy-paste already
let one dtype check drift out of sync (#965). Replace each family with
one template body that derives the expected dtype from the compile-time
trait Type_class::cy_typeid_v<T>, plus explicit instantiations for the
same 11 types, so the exported symbols and header declarations are
unchanged. The GPU-only data<cuDoubleComplex>/data<cuFloatComplex>
specializations keep their extra device check and remain hand-written.

Error-message wording is preserved byte-for-byte (verified by diffing
the what() text of all 11 mismatch cases plus bounds/empty errors
against the previous implementation).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cialized

Address @gemini-code-assist review on #979. The primary template of
type_spelling defaulted to nullptr, so adding a new at<T>/back<T>/data<T>
instantiation without a matching spelling would compile and then feed a null
pointer to the "%s" conversion in cytnx_error_msg — runtime UB.

Route the primary template through a type_spelling_holder<T> whose body is
static_assert(always_false_v<T>). Any type that reaches the dtype-mismatch
message without an explicit spelling is now rejected at compile time. The 11
specialized types are unchanged, and the hand-written GPU data<cuDoubleComplex>/
data<cuFloatComplex> specializations never reference type_spelling, so they are
unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
)

Incorporate @ianmccul's review suggestion. Add a C++20 concept

  template <typename T> concept CytnxType = variant_contains_v<T, Type_list>
                                            && !std::is_void_v<T>;

and constrain Storage_base::data<T>/at<T>/back<T> to it, with the unconstrained
primary `= delete`d. Requesting an unsupported T (e.g. data<char>()) is now a
hard compile error at the call site -- "use of deleted function" -- instead of
relying on the downstream cy_typeid_v/type_spelling failures. This complements
the existing type_spelling static_assert, which still guards a CytnxType added
without a spelling.

The GPU complex views are non-cytnx-dtype types, so they remain explicit
specializations of the deleted primary. Following Ian's second note and #1004,
data<> now offers both representations: the existing cuDoubleComplex /
cuFloatComplex (cuBLAS/cuSOLVER ABI pointers) and the new
cuda::std::complex<double/float> (what GPU kernels use internally). at<>/back<>
gain no GPU specializations -- they were never valid for the cu* types.

Verified:
- Full CPU library + test suite build; Storage/Type/Tensor suites 300 passed,
  0 failed (11 pre-existing skips).
- data<char>() is rejected with "use of deleted function [with T = char]".
- Storage_base.cpp compiles under UNI_GPU with the CCCL include path, so all
  four GPU data<> specializations (cuComplex + cuda::std::complex) type-check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yingjerkao
yingjerkao force-pushed the claude/strange-kowalevski-89d35a branch from 79fb7d0 to 867e5bf Compare July 7, 2026 09:29
@yingjerkao

Copy link
Copy Markdown
Collaborator Author

Done in 867e5bf (rebased onto master first, so #1004's cuda::std::complex is in the base).

Added the concept to Type.hpp:

template <typename T>
concept CytnxType = variant_contains_v<T, Type_list> && !std::is_void_v<T>;

(excluding the Void placeholder, which is in Type_list but isn't a real element type).

data/at/back now use exactly the = delete primary + constrained-overload pattern you sketched:

template <typename T> T* data() const = delete;   // unsupported T -> hard error
template <CytnxType T> T* data() const;

so e.g. data<char>() fails at the call site with "use of deleted function T* Storage_base::data() const [with T = char]" rather than falling through to the cy_typeid_v/type_spelling diagnostics. It composes with the earlier type_spelling static_assert, which still catches a CytnxType added without a spelling.

Per your second comment, the GPU complex overloads are provided both ways (they're explicit specializations of the deleted primary, since neither is a cytnx dtype):

at/back get no GPU specializations — they were never valid for the cu* types (the old unconstrained template would already have failed in variant_index).

Verified: full CPU library + test suite build; Storage/Type/Tensor suites 300 passed / 0 failed (11 pre-existing skips); data<char>() correctly rejected; and Storage_base.cpp compiles under UNI_GPU (with the CCCL include path) so all four GPU data<> specializations type-check. I couldn't run a full GPU link here because cuKron is currently broken under CUDA 13 (#999), unrelated to this change.

@ianmccul

ianmccul commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

I thought #1004 fixed #999 ?

yingjerkao and others added 2 commits July 7, 2026 17:42
Follow-up to constraining Storage_base. The thin Storage wrapper methods
(Storage::data<T>/at<T>/back<T>, which just delegate to _impl) were still
`template <class T>`, so an unsupported T errored one level deep inside the
wrapper body instead of at the call site. Constrain all three to CytnxType so
e.g. Storage::data<char>() fails at the call with "constraints not satisfied
... CytnxType<T>" naming the concept.

They use CytnxType (not a wider GPU-inclusive concept) deliberately: the
Storage_base GPU data<> specializations (cuComplex / cuda::std::complex) are
defined only in Storage_base.cpp and are not declared in Storage.hpp, so they
are not reachable through the wrapper from any external TU -- true on master as
well. Advertising them in the wrapper constraint would let the constraint pass
and then fail in the body at the deleted primary, which is worse than a clean
call-site rejection. Making those views externally reachable (header-declaring
the specializations) would be a separate change.

Verified: full CPU library + test suite build; Storage/Tensor suites 280 passed
/ 0 failed (11 pre-existing skips); data<char>()/at<char>() rejected at the
wrapper; header parses under UNI_GPU.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…apper

Declare the four GPU data<> explicit specializations (cuDoubleComplex,
cuFloatComplex, cuda::std::complex<double>, cuda::std::complex<float>) in
Storage.hpp, at namespace scope before the Storage wrapper. Previously they
were defined only in Storage_base.cpp, so from any other TU
`_impl->data<cuComplex>()` resolved to the deleted primary -- the views were
unreachable outside that one file (true on master too, and there were no
callers).

With the declarations visible, widen the Storage::data<T> wrapper constraint
back to StorageDataType (CytnxType plus the four GPU views), re-adding the
GpuComplexView / StorageDataType concepts. So `storage.data<cuDoubleComplex>()`
/ `data<cuda::std::complex<double>>()` now compile and link end-to-end, while
`data<char>()` is still rejected at the call site. at<>/back<> stay CytnxType
(they have no GPU specializations).

Verified:
- GPU (UNI_GPU + CCCL include): the wrapper compiles data<cuDoubleComplex>,
  data<cuFloatComplex>, and both cuda::std::complex views; data<char> and
  at<cuDoubleComplex> are rejected; Storage_base.cpp emits all four
  specializations as strong (T) symbols matching the header declarations.
- CPU: full library + test suite build; header parses (decls are #ifdef'd out);
  data<char> rejected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yingjerkao

Copy link
Copy Markdown
Collaborator Author

Follow-up on the wrapper, @ianmccul — now fully wired through, in two commits on top of the concept change:

1. Constrained the Storage wrapper too (92f86060). The thin Storage::data<T>/at<T>/back<T> delegators were still template <class T>, so an unsupported T errored one level deep in the wrapper body. All three now carry the constraint, so storage.data<char>() fails right at the call site with constraints not satisfied … CytnxType<T>.

2. Made the GPU views actually reachable (a70638f8). While constraining the wrapper I found the GPU data<> specializations were only defined in Storage_base.cpp and never declared in Storage.hpp — so from any other TU _impl->data<cuDoubleComplex>() resolved to the deleted primary. They were unreachable outside that one file (true on master too; there were no callers). So I:

  • declared all four specializations in Storage.hpp at namespace scope before the wrapper, and
  • widened the data wrapper constraint to a StorageDataType concept = CytnxType ∪ the four GPU views.

Now storage.data<cuDoubleComplex>(), data<cuFloatComplex>(), and data<cuda::std::complex<double/float>>() compile and link end-to-end, while data<char>() is still rejected. at/back stay CytnxType-only (they have no GPU specializations — the old unconstrained template would already have failed in variant_index).

Verified:

  • GPU (UNI_GPU + CCCL include): the wrapper compiles all four GPU views and data<char>/at<cuDoubleComplex> are rejected; nm confirms Storage_base.cpp emits the four specializations as strong (T) symbols (double2, float2, both cuda::std::complex) matching the header declarations.
  • CPU: full library + test suite build; Storage suite 268 passed / 0 failed (11 pre-existing skips).

I couldn't run a full GPU link here because cuKron is currently broken under CUDA 13 (#999), unrelated to this change — but the per-TU compile + symbol check covers the declaration↔definition contract.

@pcchen

pcchen commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Code Review

Collapses Storage_base::at<T>/back<T>/data<T> from 11 hand-written specializations each into single template bodies. The refactor itself is correct and well-executed — but it introduces a downstream-compat regression that must be fixed before merge.

The refactor is correct (verified in full)

  • Single template bodies; the dtype check now comes from cy_typeid_v<T> — one source of truth, so the Storage::at<T>() and Tensor::item<T>() silently reinterpret mismatched dtype in normal builds #965-style per-type drift cannot recur. ✅
  • type_spelling<T> (variable template with a static_assert default) reproduces the old inline spellings, and the new bodies are byte-faithful to the old ones (bounds check on at, empty check on back — even the "stoarge" typo preserved — cudaDeviceSynchronize, static_cast). The "...try to get %s type..." + type_spelling<T> renders byte-identical. ✅
  • Concept-constrained declarations + an unconstrained = delete fallback → an unsupported T is now a clean compile-time error at the call site (was a link error). GPU data<cuDoubleComplex/cuFloatComplex> specializations are #ifdef UNI_GPU-guarded and header-declared (ODR-correct); StorageDataType is correctly used on the Storage wrapper's data<T> to admit them. ✅
  • Explicit instantiations preserve all exported symbols (the nm diff in the description confirms). ✅

🔴 Blocker — breaks DownstreamFindPackage (CI-verified)

include/Type.hpp:194: error: 'concept' does not name a type; did you mean 'const'?
include/backend/Storage.hpp:55: error: 'CytnxType' has not been declared

This PR introduces the first C++20 concepts into a universally-included public header (Type.hpp), but cytnx sets C++20 only via the build-level CMAKE_CXX_STANDARD variable — it does not export the requirement to consumers. So find_package(cytnx) consumers compile the headers in their default (pre-C++20) mode and fail to parse concept. DownstreamFindPackage was green on the recent merges (#972/#977/#998), so this is a regression this PR surfaces.

Fix: have cytnx declare its language requirement to consumers on the installed/exported target, e.g.

target_compile_features(cytnx PUBLIC cxx_std_20)

rather than relying only on the build-level CMAKE_CXX_STANDARD. That's a CMake change not in this PR. Silver lining: it fixes a genuine latent gap — the public headers already require C++20 (std::format, std::source_location); the concept keyword just makes it undeniable, and exporting the requirement benefits every downstream consumer.

Notes

  • Behind master but MERGEABLE; BuildAndTest is green on Linux + macOS (cytnx's own build is C++20). macOS-15-intel + wheels were still pending.

Recommendation: request changes — the dedup + API hardening is good and should land; it just needs the PUBLIC cxx_std_20 export (or equivalent) so DownstreamFindPackage passes.

Posted by Claude Code on behalf of @pcchen

pcchen added a commit that referenced this pull request Jul 10, 2026
…oid guards, Sproxy consolidation

Implements items B, C and D of the consolidated review checklist
(A -- explicit constrained ctor + operator<=> -- is split into a
follow-up PR, since it changes overload resolution codebase-wide and
carries an unresolved complex-ordering semantic decision):

B. Conversion surface (review threads on Scalar.hpp:354, Scalar.cpp:227/60/322):
- One constrained template  replaces the
  9 per-type cast operators; conversions the language cannot perform
  error with Type_enum_name-based text (complex->real adds the
  real()/imag() hint). to_complex128()/to_complex64() delegate to it.
- Type_enum_name<std::monostate> added (displays as "Void").
- astype() on a Void source now errors instead of silently staying
  Void; the dead convert_value/explicit_cast helpers are removed.

C. Correctness items (codex findings):
- conj() on a Void Scalar throws (old PIMPL contract) instead of
  silently returning Void.
- Sproxy's 11 per-type assignment overloads collapse to one
  CytnxType-constrained template delegating through Scalar.
- Type_class::norm_result_dtype(Void) rejects instead of mapping to
  Double. The CytnxType concept is the documented one-liner from #979.
- Stale "lossy in-place combinations throw" comment updated to the
  promote semantics.

D. pytest: test_inplace_same_dtype_keeps_dtype pins Int32 operands via
astype() to sidestep the preexisting pybind ctor-collapse quirk that
#1014 fixes (workaround documented for removal).

Verified: C++ suite 1676 ran / 1665 passed / 11 skipped / 0 failed
(4 new Void-guard tests); pytests/scalar_variant_test.py 43/43 against
the freshly built extension; clang-format 14.0.6.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e_features

PR #979 adds the first C++20 concept (CytnxType) to a universally-included
public header (Type.hpp). cytnx only sets C++20 at build level
(CMAKE_CXX_STANDARD), which does not propagate through the installed/exported
target, so find_package(cytnx) consumers compile the public headers in their
default standard and fail to parse `concept` -- breaking DownstreamFindPackage.

Add target_compile_features(cytnx PUBLIC cxx_std_20) so the exported target
carries the requirement to consumers. This also closes a pre-existing latent
gap: the public headers already require C++20 (std::format,
std::source_location); the concept just makes it undeniable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yingjerkao

Copy link
Copy Markdown
Collaborator Author

@ianmccul You're right, and my two "cuKron still broken" notes were stale — I was building a base that predated the fix. #1004 fixed it: commit 7bbd814 rewrote the kernel line to compute in the output dtype (out[i] = TO(Lin[x]) * TO(Rin[y])), and #1019 then deleted cucomplex_arithmetic outright, so the cuFloatComplex × real → cuFloatComplex overloads at the root of #994/#999 are gone. Confirmed cuKron compiles on current master — I've closed #999 and #994 (and superseded PR #995) accordingly.

@yingjerkao

Copy link
Copy Markdown
Collaborator Author

@pcchen Confirmed and fixed in this PR (f346f7b). DownstreamFindPackage was red for exactly the reason you diagnosed: this is the first concept in a universally-included public header (Type.hpp), which turns the already-latent C++20 requirement (std::format, std::source_location) into a hard parse error for consumers that compile our headers in their default standard. We only set CMAKE_CXX_STANDARD at build level and never exported it.

Applied your recommended fix on the cytnx target:

target_compile_features(cytnx PUBLIC cxx_std_20)

so find_package(cytnx) consumers inherit -std=c++20. As you noted, this also closes the pre-existing latent gap rather than just papering over the concept keyword. CI is re-running; expecting DownstreamFindPackage to go green now. Thanks for the thorough review.

@ianmccul ianmccul left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@ianmccul
ianmccul merged commit fbc3608 into master Jul 11, 2026
19 checks passed
@ianmccul
ianmccul deleted the claude/strange-kowalevski-89d35a branch July 11, 2026 01:51
yingjerkao added a commit that referenced this pull request Jul 13, 2026
… master

master's #979 landed `concept CytnxType` in include/Type.hpp, while this
branch had added its own equivalent one-liner in include/backend/Scalar.hpp
(checklist item C). Merging master in left both definitions present, so every
TU that pulls in Scalar.hpp (via Storage.hpp) failed to compile with
"redefinition of template<class T> concept cytnx::CytnxType" -- the
DownstreamFindPackage CI failure.

The two definitions are semantically identical (Type.hpp's
`variant_contains_v<T, Type_list> && !is_void_v<T>` == the 11 concrete types
this branch enumerated). Scalar.hpp already includes Type.hpp, so drop the
local copy and rely on the canonical one, exactly the "the other rebases"
resolution flagged in the #1011 review when #979 lands first.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants