Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,16 @@ regenerated (2026-09-11).
`-mllvm -basic-aa-separate-storage` to our targets (and to the ld64 link under LTO), and the gate classifies the
compiler by compiling the real slice three ways, with a `=false` negative control and a cross-check against the
cached CMake probe.
### Added — `VERIFY_NO_ALIAS` guards at 15 call sites where self-aliasing was a silent wrong answer or UB

`VERIFY_NO_ALIAS` / `VERIFY_NO_ALIAS3` at the top of 15 functions whose two-or-more same-element-type
out-parameters would silently mis-compute or invalidate an iterator if a caller ever passed the same
object twice. The check runs in debug builds; in release the macro leaves only the
`__builtin_assume_separate_storage` promise on the two objects, which the optimizer reads on clang 18+
by default, on LLVM 17 / AppleClang 16 only with the CMake-added `-mllvm -basic-aa-separate-storage`
and there for scalar accesses, and not at all on GCC or clang before 17. For these 15 functions the
promise measured no codegen change (the object form says nothing about a container's heap buffer), so
there is no performance claim here: these are correctness contracts.

## [0.6.0] — 2026-09-11

Expand Down
1 change: 1 addition & 0 deletions src/columnar.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ inline constexpr const char* kColumnarLegend =
inline void buildPathTable( const std::vector<std::uint32_t>& rowFileIds,
std::vector<std::uint32_t>& outUniqueFiles, std::vector<std::uint32_t>& outRowPathIdx )
{
VERIFY_NO_ALIAS3( rowFileIds, outUniqueFiles, outRowPathIdx );
outUniqueFiles.clear();
outRowPathIdx.clear();
outRowPathIdx.reserve( rowFileIds.size() );
Expand Down
1 change: 1 addition & 0 deletions src/commentcoherence.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ inline bool isCommentStopword( std::string_view w ) noexcept
// splitIdentifier(...) lowercased, one call site — the ONE tokenizer this whole lens uses (header note).
inline void lowerSplitInto( std::string_view text, std::vector<std::string>& scratch, std::vector<std::string>& out )
{
VERIFY_NO_ALIAS( scratch, out );
naminglens::splitIdentifier( text, scratch );
out.reserve( out.size() + scratch.size() );
for( const std::string& tok : scratch )
Expand Down
1 change: 1 addition & 0 deletions src/contextratio.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ inline Facts collectFacts( const IngestResult& ing, const NameDefs& byName,
{
// name interning, so a "distinct NAME" fact is a u32 and the ext=/amb= folds are the same sort as the
// entity fold. Same rule as byName: lookup only, never iterated.
VERIFY_NO_ALIAS( symRows, fileRows );
HashMap<std::string_view, std::uint32_t> nameIndex;
nameIndex.reserve( byName.size() );

Expand Down
1 change: 1 addition & 0 deletions src/editpreview.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ inline Outcome refuse( std::string message )
// kBinaryPayloadRefusal makes is exactly the condition that would drop the file from the index.
inline bool readPayload( std::string_view spec, std::size_t maxFileBytes, std::string& out, std::string& err )
{
VERIFY_NO_ALIAS( out, err );
out.clear();
if( spec == "-" )
{
Expand Down
1 change: 1 addition & 0 deletions src/gitoracle.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ inline void putStr( std::string& b, const std::string& s )
{
// Every field written here is a git-controlled identifier / sha / date / path, all far inside 64 KiB; a
// pathological one is CLAMPED rather than allowed to wrap the length field (G1 runs -fsanitize=integer).
VERIFY_NO_ALIAS( b, s );
const std::uint16_t n = std::uint16_t( std::min<std::size_t>( s.size(), 0xffffu ) );
qsnapPut( b, n );
b.append( s.data(), n );
Expand Down
1 change: 1 addition & 0 deletions src/ingest_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -2157,6 +2157,7 @@ inline std::vector<CacheWriteRow> buildCacheWritePlan( const std::vector<std::ui
const std::vector<CacheEntry>& prevEntries,
std::vector<CacheEntry>& carryOut )
{
VERIFY_NO_ALIAS( prevEntries, carryOut );
carryOut.clear();
carryOut.reserve( prevEntries.size() );
{
Expand Down
1 change: 1 addition & 0 deletions src/ingest_parsepool.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ inline WarmHitTotals markCacheHits( const std::vector<std::string>& files, const
HashMap<std::string, FileFacts>& cache,
std::vector<FileFacts*>& candidates, std::vector<FileFacts*>& hits )
{
VERIFY_NO_ALIAS( candidates, hits );
WarmHitTotals tot;
for( std::size_t fileId = 0; fileId < files.size(); ++fileId )
{
Expand Down
1 change: 1 addition & 0 deletions src/mcpindex.h
Original file line number Diff line number Diff line change
Expand Up @@ -1274,6 +1274,7 @@ inline const McpIndex& getIndex( const std::string& root )
// identity and there is nothing to strip.
inline void handleIdentity( const McpIndex& ix, NodeId id, std::string& canonOut, std::string& pathOut )
{
VERIFY_NO_ALIAS( canonOut, pathOut );
const Symbol& s = ix.ing.symbols[ id ];
const std::string_view rootArg = ix.ing.realPaths.empty() ? std::string_view( ix.root ) : std::string_view();
canonOut = ( id < ix.g.canonId.size() ) ? canonicalIdForEmit( ix.ing, s, rootArg ) : s.name;
Expand Down
3 changes: 3 additions & 0 deletions src/mention.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ inline std::string capDisclosureNote( const CapDisclosure& disc )
// Every one of the three is "" unless a cap actually bit, so a bundle that lost nothing still pays nothing.
inline void absorbCapDisclosure( const CapDisclosure& disc, std::string& note, std::string& xmlAttrs, std::string& jsonKeys )
{
VERIFY_NO_ALIAS3( note, xmlAttrs, jsonKeys );
note += capDisclosureNote( disc );
xmlAttrs += disc.xml;
jsonKeys += disc.json;
Expand Down Expand Up @@ -403,6 +404,7 @@ inline bool definesScopeName( const IngestResult& ing, const std::string& scope,
inline void mentionUnkeptFiles( const IngestResult& ing, const RawMention& m, const std::vector<std::uint32_t>& kept,
std::vector<std::uint32_t>& out )
{
VERIFY_NO_ALIAS( kept, out );
const std::size_t fileCount = ing.files.size();
for( std::size_t suffixLen = m.segments.size(); suffixLen >= 1; --suffixLen )
{
Expand Down Expand Up @@ -801,6 +803,7 @@ struct DocMentionBoostInfo
inline void collectRefusedDocLifts( const Graph& g, const std::vector<float>& lensRank, const std::vector<NodeId>& order,
std::size_t from, std::size_t to, std::vector<NodeId>& out )
{
VERIFY_NO_ALIAS( order, out );
for( std::size_t k = from; k < to; ++k )
{
const NodeId anchor = order[k];
Expand Down
1 change: 1 addition & 0 deletions src/packtask.h
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,7 @@ inline void partitionByEligibility( const std::vector<NodeId>& topRanked, const
const std::vector<char>& d1Mark,
std::vector<NodeId>& eligibleIds, std::vector<NodeId>& d2plusIds )
{
VERIFY_NO_ALIAS3( topRanked, eligibleIds, d2plusIds );
for( NodeId id : topRanked )
{
( ( id < d0Mark.size() && d0Mark[id] ) || ( id < d1Mark.size() && d1Mark[id] ) ? eligibleIds : d2plusIds ).push_back( id );
Expand Down
2 changes: 2 additions & 0 deletions src/search.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ inline bool matchesOnlyEmpty( const RegexInfo& r )
// (e.g. `(ab|cd)(ef|gh)` → abef, abgh, cdef, cdgh, whose trigrams the AND can then require).
inline bool crossProduct( const std::vector<std::string>& a, const std::vector<std::string>& b, std::vector<std::string>& out )
{
VERIFY_NO_ALIAS( a, out ); // inputs are only read: a self-product crossProduct( v, v, out ) is valid,
VERIFY_NO_ALIAS( b, out ); // so the contract is each input against the output, never a against b
if( a.size() * b.size() > kMaxExactSet )
{
return false;
Expand Down
1 change: 1 addition & 0 deletions src/testmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,7 @@ inline bool dependenciesMapCorpus( const IngestResult& ing, const std::vector<st
// The word list of every `for <var> in <members…>; do` in the token stream, one token of lookahead state.
inline void appendForListStems( const std::vector<std::string>& tokens, std::vector<std::string>& stems )
{
VERIFY_NO_ALIAS( tokens, stems );
enum class Loop : std::uint8_t { Scan, Var, ExpectIn, List };
Loop state = Loop::Scan;
for( const std::string& token : tokens )
Expand Down
1 change: 1 addition & 0 deletions src/verbs_navigate.h
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,7 @@ inline std::optional<int> sliceSincePrepare( const MainDispatch& d, std::string_
const ::TSLanguage* grammar, const rw::slicev::SliceScan& scan, const std::string& src,
std::string& legendOut, std::string& bodyOut, rw::slicev::SliceEmitOpts& emit )
{
VERIFY_NO_ALIAS( legendOut, bodyOut );
const rw::Config& cfg = d.cfg;
if( cfg.since.empty() )
{
Expand Down
4 changes: 3 additions & 1 deletion test/columnarcommacheck.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ command -v "$CXX" >/dev/null 2>&1 || CXX=g++
# (PR #1, run 30732976779). Rationale + the CMake mapping this mirrors: scripts/cxxstd.sh.
. "$ROOT/scripts/cxxstd.sh"
CXXSTD="$( ripwire_cxx_std_flag "$CXX" )"
"$CXX" "$CXXSTD" -I "$ROOT/src" -I "$ROOT/src/infra" -I "$ROOT/third_party" "$SRC" -o "$TMP/t" 2>"$TMP/build.err"
# diagnostics.cpp supplies Diagnostics::ConsoleLog::handleAssert — link it exactly as every other
# standalone harness in test/ does, now that buildPathTable carries a VERIFY_NO_ALIAS3 guard.
"$CXX" "$CXXSTD" -I "$ROOT/src" -I "$ROOT/src/infra" -I "$ROOT/third_party" "$SRC" "$ROOT/src/infra/diagnostics.cpp" -o "$TMP/t" 2>"$TMP/build.err"
if [ -x "$TMP/t" ]; then
ok "standalone gate binary built"
else
Expand Down
Loading