[Bug]: Compilation regression in version update: "...incomplete type 'absl::container_internal::HashEq..."
- Dominant language
- C++
- Stars
- 18.1k
- Forks
- 3.2k
- Avg merge
- 20h 36m
- Merged PRs (30d)
- 1
Description
### Describe the issue
I updated from 20240116.2 to 20240722.0 and had a compilation regression of previous code. There was some nontrivial template meta-programming involved, but the part that failed for me was around returning an absl::flat_hash_set from a method in a templated type Foo.
[This commit](https://github.com/monkeynova/project-euler/commit/325966dc6a698383b9e9387aa9986255c06f034d) documents my upgrade and the change I had to make, though it's a private repository, so I'm not sure how best to share that with you.
I stripped the problem down to a bare reproduction step that can exist as a super-simple bazel repository which I've included in reproduction steps. Bringing the version back in MODULES.bazel allows compilation. As does setting the #define I've included in the code which documents my current workaround for this regression.
The error messages I see are as follows
```
INFO: Analyzed target //:im_replicate_test (0 packages loaded, 0 targets configured).
ERROR: /Users/keith/github/im_replicate/BUILD:1:8: Compiling im_replicate_test.cc failed: (Exit 1): cc_wrapper.sh failed: error executing CppCompile command (from target //:im_replicate_test) external/bazel_tools~cc_configure_extension~local_config_cc/cc_wrapper.sh -U_FORTIFY_SOURCE -fstack-protector -Wall -Wthread-safety -Wself-assign -Wunused-but-set-parameter -Wno-free-nonheap-object ... (remaining 50 arguments skipped)
Use --sandbox_debug to see verbose messages from the sandbox and retain the sandbox build root for debugging
In file included from im_replicate_test.cc:3:
In file included from external/abseil-cpp~/absl/container/flat_hash_map.h:43:
In file included from external/abseil-cpp~/absl/container/hash_container_defaults.h:19:
external/abseil-cpp~/absl/container/internal/hash_function_defaults.h:263:1: error: incomplete type 'absl::container_internal::HashEq>>' named in nested name specifier
using hash_default_hash = typename container_internal::HashEq::Hash;
^~~~~
external/abseil-cpp~/absl/container/hash_container_defaults.h:31:1: note: in instantiation of template type alias 'hash_default_hash' requested here
using DefaultHashContainerHash = absl::container_internal::hash_default_hash;
^
external/abseil-cpp~/absl/container/flat_hash_set.h:122:33: note: in instantiation of template type alias 'DefaultHashContainerHash' requested here
template ,
^
im_replicate_test.cc:48:9: note: in instantiation of default argument for 'flat_hash_set>>' required here
absl::flat_hash_set Sqrt() const {
^~~~~~~~~~~~~~~~~~~~~~~~~
external/abseil-cpp~/absl/container/internal/hash_function_defaults.h:197:54: note: in instantiation of template class 'IntegerMod>' requested here
struct HasAbslContainerHash>
^
external/abseil-cpp~/absl/container/internal/hash_function_defaults.h:247:44: note: during template argument deduction for class template partial specialization 'HasAbslContainerHash>' [with T = IntegerMod>]
struct HashEq::value>> {
^
external/abseil-cpp~/absl/container/internal/hash_function_defaults.h:247:44: note: (skipping 1 context in backtrace; use -ftemplate-backtrace-limit=0 to see all)
external/abseil-cpp~/absl/container/internal/hash_function_defaults.h:263:1: note: during template argument deduction for class template partial specialization 'HashEq::value>>' [with T = IntegerMod>]
using hash_default_hash = typename container_internal::HashEq::Hash;
^
external/abseil-cpp~/absl/container/internal/hash_function_defaults.h:263:1: note: in instantiation of template class 'absl::container_internal::HashEq>>' requested here
external/abseil-cpp~/absl/container/hash_container_defaults.h:31:1: note: in instantiation of template type alias 'hash_default_hash' requested here
using DefaultHashContainerHash = absl::container_internal::hash_default_hash;
^
external/abseil-cpp~/absl/container/flat_hash_set.h:122:33: note: in instantiation of template type alias 'DefaultHashContainerHash' requested here
template ,
^
im_replicate_test.cc:82:9: note: in instantiation of default argument for 'flat_hash_set>>' required here
absl::flat_hash_set set;
^~~~~~~~~~~~~~~~~~~~~~
external/abseil-cpp~/absl/container/internal/hash_function_defaults.h:71:8: note: forward declaration of 'absl::container_internal::HashEq>>'
struct HashEq {
^
1 error generated.
Target //:im_replicate_test failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 1.509s, Critical Path: 1.39s
INFO: 2 processes: 2 internal.
ERROR: Build did NOT complete successfully
//:im_replicate_test FAILED TO BUILD
Executed 0 out of 1 test: 1 fails to build.
```
### Steps to reproduce the problem
```bazel test ... ```
With the following repository
## MODULES.bazel
```
# works with 20240116.2
bazel_dep(name = "abseil-cpp", version = "20240722.0", repo_name = "com_google_absl")
bazel_dep(name = "googletest", version = "1.15.2", repo_name = "com_google_googletest")
```
## BUILD
```
cc_test(
name = "im_replicate_test",
srcs = ["im_replicate_test.cc"],
deps = [
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/flags:parse",
"@com_google_absl//absl/flags:usage",
"@com_google_absl//absl/log:check",
"@com_google_absl//absl/log:initialize",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest",
],
)
```
## im_replicate_test.cc
```
#include
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/flags/parse.h"
#include "absl/flags/usage.h"
#include "absl/log/check.h"
#include "absl/log/initialize.h"
#include "absl/strings/str_join.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
template
struct StaticModTraits {
bool operator==(const StaticModTraits&) const = default;
constexpr Storage mod() const { return kMod; }
};
template
struct DynamicModTraits {
DynamicModTraits(Storage mod) : mod_(mod) {}
bool operator==(const DynamicModTraits&) const = default;
Storage mod() const { return mod_; }
private:
Storage mod_;
};
template >
class IntegerMod {
public:
IntegerMod() = default;
template
constexpr IntegerMod(const Storage& v, TraitArgs... trait_args)
: traits_(trait_args...), v_(v % traits_.mod()) {}
bool operator==(const IntegerMod& o) const = default;
#ifdef WORKING_VERSION
// This version allows compilation.
template
absl::flat_hash_set Sqrt() const {
return {};
}
#else
absl::flat_hash_set Sqrt() const {
return {};
}
#endif
template
friend H AbslHashValue(H h, const IntegerMod& m) {
return H::combine(std::move(h), m.v_);
}
template
friend void AbslStringify(Sink& sink, const IntegerMod& m) {
absl::Format(&sink, "(%v MOD %v)", m.v_, m.mod());
}
friend std::ostream& operator<<(std::ostream& out, const IntegerMod& m) {
return out << absl::StreamFormat("%v", m);
}
private:
Traits traits_;
Storage v_ = 0;
};
template
using StaticIntegerMod =
IntegerMod>;
TEST(IntegerMod, Hash_Static) {
// absl::flat_hash_set> encountered template
// instantiation problems (see comment on IntegerMod::Sqrt). This is here
// to ensure that we hit those problems in euler/... and to help replicate
// in a controlled environment.
using ModType = StaticIntegerMod;
absl::flat_hash_set set;
set.insert(ModType{5});
set.insert(ModType{7});
EXPECT_EQ(set.size(), 2);
set.insert(ModType{42});
EXPECT_EQ(set.size(), 2);
}
std::vector InitMain(int argc, char** argv, const std::string& usage) {
absl::SetProgramUsageMessage(usage);
absl::InitializeLog();
return absl::ParseCommandLine(argc, argv);
}
int main(int argc, char** argv) {
std::vector args = InitMain(
argc, argv,
absl::StrCat("This program runs the collection of gunit tests (default) "
"or benchmarks linked in (if the --benchmark flag is set). "
"No arguments are accepted. Usage:\n", argv[0],
" [--benchmark]"));
CHECK_EQ(args.size(), 1) << absl::StrJoin(args, ",");
return RUN_ALL_TESTS();
}
```
### What version of Abseil are you using?
20240116.2 (works) 20240722.0 (doesn't)
### What operating system and version are you using?
macos 14.6.1
### What compiler and version are you using?
default with the os. I think that's clang.
clang -v
```
Apple clang version 15.0.0 (clang-1500.3.9.4)
Target: arm64-apple-darwin23.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
```
### What build system are you using?
bazel --version -> bazel 7.3.0 (via alas bazelisk=bazel)
### Additional context
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.