Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix gcc7.5 compile error #1379

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

fix gcc7.5 compile error #1379

wants to merge 2 commits into from

Conversation

tpoisonooo
Copy link

Context

I tried to compile google/uVkCompute with GCC7.5, got some error:

...
uVkCompute/third_party/benchmark/include/benchmark/benchmark.h:1204:41: error: field 
‘benchmark::RegisterBenchmark(const char*, Lambda&&, Args&& ...) [with Lambda = void (&)(benchmark::State&, 
uvkc::vulkan::Device*, uvkc::benchmark::LatencyMeasureMode, const double*, const unsigned int*, long unsigned int, 
long unsigned int, int, double*); Args = {uvkc::vulkan::Device*&, uvkc::benchmark::LatencyMeasureMode&, const 
double*&, const unsigned int* const&, long unsigned int, long unsigned int&, long unsigned int, double*&}]::
<lambda(benchmark::State&)>::<fn capture>’ invalidly declared function type

...

The key problem is construct lambda in gcc7.5, please build this snippet and have a try:

#include <iostream>

template <class Lambda>
void RegisterBenchmark(Lambda&& fn) {
  fprintf(stdout, "first version\n");
}

template <class Lambda, class... Args>
void RegisterBenchmark(Lambda&& fn, Args&&... args) {

  // no auto decay in g++7.5, crash !!!
  auto fff = [=](){ fn(args...); };

  fff = [=, gn=std::forward<Lambda>(fn)](){ gn(args...); };
  fff = [=, gn=std::decay_t<Lambda>(fn)](){ gn(args...); };
  RegisterBenchmark(std::move(fff)); 
}


int func(int a) {
  fprintf(stdout, "%d\n", a);
}

int main() {
RegisterBenchmark(func, 12);
return 0;
}

auto fff = [=](){ fn(args...); }; is fine in clang/gcc11, but does not work in gcc7.5.

please check

@LebedevRI
Copy link
Collaborator

Can you point me at the test within this repo that fails when you build the benchmark itself with GCC7.5?
If none, please add one.

@tpoisonooo
Copy link
Author

Can you point me at the test within this repo that fails when you build the benchmark itself with GCC7.5? If none, please add one.

I have build google/benchmark with commit-id 0d98dba (uVKCompute use it) and 60b16f1 (the newest one), no error happens.

@tpoisonooo
Copy link
Author

+_+

@LebedevRI
Copy link
Collaborator

Can you point me at the test within this repo that fails when you build the benchmark itself with GCC7.5? If none, please add one.

I have build google/benchmark with commit-id 0d98dba (uVKCompute use it) and 60b16f1 (the newest one), no error happens.

Then please add a test that fails without this fix :)

@tpoisonooo tpoisonooo changed the title fix gcc7.5 compile error Draft: fix gcc7.5 compile error Apr 3, 2022
@tpoisonooo
Copy link
Author

tpoisonooo commented Apr 6, 2022

Can you point me at the test within this repo that fails when you build the benchmark itself with GCC7.5? If none, please add one.

I have build google/benchmark with commit-id 0d98dba (uVKCompute use it) and 60b16f1 (the newest one), no error happens.

Then please add a test that fails without this fix :)

Thanks for your guidance, testcase added, RegisterBenchmark a static function with GCC7.5 can reproduce it.

It seems that lambda is not compatible with compiler, use std::bind could fix it, no need BENCHMARK_HAS_CXX14.

According to absl-cpp avoid std::bind, google dev prefer absl::bind ? I am not sure, if absl::bind is a must, pls let me know.

@tpoisonooo tpoisonooo changed the title Draft: fix gcc7.5 compile error fix gcc7.5 compile error Apr 6, 2022
@LebedevRI
Copy link
Collaborator

Can you point me at the test within this repo that fails when you build the benchmark itself with GCC7.5? If none, please add one.

I have build google/benchmark with commit-id 0d98dba (uVKCompute use it) and 60b16f1 (the newest one), no error happens.

Then please add a test that fails without this fix :)

Thanks for your guidance, testcase added, RegisterBenchmark a static function with GCC7.5 can reproduce it.

It seems that lambda is not compatible with compiler, use std::bind could fix it, no need BENCHMARK_HAS_CXX14.

According to absl-cpp avoid std::bind, google dev prefer absl::bind ? I am not sure, if absl::bind is must, pls let me know.

I'm not sure why what is the problem with just defining the macro?

@tpoisonooo
Copy link
Author

Ah...which "macro" ? no macro now.

I have added static void StaticFunction(::benchmark::State& state, int) {} to reproduce the problem and use std::bind to fix it, please check the code.

@LebedevRI
Copy link
Collaborator

I believe the previous fix is much less controversial.

@tpoisonooo
Copy link
Author

I believe the previous fix is much less controversial.

Ah I got it ... I have tried to add BENCHMARK_HAS_CXX14 in benchmark.h

#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
#define BENCHMARK_HAS_CXX14
#endif
...
#if BENCHMARCK_HAS_CXX14
...
#elif BENCHMARCK_HAS_CXX11
...
#endif

But the default compile option is std=c++11, so RegisterBenchmark a static function still failed.

$ cd benchmark/build
$ make VERBOSE=1
....  -std=c++11 ....

That means GCC7.5 -std=c++11 could not use lamda, use #if BENCHMARK_HAS_CXX14 or not does not make any sense...

@LebedevRI
Copy link
Collaborator

LebedevRI commented Apr 7, 2022

Err, i'm being stupid again.
Of course, the check shouldn't be for the C++17, it should be for GCC version :/
So roughly i think it should be

#if defined(BENCHMARK_GCC_VERSION) && BENCHMARK_GCC_VERSION < 800
<the code with explicit move>
#else
<original code>
#endif

@tpoisonooo
Copy link
Author

for clang/gcc11, it's fine;
for c++14/c++17, explicit move is fine;

for c++11, lamda not support capture initializer, for example this code not work:

int value1=1;
auto x = [=, value2=value1](){...}

@tpoisonooo
Copy link
Author

That is why I use std::bind.

@tpoisonooo
Copy link
Author

Err... is this PR acceptable ? @LebedevRI

@dmah42
Copy link
Member

dmah42 commented Feb 6, 2023

ping for @LebedevRI to comment :)

@LebedevRI
Copy link
Collaborator

I think there may be a translation issue here.

This sounds like a GCC7 bug, so the fix should not affect anything else.
Roughly, if you change the diff to the following, i'd stamp:

template <class Lambda, class... Args>
internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn,
                                       Args&&... args) {
+#if !defined(__GNUC__) || (defined(BENCHMARK_GCC_VERSION) && BENCHMARK_GCC_VERSION >= 800) || __cplusplus >= 201402L
  return benchmark::RegisterBenchmark(
      name, [=](benchmark::State& st) { fn(st, args...); });

+#else
+  // Workaround GCC7.5 C++ bug, see https://github.com/google/benchmark/pull/1379.
+  auto func = std::bind(std::forward<Lambda>(fn), std::placeholders::_1,
+                        std::forward<Args>(args)...);
+  return benchmark::RegisterBenchmark(name,
+                                      [=](benchmark::State& st) { func(st); });
+#endif
}

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.

None yet

3 participants