I may have found a bug with GCC v4.8.2, but I want to check first before I submit it as it could be me doing something wrong!
The following code:
#include <vector>
struct Message
{
typedef union {
char byte;
const char *str;
} Parameter;
Parameter p1;
Parameter p2;
};
int main()
{
std::vector<Message> messages_;
messages_.push_back({{ .byte = 'a' }});
Message message = {{ .byte = 'a' }, { .str = "Hello World" }};
messages_.push_back(message);
messages_.push_back({{ .byte = 'a' }, { .str = "Hello World" }});
}
clang++ -std=c++11 main.cpp compiles this fine. However g++ outputs this:
main.cpp: In function ‘int main()’:
main.cpp:23:66: internal compiler error: in reshape_init_class, at cp/decl.c:5216
messages_.push_back({{ .byte = 'a' }, { .str = "Hello World" }});
^
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://bugzilla.redhat.com/bugzilla> for instructions.
Preprocessed source stored into /tmp/ccrf5vwr.out file, please attach this to your bugreport.
I'll submit this as a bug if nobody has any ideas, although in my experience a programmers problem is almost never a compiler bug and almost always a fault of his own!
As answered in the comments above: Any error message you get from GCC that includes the phrases internal compiler error and Please submit a full bug report is definitely a compiler bug, not your own fault! In this case, the bug appears to be something to do with GCC's parsing of {{ ... }} in C++ mode where the "..." includes a designated initializer. #Sam has reported it as GCC bug 59832.
However, as #Angew pointed out, this line —
messages_.push_back({{ .byte = 'a' }});
— is not valid C++. Standard C++ doesn't allow designated initializers; that's a C99 feature that was not adopted into C++ (neither C++11 nor C++14).
As for why designated initializers have been problematic to add to C++, see here, where Doug Gregor asks how the compiler should interpret things like
struct Foo {int x,y; };
void f(Foo);
void f(std::initializer_list<int>);
int main(){
f({1});
f({1,2});
f({1,2,3});
f({.x=1});
f({.x=1,2});
f({.x=1,2,3});
}
For the record, GCC 4.8 treats all six as calls to f(initializer_list<int>). Clang 3.5 treats the first three as calls to f(initializer_list<int>), the next two as calls to f(Foo), and the last one as ill-formed. Basically, it's a non-standard construct: different compilers are within their rights to treat it differently, and they do.
Related
struct Foo {
char a[10];
int b;
};
static Foo foo = {.a="bla"};
Compiling the above code gives the following gcc error:
$ gcc -std=gnu++2a test.cpp
C99 designator ‘a’ outside aggregate initializer
I thought that c-string designators in initializer list like these are ok in C++20? What am I missing? I am using gcc version 10.
This is a known bug with GCC: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55227
Unfortunately, you will have to either not use designated initializers or use a different initializer for the array:
static Foo foo = {"bla"};
static Foo foo = {.a={'b', 'l', 'a', 0}};
I got the same error and I dealt with mv my.cpp my.c
You also can find answer in this link:
https://pcbartists.com/firmware/esp32-firmware/designator-outside-aggregate-initializer-solved/
#ifdef __cplusplus
extern "C"
{
#endif
// C code goes here
#ifdef __cplusplus
}
#endif
I use strncpy (from <cstring>), for example:
strncpy(foo.str, "hello", sizeof(foo_t::str));
It seems to be optimized away, therefore generating the same assembly as normal approach in newer GCC (11.3^) and the same as using Artyer solution (the accepted one) of using char array.
Godbolt link: https://godbolt.org/z/9G7b6PT9b
However, the solution might cause warning: missing initializer for member 'foo_t::str' [-Wmissing-field-initializers] if you have the -Wextra warnings enable, but you can use -Wno-missing-field-initializers to exclude it.
By the way, with stucts like that you always have to remember the space is limited, and in many cases you might want leave trailing zero for string end. Using strncpy you can force that by adding:
foo.str[sizeof(foo_t::str) - 1] = 0;
The following code compiles just fine and I'm not sure why. Can someone please explain to me why this is legal?
I am using g++ (Debian 6.1.1-10) 6.1.1 20160724 to compile.
#include <iostream>
int sum(int x, int y) { return x + y; }
int main(int argc, char *argv[])
{
using std::cout;
int (*) (int, int) = ∑
cout << "what" << '\n';
}
Addendum
The following program compiles fine using g++ version 5.4.0 but fails to compile in gcc.
int main()
{
int (*) = 20;
}
It's very likely to be related to this bug reported by Zack Weinberg:
Bug 68265 - Arbitrary syntactic nonsense silently accepted after 'int (*){}' until the next close brace
(From Why does this invalid-looking code compile successfully on g++ 6.0? :)
The C++ compiler fails to diagnose ill-formed constructs such as
int main()
{
int (*) {}
any amount of syntactic nonsense
on multiple lines, with *punctuation* and ++operators++ even...
will be silently discarded
until the next close brace
}
With -pedantic -std=c++98 you do get "warning: extended initializer
lists only available with -std=c++11 or -std=gnu++11", but with
-std=c++11, not a peep.
If any one (or more) of the tokens 'int ( * ) { }' are removed, you do
get an error. Also, the C compiler does not have the same bug.
Of course, if you try int (*) (int, int) {} or other variants, it erroneously compiles. The interesting thing is that the difference between this and the previous duplicate/bug reports is that int (*) (int, int) = asdf requires asdf to be a name in scope. But I highly doubt that the bugs are different in nature, since the core issue is that GCC is allowing you to omit a declarator-id.
[n4567 §7/8]: "Each init-declarator in the init-declarator-list
contains exactly one declarator-id, which is the name declared by
that init-declarator and hence one of the names declared by the
declaration."
Here's an oddity:
int (*) (int, int) = main;
In this specific scenario, GCC doesn't complain about taking the address of main (like arrays, &main is equivalent to main).
The following is nonsensical yet compiles cleanly with g++ -Wall -Wextra -Werror -Winit-self (I tested GCC 4.7.2 and 4.9.0):
#include <iostream>
#include <string>
int main()
{
for (int ii = 0; ii < 1; ++ii)
{
const std::string& str = str; // !!
std::cout << str << std::endl;
}
}
The line marked !! results in undefined behavior, yet is not diagnosed by GCC. However, commenting out the for line makes GCC complain:
error: ‘str’ is used uninitialized in this function [-Werror=uninitialized]
I would like to know: why is GCC so easily fooled here? When the code is not in a loop, GCC knows that it is wrong. But put the same code in a simple loop and GCC doesn't understand anymore. This bothers me because we rely quite a lot on the compiler to notify us when we make silly mistakes in C++, yet it fails for a seemingly trivial case.
Bonus trivia:
If you change std::string to int and turn on optimization, GCC will diagnose the error even with the loop.
If you build the broken code with -O3, GCC literally calls the ostream insert function with a null pointer for the string argument. If you thought you were safe from null references if you didn't do any unsafe casting, think again.
I have filed a GCC bug for this: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63203 - I'd still like to get a better understanding here of what went wrong and how it may impact the reliability of similar diagnostics.
I'd still like to get a better understanding here of what went wrong and how it may impact the reliability of similar diagnostics.
Unlike Clang, GCC doesn't have logic to detect self-initialized references, so getting a warning here relies on the code for detecting use of uninitialized variables, which is quite temperamental and unreliable (see Better Uninitialized Warnings for discussion).
With an int the compiler can figure out that you write an uninitialized int to the stream, but with a std::string there are apparently too many layers of abstraction between an expression of type std::string and getting the const char* it contains, and GCC fails to detect the problem.
e.g. GCC does give a warning for a simpler example with less code between the declaration and use of the variable, as long as you enable some optimization:
extern "C" int printf(const char*, ...);
struct string {
string() : data(99) { }
int data;
void print() const { printf("%d\n", data); }
};
int main()
{
for (int ii = 0; ii < 1; ++ii)
{
const string& str = str; // !!
str.print();
}
}
d.cc: In function ‘int main()’:
d.cc:6:43: warning: ‘str’ is used uninitialized in this function [-Wuninitialized]
void print() const { printf("%d\n", data); }
^
d.cc:13:19: note: ‘str’ was declared here
const string& str = str; // !!
^
I suspect this kind of missing diagnostic is only likely to affect a handful of diagnostics which rely on heuristics to detect problems. These would be the ones that give a warning of the form "may be used uninitialized" or "may violate strict aliasing rules", and probably the "array subscript is above array bounds" warning. Those warnings are not 100% accurate and "complicated" logic like loops(!) can cause the compiler to give up trying to analyse the code and fail to give a diagnostic.
IMHO the solution would be to add checking for self-initialized references at the point of initialization, and not rely on detecting it is uninitialized later when it gets used.
You claim it's undefined behavior, but when I compile the two cases to assembly, I definitely see the function-scoped variable not being initialized on the stack, and the block-scoped variable getting set to NULL.
That's as much of an answer as you're getting from me. I downloaded the C++ spec to definitively settle this, but fell into a Lovecraftian-type fugue when I gazed upon it, to preserve my fragile sanity...
I strongly suspect the block-scoped case is not actually undefined.
This question already has answers here:
What is the strict aliasing rule?
(11 answers)
Closed 9 years ago.
In file included from /usr/local/Qt/linux-g++/include/QtCore/QLinkedList:2,
from /home/bamboo/Packages/Parser.h:17,
from /home/bamboo/Packages/Module.cpp:6:
/usr/local/Qt/linux-g++/include/QtCore/qlinkedlist.h: In member function 'void QLinkedList<T>::clear() [with T = int]':
/usr/local/Qt/linux-g++/include/QtCore/qlinkedlist.h:294: error: dereferencing pointer 'y' does break strict-aliasing rules
/usr/local/Qt/linux-g++/include/QtCore/qlinkedlist.h:293: note: initialized from here
/usr/local/Qt/linux-g++/include/QtCore/qlinkedlist.h:294: error: dereferencing pointer 'y' does break strict-aliasing rules
/usr/local/Qt/linux-g++/include/QtCore/qlinkedlist.h:293: note: initialized from here
where in big lines class Module contains a member template like: Parser<int> and the class parser is defined:
template <typename T> class Parser
{
// some stuff
QLinkedList<T> stuff;
};
and this piece of code compiles nicely with gcc (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3 and nicely with g++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2 and fails with g++ (Debian 4.4.5-8) 4.4.5 ... and I have no idea why? Anyone has seen this error message and anyone know what this might mean?... and more importantly how to solve it?
Aliasing means that a pointer int *i points to the same address as double *d.
So if
int i = 5;
int *pi = &i:
double *d = pi;
here d is aliasing pi.
this is in c99 >illegal<
I don't know how exactly c++ treats it, but I can't imagine it is welcome.
If you want to test a code where it will be getting funny, try this code in different optimisation levels.
You will get differen results with gcc 4.2
uint32_t anint;
int main(int arg, char** argv)
{
foo ((uint64_t *)&anint);
return 0;
}
void foo (uint64_t *dblptr)
{
anint = 88;
*dblptr = 86;
dosmthng (anint);
}
void dosmthng (uint32_t val)
{
printf ("%d\r\n", val);
}
if you do -O2 or higher the output will be 88. because the compiler expects you to respect the strict-aliasing rule and expects *dblptr as never been used in this code, and jsut takes the line out.
If you any way see no way of working wihtout aliasing, you can give the compiler the param -fno-strict-aliasing. This forces GCC to do not any optimisation based on this expection.
But anyway in C it is not strict ISO C code if you do wrong type punning.
(So if it may ease you, a lot of C code on famous programms gets compiled with -fno-strict-aliasing)
When I compile this helloworld example, I get the following error repeated 4 times:
error: expected primary-expression before ‘.’ token
Here is the code:
static struct fuse_operations hello_oper = {
.getattr = hello_getattr,
.readdir = hello_readdir,
.open = hello_open,
.read = hello_read,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &hello_oper);
}
Your compiler is too old. It needs to support C99. Pass in -std=c99 if the compiler is current enough
That syntax is using a new feature of the C99 language standard called designated initializers. That feature is not part of the more common C89 standard (aka ANSI C), so a C89 compiler will give you syntax errors when you try to compile code that uses it.
To fix it, tell your compiler to use its C99 mode if it has one. For example, if you're using GCC, you should pass the -std=c99 compiler option. If your compiler doesn't support C99 at all, you'll have to either switch to a compiler that does, or refactor the code to avoid using C99 features.
Actually, gcc support newer dialects of C (or of C++). Try passing it gcc -std=c99 -Wall
Ran into a similar error, although I was unable to overcome it by adding "#define FUSE_USE_VERSION ..." as mentioned in one of the comments above.
To overcome the error, I wrote a wrapper around the fuse_operations as follows:
struct my_operations: public fuse_operations {
my_operations()
{
read = my_read;
open = my_open;
}
} operations;
main(int argc, char* argv[])
{
return fuse_main(argc, argv, &operations, NULL);
}