GCC, empty structs, and -Wunused-result - gcc

The following program causes gcc to emit -Wunused-result:
struct Empty { };
__attribute__((warn_unused_result))
static struct Empty func(void) {
return (struct Empty){};
}
int main(void) {
struct Empty res = func();
(void)res;
return 0;
}
Compiler output:
gcc -Wall -Wextra /tmp/test.c -c -o /tmp/test
/tmp/test.c: In function ‘main’:
/tmp/test.c:12:22: warning: ignoring return value of ‘func’, declared with attribute warn_unused_result [-Wunused-result]
struct Empty res = func();
^~~~~~
clang doesn't emit a warning.
Is this a bug or a feature?
(Empty struct as return value is useful in some code generation scenarios where a return value is always expected, but that is beside the question)

This does indeed appear to be a bug in GCC. I filed a bug report with them.
A workaround is to include a nameless bitfield in the "empty" structure:
struct Empty {char:1;};
extern void use_empty(struct Empty);
__attribute__((warn_unused_result))
extern struct Empty make_empty(void);
void should_warn(void)
{
make_empty();
}
void shouldnt_warn_1(void)
{
use_empty(make_empty());
}
void shouldnt_warn_2(void)
{
struct Empty e = make_empty();
use_empty(e);
}
warns only for 'should_warn'. This does mean that sizeof(struct Empty) is 1 rather than 0, and GCC generates an additional move instruction in both shouldnt_warn_1 and shouldnt_warn_2, but those are probably acceptable side-effects.
(Note that both a struct with no fields at all, and a struct with no named fields, are GNU extensions — in ISO C you must include at least one named field in every struct. Nameless bitfields, however, are standard, just obscure.)

Related

Why there is unused-but-set variable-warning with pointers

I have the following code:
#include <iostream>
class Test
{
public:
Test(int i)
{
initialize(i);
}
void initialize(int i)
{
std::cout<<"i: "<<i<<std::endl;
}
};
int main()
{
Test* obj1(nullptr);
obj1 = new Test(2);
Test* obj2(nullptr);
obj2 = new Test(2);
obj2->initialize(3);
return 0;
}
When I compile as such (GCC v11.2.0):
g++ -Wall --std=c++11 main.cpp
I see the following warning:
main.cpp: In function ‘int main()’:
main.cpp:25:15: warning: variable ‘obj1’ set but not used [-Wunused-but-set-variable]
25 | Test* obj1(nullptr);
| ^~~~
My question is why is there a warning for obj1, but not obj2 when they do almost the same thing?
The key thing to realize here is that you actually have FOUR objects in your code -- two instances of the class Test and two pointers. The instances of Test don't have names (they're created with new), while the pointers do have names (obj1 and obj2).
The warning here is about the pointer object obj1 which is only ever assigned to and not used. The fact that the object it points at after the final assignment has had various side effects prior to that assignment is not relevant. You could remove the declaration an assignment (but not the new call in the assignment) without affecting the behavior or output of your program.
int main()
{
new Test(2);
Test* obj2(nullptr);
obj2 = new Test(2);
obj2->initialize(3);
return 0;
}

Does MSP430 GCC support newer C++ standards? (like 11, 14, 17)

