Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
83723ea
fix: defer Catch2 test discovery to ctest time to unblock CodeQL build
steve-downey Sep 8, 2026
0e9a961
Merge pull request #10 from steve-downey/fix-codeql-test-discovery-asan
steve-downey Sep 8, 2026
85e6712
docs: annotate headers with specgen wording docblocks
steve-downey Sep 8, 2026
38d5532
docs: generate [expected] wording from the annotated headers
steve-downey Sep 8, 2026
2261cbd
fix: gather unexpected.hpp/bad_expected_access.hpp into expected.hpp'…
steve-downey Sep 10, 2026
b7ec3e1
fix: don't leave a trailing blank line in generate.sh's assembled exp…
steve-downey Sep 10, 2026
2b737a4
fix: emit the wording at the draft's own \rSec levels
steve-downey Sep 15, 2026
50115b0
fix: drop the specgen workarounds now that #113 and #114 are fixed
steve-downey Sep 17, 2026
e38a6f2
Build the wording with make, not a script
steve-downey Sep 18, 2026
8cad346
fix: include the wording depfile by name, not by glob
steve-downey Sep 18, 2026
cb94b27
fix: let specgen infer declaration conditions
steve-downey Sep 19, 2026
344c462
docs: regenerate wording with specgen's in-class item gate fix
steve-downey Sep 22, 2026
2328bc6
fix: document the missing T-constructibility constraint on the refere…
steve-downey Sep 22, 2026
483d3ef
fix: document the missing object-type mandate on unexpected<E&>'s ref…
steve-downey Sep 22, 2026
12fa333
fix: document the missing T-exclusions on expected<T&,E>'s class Mand…
steve-downey Sep 22, 2026
7ffc6ee
fix: correct the wrong participation predicate on expected<T&,E>'s re…
steve-downey Sep 22, 2026
a162476
docs: explain expected<T&,E>'s reference-error converting copy constr…
steve-downey Sep 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,9 @@
/.emacs.d/elpa/
/.emacs.d/custom.el
*.deps

