Repository navigation
fix(cpp): a call on what a container's front()/back()/at() or a holder's get()/value() returns, like rocksdb's edits.back()->MarkAtomicGroup(…), calls the element's method - #2616
Merged
Conversation
… holder's `get()`/`value()` returns, like rocksdb's `edits.back()->MarkAtomicGroup(…)`, calls the element's method A call on what a library container hands out linked to nothing: the standard library's `front()` returns nothing the index can read, and the library-receiver gate keeps the name strategies off a `std::vector`. cppLibraryElementOf reads what such a member returns, where the container's type is written: - `front()`, `back()` and `at(i)` of a sequence (std/absl, and the project sequences cppRangeElementOf already treats as such) → its element; - a library map's `at(key)` → the mapped value; - `std::stack`/`std::priority_queue` `top()`, `std::queue` `front()`/`back()` → the element; - `get()` of `std::unique_ptr`/`std::shared_ptr`/`absl::NoDestructor` → a pointer to the held type, `value()`/`value_or()` of an optional or an `absl::StatusOr` → the held type. It is asked in cppChainInnerType (a chain `recv.front().m()`) and in cppExpressionType (an `auto` local, a range, an argument), next to cppLibraryIteratorOf. A/B on the cgstd kit against main 98127e5: leveldb, fmt and redis identical; rocksdb 299 calls added, 89 retargeted (overloads picked by a typed `.get()` argument, like `test::PerThreadDBPath(env_.get(), …)`, and inherited methods on a typed element), 10 removed (guesses on what turned out to be library containers) and 56 confidence-only; protobuf 7 added and 16 retargeted (cast helpers off their `std::shared_ptr` overloads, `Add` off a deleted one). Every site was joined with the element type an instrumented arm logged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This is the follow-up both #2601 and #2602 left open: calls on what a library container or holder hands out.
The bug. A call made through one of these accessors linked to nothing:
bufs.front().Flush()over astd::vector<Buffer>;wals.at(n).HasSyncedSize()over astd::map;pending.top()->Valid()on astd::stack;mock_clock.get()->GetCurrentTime()on astd::shared_ptr;scan_opts_.value().GetScanRanges()on astd::optional.The library's member returns nothing the index can read, and the library-receiver gate (#2413) rightly keeps the name strategies off a
std::vector.The fix.
cppLibraryElementOfreads what such a member returns, where the container's type is written:front(),back(),at(i)cppRangeElementOfalready treats as such (RepeatedPtrField, rocksdb'sautovector)at(key)top()std::stack,std::priority_queuefront(),back()std::queueget()std::unique_ptr,std::shared_ptr,absl::NoDestructorvalue(),value_or()absl::StatusOrIt is asked in two places:
cppChainInnerType, for a chain likerecv.front().m();cppExpressionType, for anautolocal, a range or an argument, next tocppLibraryIteratorOf.A typed argument also feeds overload choice, so a call given such a value now takes the overload for its type.
A/B on the C/C++ kit (main
98127e54vs this branch)Triage method. An instrumented copy of the fix arm logged every element type
cppLibraryElementOfderived. Each changed site was joined with those logs, by file and nearby line, and checked against the target's class or one of its ancestors (extendsedges).typedef std::shared_ptr<PersistentCacheTier> Tier,using InternalIterator = InternalIteratorBase<Slice>,using UserDefinedIndexIterator = IndexFactoryIterator;range.limit.value()→OptSlice::value;.get()through a member chain, liketbo.moptions.compression_manager.get();.get()argument.test::PerThreadDBPath(mock_env_.get(), …)moves from(std::string dir, std::string name)to(Env* env, std::string name), andCreateNewBackup(db_.get()),WriteStringToFile,ReadFileToString,CopyFile,CreateFileandLogFlushlikewise.tracked_files.size()on thestd::unordered_mapfromget()->GetTrackedFiles(), which went toCompactionInputFiles::size;scan_ranges.size()on astd::vector, which went toMultiScanArgs::size;str.c_str(), which went to gtest'sFilePath::c_str.index->SetPrimaryColumnFamilyover astd::vector<std::shared_ptr<SecondaryIndex>>.children_.back()->InsertImpl,message_generators_.back()->AddGenerators,ordered_fields_.back()->number(),subs_.at(i).value(), and others.hpb::Parse(model.get(), bytes.value())reaches the(PtrOrRaw<T>, string_view)overload;field.Add("")leaves a= deleted overload;DynamicCastMessage/DownCastMessagecalls onptr.get()leave theirstd::shared_ptroverloads for the pointer ones.Known limit. About 6 of those cast calls pass a non-const pointer and land on the
const MessageLite*overload, where C++ picks theMessageLite*one. Overload fit ties const and non-const pointers and breaks the tie by declaration order. That is pre-existing overload logic, filed as a follow-up.Tests
__tests__/cpp-container-accessor-calls.test.ts(5 tests). The accessor members each have a case, plus anautolocal and a project sequence. On98127e54the four behavior tests fail (checked on a detached checkout). The guard test passes on both: a project class named like a container, astd::stringelement and a template's ownT.cppRangeElementOf'sproject-namesake guard covers thelibrary &&check on sequences, and the pointer guard is the other.mcp-daemon.test.tsdaemon-reaper test timed out at 20 s under load; the file passes 21/21 when rerun on its own.🤖 Generated with Claude Code