I'm writing some code that would greatly benefit from the concise syntax of lambdas, which were introduced with C++ 11. Is this supported by the compiler?
How do I specify the compiler flags when compiling using Energia or embedXcode?
As of February 2018, up to C++14 is supported with some limitations:
http://processors.wiki.ti.com/index.php/C%2B%2B_Support_in_TI_Compilers
There isn't much about this topic on the TI site, or, at least, I don't know enough C++ to give you a detailed and precise response.
The implementation of the embedded ABI is described in this document that is mainly a derivation of the Itanium C++ ABI. It explains nothing about the implementation of lambdas nor the auto, keyword (or probably I'm not able to derive this information from the documentation).
Thus I decided to directly test in Energia. Apparently the g++ version is 4.6.3, thus it should support both.
And in fact (from a compilation point of view, I don't have my MSP here to test the code) it can compile something like:
// In template.hpp
#ifndef TEMPLATE_HPP_
#define TEMPLATE_HPP_
template<class T>
T func(T a) {
auto c = [&](int n) { return n + a; };
return c(0);
}
#endif /* TEMPLATE_HPP_ */
// in the sketch main
#include "template.hpp"
void setup() { int b = func<int>(0); }
void loop() { }
(the template works only if in an header, in the main sketch raises an error). To compile this sketch I had to modify one internal file of the editor. The maximum supported standard seems to be -std=c++0x, and the compilation flags are in the file:
$ENERGIA_ROOT/hardware/energia/msp430/platform.txt
in my setup the root is in /opt/energia. Inside that file I modified line 32 (compiler.cpp.flags) and added the option. Notice that -std=c++11 is not supported (raises an error).
compiler.cpp.flags=-std=c++0x -c -g -O2 {compiler.mlarge_flag} {compiler.warning_flags} -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD
Unfortunately I have zero experience with embedXcode :\
Mimic std::function
std::function is not provided, thus you have to write some sort of class that mimics it. Something like:
// callback.hpp
#ifndef CALLBACK_HPP_
#define CALLBACK_HPP_
template <class RET, class ARG>
class Callback {
RET (*_f)(ARG);
public:
Callback() : _f(0) { };
Callback(RET (*f)(ARG)) : _f(f) { };
bool is_set() const { return (_f) ? true : false; }
RET operator()(ARG a) const { return is_set() ? _f(a) : 0; }
};
#endif /* CALLBACK_HPP_ */
// sketch
#include "callback.hpp"
// | !! empty capture!
void setup() { // V
auto clb = Callback<int, char>([](char c) { return (int)c; });
if (clb.is_set())
auto b = clb('a');
}
void loop() {}
may do the work, and it uses a simple trick:
The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. [C++11 standard 5.1.2]
As soon as you leave the capture empty, you are assured to have a "conversion" to a function pointer, thus you can store it without issues. The code I have written:
requires a first template RET that is the returned type
requires a second template ARG that is one argument for the callback. In the majority of the case you may consider to use void* as common argument (cast a struct pointer in a void pointer and use it as argument, to counter-cast in the function, the operation costs nothing)
implements two constructors: the empty constructor initialize the function pointer to NULL, while the second directly assigns the callback. Notice that the copy constructor is missing, you need to implement it.
implements a method to call the function (overloading the operator ()) and to check if the callback actually exists.
Again: this stuff compiles with no warnings, but I don't know if it works on the MSP430, since I cannot test it (it works on a common amd64 linux system).

Universal Reference and Named Parameter Ideom

I wrote this code and compile with gcc.
I expected to get result "2", but result was "0".
Other compiler clang and vc prints "2".
Is it undefined behaviour or not?
#include <stdio.h>
struct Test {
Test& inc() {
++value;
return *this;
}
int value = 1;
};
int main() {
auto&& t = Test().inc(); // The life-time of the temporary might extended.
printf("%d\n", t.value); // gcc prints "0". dangling reference?
return 0;
}
c.f. build reslut on http://rextester.com
gcc result
clang result
vc result
The forwarding reference (that's what universal references have been renamed to) is irrelevant -- you would observe the same behaviour with a regular reference.
The issue is that the Test's lifetime is not extended, because it is not directly bound to the reference, as auto &&t = Test(); would be. Instead, its member function returns an lvalue reference, which is used to deduce and initialize t as a Test & (you can check this via decltype(t)). Then the temporary is destructed, the reference is now dangling, and using it is undefined behaviour.

link functions with mismatching signature

I'm playing around with gcc and g++ compiler and trying to compile some C code within those, my purpose is to see how the compiler / linker enforces that when linking a model with some function declaration to a model with that implementation of that function, the correct function are linked ( in terms of parameters passed and values returned )
for example let's take a look at this code
#include <stdio.h>
extern int foo(int b, int c);
int main()
{
int f = foo(5, 8);
printf("%d",f);
}
after compilation within my symbol table I'd have a symbol for foo, but within the elf file format there is not place that describes the arguments taken and the function signature, ( int(int,int) ), so basically if I write some other code such as this:
char foo(int a, int b, int c)
{
return (char) ( a + b + c );
}
compile that model it'll also have some symbol called foo, what if I link these models together, what's gonna happen? I have never thought of this, and how would a compiler overcome this weakness... I know that within g++ the compiler generates some prefix for every symbol regarding to it's namespace, but does it also take in mind the signature? If anyone has ever encountered this it would be great if he could shed some light upon this problem
The problem is solved with name mangling.
In compiler construction, name mangling (also called name decoration)
is a technique used to solve various problems caused by the need to
resolve unique names for programming entities in many modern
programming languages.
It provides a way of encoding additional information in the name of a
function, structure, class or another datatype in order to pass more
semantic information from the compilers to linkers.
The need arises where the language allows different entities to be
named with the same identifier as long as they occupy a different
namespace (where a namespace is typically defined by a module, class,
or explicit namespace directive) or have different signatures (such as
function overloading).
Note the simple example:
Consider the following two definitions of f() in a C++ program:
int f (void) { return 1; }
int f (int) { return 0; }
void g (void) { int i = f(), j = f(0); }
These are distinct functions, with no relation to each other apart
from the name. If they were natively translated into C with no
changes, the result would be an error — C does not permit two
functions with the same name. The C++ compiler therefore will encode
the type information in the symbol name, the result being something
resembling:
int __f_v (void) { return 1; }
int __f_i (int) { return 0; }
void __g_v (void) { int i = __f_v(), j = __f_i(0); }
Notice that g() is mangled even though there is no conflict; name
mangling applies to all symbols.
Wow, I've kept exploring and testing it on my own and I came up with a solution which quietly amazed my mind,
so I wrote the following code and compiled it on a gcc compiler
main.c
#include <stdio.h>
extern int foo(int a, char b);
int main()
{
int g = foo(5, 6);
printf("%d", g);
return 0;
}
foo.c
typedef struct{
int a;
int b;
char c;
char d;
} mystruct;
mystruct foo(int a, int b)
{
mystruct myl;
my.a = a;
my.b = a + 1;
my.c = (char) b;
my.d = (char b + 1;
return my1;
}
now I compiled foo.c to foo.o with gcc firstly and checked the symbol table using
readelf and I had some entry called foo
also after that I compiled main.c to main.o checked the symbol table and it also had some entry called foo, I linked those two together and surprisingly it worked, I ran main.o and obviously encountered some segmentation fault, which makes sense as the actual implementation of foo as implemented in foo.o probably expects three parameters (first one should be struct adders), a parameter which isn't passed in main.o under it's definition to foo then the actual implementation accesses some memory that doesn't belong to it from the stack frame of main, then tries accessing addresses that it thought it got, and ends up with segmentation fault, that's fine,
now I compiled both models again with g++ and not gcc and what came up was amazing.. I found out that the symbol entry under foo.o was _Z3fooii and under main.o it was _Z3fooic, now my guess is that the ii suffix means int int and ic suffix means int char which probably refers to the parameters that should be passed to function hence allowing the compiler to know some function deceleration gets the actual implementation. so I changed my foo declaration in main.c to
extern int foo(int a, int b);
re-compiled and this time got the symbol _Z3fooii, I linked both models again and amazingly this time it worked, I tried running it and again encountered segmentation fault, which again also makes sense as the compiler wont always even authorize correct return values.. anyways what was my original thought - that g++ includes function signature within symbol name and thus enforces the linker to give function implementation get correct parameters to correct function declaration

What are "lowered vtable references"?

Clang's own diagnostics propaganda contains this exerpt:
Since Clang has range highlighting, it never needs to pretty print your code back out to you. This is particularly bad in G++ (which often emits errors containing lowered vtable references), but even GCC can produce inscrutible error messages in some cases when it tries to do this.
Googling this phrase doesn't give anything very helpful, and the subsequent example is completely unrelated.
Can someone please post an example of what it's talking about?
Thanks.
Here is an example:
struct a {
virtual int bar();
};
struct foo : public virtual a {
};
void test(foo *P) {
return P->bar()+*P;
}
Clang produces:
t.cc:9:18: error: invalid operands to binary expression ('int' and 'foo')
return P->bar()+*P;
~~~~~~~~^~~
GCC 4.2 produces:
t.cc: In function ‘void test(foo*)’:
t.cc:9: error: no match for ‘operator+’ in ‘(((a*)P) + (*(long int*)(P->foo::<anonymous>.a::_vptr$a + -0x00000000000000020)))->a::bar() + * P’
t.cc:9: error: return-statement with a value, in function returning 'void'
GCC does this because its C++ frontend is bolted on top of the C frontend in many cases. Instead of building C++-specific Abstract Syntax Trees (ASTs) for various C++ operations, the parser just lowers them immediately to their C equivalent. In this case, GCC synthesizes an struct to contain the vtable, and the pointer dereference to bar is then lowered into a series of C pointer dereferences, casts, pointer arithmetic etc.
Clang does not have this problem, because it has a very clean AST that directly represents the source code. If you change the example to:
struct a {
virtual int bar();
};
struct foo : public virtual a {
};
void test(foo *P) {
P->bar();
}
.. so that the code is valid, then ask clang to dump its ast with "clang -cc1 -ast-dump t.cc", you get:
...
void test(foo *P)
(CompoundStmt 0x10683cae8 <t.cc:8:19, line:10:1>
(CXXMemberCallExpr 0x10683ca78 <line:9:3, col:10> 'int'
(MemberExpr 0x10683ca40 <col:3, col:6> '<bound member function type>' ->bar 0x10683bef0
(ImplicitCastExpr 0x10683cac8 <col:3> 'struct a *' <UncheckedDerivedToBase (virtual a)>
(ImplicitCastExpr 0x10683ca28 <col:3> 'struct foo *' <LValueToRValue>
(DeclRefExpr 0x10683ca00 <col:3> 'struct foo *' lvalue ParmVar 0x10683c8a0 'P' 'struct foo *'))))))
-Chris

Resources