Skip to content

Expression refactor - #58

Merged
ipapadop merged 4 commits into
mainfrom
expression-refactor
Sep 8, 2026
Merged

ipapadop merged 4 commits into
mainfrom
expression-refactor

Conversation

@ipapadop

@ipapadop ipapadop commented Sep 8, 2026

Copy link
Copy Markdown
Owner

No description provided.

ipapadop and others added 2 commits September 7, 2026 17:43
Build if_, switch_ and while_ by chaining one piece at a time:

  if_(c1).then_(a).else_if_(c2).then_(b).else_(d)
  switch_(v).case_(10).then_(a).default_(d)
  while_(c).do_(body)

Each construct alternates between a pending builder -- which has no
operator(), is not Deferred, and is [[nodiscard]] -- and a complete
expression. The two-argument entry points, the variadic switch_, append()
and the free case_()/default_() factories are replaced by the chain;
else_if is renamed else_if_ for a uniform trailing underscore.

The switch no longer stores its default at case index 0. It lives in its
own member behind a no_default tag, mirroring no_else, so a case may be
added to a switch that already has a default: it is checked after the
cases already present and before the default, preserving what append()
did. A switch without default_ is now a usable expression yielding a
std::optional, like an if_ without else_.

Also fixes three pre-existing defects in result-type deduction, which
used the raw operator() return type instead of what evaluate() yields:

  - a branch or case body returning a deferred expression produced
    variant<expression_<...>, T> instead of T;
  - lvalue constant branches deduced T const& bound to a temporary,
    which segfaulted under AddressSanitizer;
  - lvalue variable branches failed to compile at all.

detail::evaluated_result_t is the single spelling of "what evaluating
this yields"; the deducers now use it. An all-void switch is no longer
reported as potentially throwing, and while_builder's forwarding
constructor no longer hijacks its own copy constructor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CftmcRq9o1fztk1puisTNN
@ipapadop ipapadop self-assigned this Sep 8, 2026
@ipapadop

ipapadop commented Sep 8, 2026 •

Copy link
Copy Markdown
Owner Author

Closes #50, #51

std::optional's converting constructor has no noexcept specification in the
standard; libstdc++ adds one and libc++ does not. Evaluating a non-finalized
conditional goes through both the no-match path (optional from nullopt_t,
always noexcept) and the matched-branch path (optional from int), so equating
noexcept(ex()) with no_match_is_nothrow_v alone held only on libstdc++ and
MSVC, and failed the macOS build.

Assert against both halves, matching the caveat already documented for the
same reason in test/unit/conditional.cpp.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CftmcRq9o1fztk1puisTNN

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 371e87712b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread include/deferred/conditional.hpp Outdated
conditional_builder::then_'s const& overload materializes Condition(m_condition)
-- a copy -- before calling append_conditional, but its specification only tested
construction from Condition&&, a move. A condition whose copy throws and whose
move does not was reported as noexcept, so a throwing copy would terminate
instead of propagating.

Include construction from Condition const& in the specification. This is the
only overload that copies a member into an argument rather than passing it
through; the rest already spell their const& types, and all fourteen builder
overloads were re-measured against a throwing-copy, nothrow-move type.

Reported by chatgpt-codex-connector on #58.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CftmcRq9o1fztk1puisTNN
@ipapadop
ipapadop merged commit 988f6de into main Sep 8, 2026
6 checks passed
@ipapadop
ipapadop deleted the expression-refactor branch September 8, 2026 03:08
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.

1 participant