Skip to content

Update C++ Standards to allow C++23#609

Open
ChrisJChang wants to merge 5 commits into
GambitBSM:masterfrom
ChrisJChang:claude/gambit-cpp20-23-compat-j6dth1
Open

Update C++ Standards to allow C++23#609
ChrisJChang wants to merge 5 commits into
GambitBSM:masterfrom
ChrisJChang:claude/gambit-cpp20-23-compat-j6dth1

Conversation

@ChrisJChang

Copy link
Copy Markdown
Collaborator

This raises the minimum C++ standard to C++17, and adds some bug fixes to allow gambit to build with C++20 and C++23.

It also raises the minimum Eigen version from v3.1.0 to v3.3.7.

This still allows backends to use lower standards when they do not support higher ones, e.g. AltarBBN.

I have tested with gcc=14, and clang 18.

claude added 5 commits July 3, 2026 12:31
Build system:
- Rewrite the root and gum/ CMake standard-detection ladders to try
  C++23 -> C++20 -> C++17, and fail hard if even C++17 is unavailable
  (previously fell back through C++14/C++11/C++0x).
- Extend check_root_std_flag()'s recognised standard list so it can
  still detect a ROOT installation built with C++20/C++23 (or the
  pre-standardisation 2a/2b flag spellings) and downgrade GAMBIT to
  match; a ROOT built with pre-C++17 now triggers a clear error.
- Generalize the gm2calc/FastJet backend "downgrade to C++14" regexes,
  which previously only matched the literal "-std=c++17" substring and
  would silently stop working (compiling those backends with whatever
  newer standard GAMBIT picked) once GAMBIT's own default moved past
  C++17.
- Remove the now-vacuous "c++14" tag from check_ditch_status, since
  GAMBIT always compiles with at least C++17.
- Bump the minimum required Eigen3 version to 3.3.7, since older Eigen
  releases use STL idioms (std::unary_function/binary_function,
  std::result_of, etc.) that are deprecated or removed in C++17/20/23.

Source fixes:
- Replace `throw()` dynamic exception specifications with `noexcept`
  in Utils/exceptions.{hpp,cpp} and ColliderBit's Py8Collider.hpp;
  dynamic exception specs were removed in C++20 and would otherwise be
  a hard compile error.
- Patch the vendored yaml-cpp 0.6.2's node_iterator_base to stop
  deriving from std::iterator<...>, which was removed in C++20, and
  provide the iterator typedefs directly instead.

Verified by configuring and building under GCC 13 (which now defaults
to -std=c++23): CMake configure completes end to end, and both the
patched yaml-cpp library and several Utils translation units compile
successfully.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EDpAzhpyYk2biu7ttb9EuQ
The previous commit's comments and error messages called out that
C++11/C++14 are "no longer supported", but most users and developers
never knew or cared that GAMBIT once supported them. Reword the
standard-detection comments and FATAL_ERROR messages to just state the
current C++17+ requirement, without the historical aside.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EDpAzhpyYk2biu7ttb9EuQ
ra_copy_hdf5::run is instantiated once per printable type, including
std::string, and filled its output buffer with std::vector<U>
output(size, 0). For U = std::string, the literal 0 is a null pointer
constant, and libstdc++ added a deleted basic_string(nullptr_t)
overload in C++23 (P2166) specifically to catch this pattern, turning
what used to be a silent (and already dubious) null-pointer
construction into a hard compile error under -std=c++23.

Use std::vector<U> output(size) instead, which value-initializes each
element (0 for arithmetic types, "" for std::string) without relying
on any implicit conversion from 0, and behaves identically to the old
code for every type this function is actually instantiated with.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EDpAzhpyYk2biu7ttb9EuQ
Farray's "copy constructor" took a non-const lvalue reference
(Farray<T,lims...>&) instead of a const reference. Through C++20, the
two-stage implicit-move rule for "return localVar;" first tries the
operand as an rvalue (fails here, since nothing can bind an rvalue to
a non-const lvalue ref) and then retries the same overload resolution
treating it as an lvalue, which succeeds by calling this constructor.

C++23's simpler implicit-move rules (P2266) fold this into a single
overload resolution pass instead of a separate lvalue retry, so a
constructor that can only bind non-const lvalues is no longer found
when returning a named local Farray by value, e.g.:

  Backends/src/frontends/Prospino_2_1.cpp:279:
    error: cannot bind non-const lvalue reference of type
    'Gambit::Farray<double, 0, 99>&' to an rvalue of type
    'Gambit::Farray<double, 0, 99>'

Since Farray is used throughout the backend frontends specifically for
returning Fortran-array-compatible values by value, this affects every
translation unit that returns an Farray by name, not just Prospino.

Fix: give Farray a proper const-reference copy constructor. This adds
no new members and doesn't change the class's memory layout (which
must exactly match Fortran array layout), just the constructor
signature, so it's a pure C++-semantics fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EDpAzhpyYk2biu7ttb9EuQ
ClosestPair2D declares "class Point;" as a forward declaration and
holds a std::vector<Point> _points member, with Point's full
definition only appearing later in the file, out-of-class. Its two
constructors were defined inline, in the class body. Per the
complete-class-context rule, inline member function bodies are
semantically analyzed immediately after the class's own closing brace
-- before Point's separate out-of-class definition -- so the implicit
default-construction of the incomplete-at-that-point _points member
(as part of the constructors' implicit member-initialization) is only
valid because GCC is lenient about exactly when it enforces this.

Clang enforces it strictly, and only starting with -std=c++20/c++23
(building with clang++ 18 against libstdc++ 13/14):

  fjcore.cc:729:3: note: in defaulted default constructor for
    'std::vector<gambit::fjcore::ClosestPair2D::Point>' first
    required here
  .../bits/stl_vector.h:370: error: arithmetic on a pointer to an
    incomplete type 'gambit::fjcore::ClosestPair2D::Point'

Fix: declare the two constructors in the class body without inline
bodies, and define them out-of-line after Point's definition, exactly
matching the pattern this same file already uses for _ID() and
size(). Verified clean with clang++ and g++ under -std=c++17/20/23.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EDpAzhpyYk2biu7ttb9EuQ
@ChrisJChang ChrisJChang self-assigned this Jul 7, 2026
@ChrisJChang ChrisJChang added the Core Core group task label Jul 7, 2026
@ahye

ahye commented Jul 7, 2026

Copy link
Copy Markdown
Member

The fjcore problem seems to be fixed in newer versions of fastjet, see version comment for fastjet 3.4.2 here:
https://www.fastjet.fr/all-releases.html

Maybe we should take the hit and update our fastjet/fjcore versions as well in this PR? (I am being very demanding now :P )

Same might be true for the yaml issue. Did we not discuss/ actually update this relatively recently, or have I just been dreaming?

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

Labels

Core Core group task

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants