Why am I unable to declare a string type variable in GCC 13.x version with #pragma GCC target(...)
Asked Answered
I

2

6

I just updated my GCC compiler version to 13.1 from 11.4. And I found the following code which used to work on my old GCC 11.4 no longer works on GCC 13.1.

#pragma GCC optimize("Ofast,unroll-loops")
#pragma GCC target("avx2,popcnt,lzcnt,abm,bmi,bmi2,fma,tune=native")

#include <iostream>

int main() {
    std::string s = "Hello World!";
    std::cout << s << std::endl;
}

Here is the compiler messages:

====================[ Build | run | Debug ]=====================================
"C:\Program Files\JetBrains\CLion 2023.3.2\bin\cmake\win\x64\bin\cmake.exe" --build C:\Users\zyk\CLionProjects\run\cmake-build-debug --target run -j 18
[1/2] Building CXX object CMakeFiles/run.dir/main.cpp.obj
FAILED: CMakeFiles/run.dir/main.cpp.obj 
C:\PROGRA~1\JETBRA~1\CLION2~1.2\bin\mingw\bin\G__~1.EXE   -g -fdiagnostics-color=always -MD -MT CMakeFiles/run.dir/main.cpp.obj -MF CMakeFiles\run.dir\main.cpp.obj.d -o CMakeFiles/run.dir/main.cpp.obj -c C:/Users/zyk/CLionProjects/run/main.cpp
In file included from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/string:43,
                 from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/bits/locale_classes.h:40,
                 from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/bits/ios_base.h:41,
                 from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/ios:44,
                 from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/ostream:40,
                 from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/iostream:41,
                 from C:/Users/zyk/CLionProjects/run/main.cpp:3:
C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/bits/allocator.h: In destructor 'std::__cxx11::basic_string<char>::_Alloc_hider::~_Alloc_hider()':
C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/bits/allocator.h:184:7: error: inlining failed in call to 'always_inline' 'std::allocator< <template-parameter-1-1> >::~allocator() noexcept [with _Tp = char]': target specific option mismatch
  184 |       ~allocator() _GLIBCXX_NOTHROW { }
      |       ^
In file included from C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/string:54:
C:/Program Files/JetBrains/CLion 2023.3.2/bin/mingw/lib/gcc/x86_64-w64-mingw32/13.1.0/include/c++/bits/basic_string.h:192:14: note: called from here
  192 |       struct _Alloc_hider : allocator_type // TODO check __is_final
      |              ^~~~~~~~~~~~
ninja: build stopped: subcommand failed.

By removing #pragma GCC target("avx2,popcnt,lzcnt,abm,bmi,bmi2,fma,tune=native") or even simply not declaring any string type variables I am able to get the code work again. But I sometimes need that line of code for some reasons.

Here is the link of my code on Compiler Explorer:https://godbolt.org/z/r4rxr6Efn

UPD: Updated with minimal working example without using namespace std; and bit/stdc++.h header file.

Installation answered 2/1 at 9:8 Comment(8)
Your code fails with both gcc 11.2 and 13.1: godbolt.org/z/8hKqhYKzG Please provide a minimal working example.Freyah
Adding std:: reproduces this: godbolt.org/z/n1eYG3fE4 You should add it to the code in the question.Seraglio
Here is the reproduction with the minimal working example on both GCC 11.4 and GCC 13.1: godbolt.org/z/r5bx7qdGn I remove the horrible using namespace std; code and horrible bits/stdc++.h header file and the problem still exists.Installation
@AdrianMole I've reopened this. The header has nothing to do with the problem. I don't think we should close questions like this unless we can demonstrate that removing the header fixes the issue.Seraglio
You're still missing #include <string> and std::.Seraglio
You can fix your problem by specifying a minimum architecture in the gcc compiler options va -march=native, see also lemire.me/blog/2018/07/25/…. Godbolt: godbolt.org/z/z9nh3W14EFreyah
@Seraglio Fair enough (after the edit). Still looks a bit weird, though. I think there's probably a dupe for 'other' headers being included by something like <iostream>.Everick
Thank you guys for answering my question. I am new to this community and I am a bit nervous at asking this question... Sorry for making so many edits.Installation
S
5

Updated with minimal working example without using namespace std; and bit/stdc++.h header file.

I assume you're from the competitive programming community so I will provide an answer purely optimized for sites like codeforces, atcoder, ...)

"Debunking" the top answer:

otherwise you attempt to put target pragmas on standard library functions and that's not supported.

This is not true, that is a bug regression on GCC 13 and has been reported on GCC bugzilla and later duplicated on codeforces. In short, there is an always_inline on constructor issue that prevents constructors like std::vector, std::set, std::string, etc from compiling with #pragma GCC target. While it worked perfectly fine for years with GCC version < 13

Never put it in front of an #include directive;

Quoting from a well-researched blog [Tutorial] GCC Optimization Pragmas: Do remember that for the sake of optimizing all parts of your program, all pragmas must be present at the beginning of the submission, even before the includes. So do not listen to the advice above if you want to squeeze a problem into time limit!

The solution

Fortunately, most online judges are still holding onto older GCC versions, e.g. codeforces (GCC 11.2.0) and atcoder (GCC 12.2) so you don't have to worry about compile errors after submitting these code.

That leaves us with 3 ways to deal with this error locally:

  • The most obvious solution is to install an older gcc version (sudo apt install gcc-12 or yay -S gcc12) and then use g++-12 instead of g++
  • Manually add -m{target} compile flags, e.g. If you write #pragma GCC target("avx2,bmi2") you should be able to compile with g++ sol.cpp -mavx2 -mbmi2
  • Most online judges has -DONLINE_JUDGE in their compile command (e.g. codeforces commands, atcoder commands) so let's use that to our advantage (Alternately, you can also use g++ sol.cpp -DLOCAL and change the first line to #ifndef LOCAL):
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
#endif
#include <bits/stdc++.h>
using namespace std;

int main() {
  cin.tie(0)->sync_with_stdio(0);
  string s = "Hello world!";
  cout << s << '\n';
}

This way, your code will compile both locally (without pragmas) and online judges (with pragmas) on the latest GCC version!

Shults answered 25/1 at 23:56 Comment(0)
P
3

The target pragma applies to all functions defined later in the file. Never put it in front of an #include directive; otherwise you attempt to put target pragmas on standard library functions and that's not supported.

The following code compiles (https://godbolt.org/z/efxThx51e):

#include <iostream>
#include <string>

#pragma GCC target("avx2,popcnt,lzcnt,abm,bmi,bmi2,fma,tune=native")

int main() {
    std::string s = "Hello World!";
    std::cout << s << std::endl;
}

Alternatively, you can put a target attribute on individual functions:

int main() __attribute__ ((__target__ ("avx2,popcnt,lzcnt,abm,bmi,bmi2,fma,tune=native")))
Pentadactyl answered 2/1 at 9:55 Comment(1)
Also with the preferred C++11/C23 attribute syntax: [[gnu::__target__("...")]] int main() {Babbie

© 2022 - 2024 — McMap. All rights reserved.