# specgen writes one *.root.tex per document, holding the exposition-only
# helpers that sit outside every clause. The draft states those inline in the
# clause that uses them, so they are not part of this paper's wording and are
# not committed -- see papers/wording/README.md.
papers/wording/fragments/*.root.tex
80 changes: 79 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,87 @@ env:
$(foreach v, $(.VARIABLES), $(info $(v) = $($(v))))

.PHONY: papers
papers:
papers: wording
$(MAKE) -C papers papers

# ---- Generated [expected] wording ------------------------------------------
#
# The three annotated headers are one specgen document each and one paper: a
# single invocation renders them together, so --validate sees the paper-wide
# union of documented names and a name specified by a sibling header is not
# foreign.
#
# specgen writes the fragments; this makefile assembles expected.tex from them,
# because the paper's clause order is not the headers' declaration order and
# cannot be. bad_expected_access<void> is the base class of
# bad_expected_access<E>, so the header has to define it first, while the draft
# states the primary template first. $(WORDING_CLAUSES) is where that one
# divergence is written down.

SPECGEN ?= specgen

WORDING_HEADERS := $(addprefix include/beman/expected/, \
unexpected.hpp bad_expected_access.hpp expected.hpp)

# In the draft's clause order, by stable name. These are the fragments that
# become expected.tex; specgen also writes one *.root.tex per document, holding
# the exposition-only helpers that sit outside every clause. The draft states
# those inline in the clause that uses them -- reinit-expected inside
# [expected.object.assign]'s own intro -- so they are deliberately not part of
# the assembled wording.
WORDING_CLAUSES := \
expected.unexpected \
expected.bad \
expected.bad.void \
expected.expected \
expected.void \
expected.ref

WORDING_DIR := papers/wording
WORDING_FRAGMENTS := \
$(addprefix $(WORDING_DIR)/fragments/,$(addsuffix .tex,$(WORDING_CLAUSES)))

SPECGEN_CLANG_ARGS := -std=c++2c -Iinclude
ifneq ($(SPECGEN_GCC_TOOLCHAIN),)
SPECGEN_CLANG_ARGS += --gcc-toolchain=$(SPECGEN_GCC_TOOLCHAIN)
endif

# A grouped target (GNU Make 4.3+): one invocation writes all of these, and
# make must not run it once per fragment.
$(WORDING_FRAGMENTS) &: $(WORDING_HEADERS)
@mkdir -p papers/.deps
$(SPECGEN) generate $(WORDING_HEADERS) \
--backend latex --validate --base-section-depth 2 \
--split $(WORDING_DIR)/fragments \
--root expected.unexpected.root \
--root expected.bad.root \
--root expected.root \
--depfile papers/.deps/wording.d \
$(addprefix --dep-target ,$(WORDING_FRAGMENTS)) \
--no-compile-commands -- $(SPECGEN_CLANG_ARGS)

# Assembled into a temporary first: a half-written expected.tex that make
# believes is finished is worse than no expected.tex at all.
$(WORDING_DIR)/expected.tex: $(WORDING_DIR)/preamble.tex $(WORDING_FRAGMENTS)
@cat $(WORDING_DIR)/preamble.tex > $@.tmp
@for clause in $(WORDING_CLAUSES); do \
printf '\n' >> $@.tmp; \
cat $(WORDING_DIR)/fragments/$$clause.tex >> $@.tmp; \
done
@mv $@.tmp $@
@echo "Wrote $@"

.PHONY: wording
wording: $(WORDING_DIR)/expected.tex ## Regenerate papers/wording/ from the annotated headers via specgen

# What specgen read to produce the fragments -- including headers reached only
# through an #include, which is the edge a hand-written prerequisite list
# forgets. Written by --depfile above; absent until the first run, hence
# $(wildcard): a bare glob that matches nothing stays a literal target name,
# and .DEFAULT below would hand it to cmake. Named, not globbed: papers/.deps/
# is also latexmk's -deps-out directory, and its paths are relative to papers/.
-include $(wildcard papers/.deps/wording.d)

.DEFAULT: $(_build_path)/CMakeCache.txt ## Other targets passed through to cmake
$(CMAKE) --build $(_build_path) --config $(CONFIG) --target $@ -- -k 0

Expand Down
16 changes: 16 additions & 0 deletions include/beman/expected/bad_expected_access.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ namespace expected {
template <class E>
class bad_expected_access;

// \rSec2[expected.bad.void]{Class template specialization bad_expected_access<void>}
template <>
class bad_expected_access<void> : public std::exception {
protected:
Expand All @@ -74,6 +75,11 @@ class bad_expected_access<void> : public std::exception {
BEMAN_EXPECTED_CONSTEXPR_EXCEPTION const char* what() const noexcept override;
};

// \rSec2[expected.bad]{Class template bad_expected_access}
//! \remarks The class template `bad_expected_access` defines the type of
//! objects thrown as exceptions to report the situation where an attempt is
//! made to access the value of an `expected<T, E>` object for which
//! `has_value()` is `false`.
template <class E>
class bad_expected_access : public bad_expected_access<void> {
public:
Expand All @@ -85,40 +91,50 @@ class bad_expected_access : public bad_expected_access<void> {
constexpr const E&& error() const&& noexcept;

private:
//! \expos
E unex;
};

// bad_expected_access<void> out-of-line definitions

//! \returns An implementation-defined ntbs, which during constant evaluation
//! is encoded with the ordinary literal encoding (\iref{lex.ccon}).
inline BEMAN_EXPECTED_CONSTEXPR_EXCEPTION const char* bad_expected_access<void>::what() const noexcept {
return "bad expected access";
}

// bad_expected_access<E> out-of-line definitions

//! \effects Initializes `unex` with `std::move(e)`.
template <class E>
BEMAN_EXPECTED_CONSTEXPR_EXCEPTION bad_expected_access<E>::bad_expected_access(E e) : unex(std::move(e)) {}

//! \returns An implementation-defined ntbs, which during constant evaluation
//! is encoded with the ordinary literal encoding (\iref{lex.ccon}).
template <class E>
BEMAN_EXPECTED_CONSTEXPR_EXCEPTION const char* bad_expected_access<E>::what() const noexcept {
return "bad expected access";
}

//! \returns `unex`.
template <class E>
constexpr E& bad_expected_access<E>::error() & noexcept {
return unex;
}

//! \returns `unex`.
template <class E>
constexpr const E& bad_expected_access<E>::error() const& noexcept {
return unex;
}

//! \returns `std::move(unex)`.
template <class E>
constexpr E&& bad_expected_access<E>::error() && noexcept {
return std::move(unex);
}

//! \returns `std::move(unex)`.
template <class E>
constexpr const E&& bad_expected_access<E>::error() const&& noexcept {
return std::move(unex);
Expand Down
Loading
Loading