Is clang++ ignoring extern "C" for some deprecation warnings? - c++

If I use clang 3.8.1 to compile:
extern "C" {
int foo(int x) { register int y = x; return y; }
}
int main() { return foo(123); }
I get the warning:
a.cpp:3:18: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
int foo(int x) { register int y = x; return y; }
^~~~~~~~~
... which I really shouldn't be getting this, since the inner function is C code. If I use GCC 6.3.1, even with -Wall, I don't get this warning.
Is this a clang bug or am I doing something wrong?

extern "C" does not mean "compile this code as C". It means "make this function (or functions) callable from C code", which typically means changing name mangling and, sometimes, calling convention.

Perhaps the error has nothing to do with the extern "C"? It looks like it says, not, "register is incompatible with C" but rather "register is incompatible with C++1z". (I assume C++1x means C++11/14/17.)

Related

Why do C++ deprecated warnings print twice?

If I have
namespace foo {
inline int bar() {
return 1119;
}
}
__attribute__((deprecated)) inline int bar() {
return 138;
}
in header.h and
#include "header.h"
#include <iostream>
int main() {
int x = bar();
int y = foo::bar();
std::cout << x << std::endl;
std::cout << y << std::endl;
}
in source.cpp, then
g++ source.cpp -o deprecated-test
results in
source.cpp: In function ‘int main()’:
source.cpp:5:17: warning: ‘int bar()’ is deprecated [-Wdeprecated-declarations]
int x = bar();
^
In file included from source.cpp:1:
header.h:7:40: note: declared here
__attribute__((deprecated)) int bar() {
^~~
source.cpp:5:17: warning: ‘int bar()’ is deprecated [-Wdeprecated-declarations]
int x = bar();
^
In file included from source.cpp:1:
header.h:7:40: note: declared here
__attribute__((deprecated)) int bar() {
(on Ubuntu 18.10 with g++ 8.2.0).
Why does the deprecated warning print twice?
Heading off some suggestions that would be unhelpful:
[[deprecated]]:
I know with C++14 on you can use the [[deprecated]] attribute, but I need to work with C++11.
Declaration vs. definition: The docs seem to imply it should be used with function declaration rather than definition, but
I need to define the functions inline in a header rather than declare in the header and define in source files; and
Trying this approach didn't stop the warning from printing twice anyway.
As per the documentation of GCC 8.2.0:
The deprecated attribute results in a warning if the function is used anywhere
in the source file. This is useful when identifying functions that are expected
to be removed in a future version of a program. The warning also includes the
location of the declaration of the deprecated function, to enable users to easily
find further information about why the function is deprecated, or what they
should do instead. Note that the warnings only occurs for uses...
There should be only one warning and not two. So this is a bug in GCC.
There is a related bug for Type attributes (rather than Function attributes) titled: C/C++ __attribute__((deprecated)) does not appear to wrap declarations as implied from the doc.
It has been confirmed as a bug.

warn_unused_result attribute and returning class object

Please consider the following code:
class cls
{
};
__attribute__((warn_unused_result))
cls fn1()
{
return cls();
}
__attribute__ ((warn_unused_result))
int fn2()
{
return 1;
}
int main()
{
auto x = fn1();
(void)x;
auto y = fn2();
(void)y;
return 0;
}
When I compile this with -Wall -Wextra with gcc 5.4.0, I get a warning:
warning: ignoring return value of ‘cls fn1()’,
declared with attribute warn_unused_result [-Wunused-result]
Can somebody tell me what's wrong?
Why this warning appears for fn1 despite the x variable, and why it does NOT appear for the fn2?
Update 1: With a little help, I tried this with g++ 4.8.3 - the same result. Even more - g++ 3.3.6 produces two warnings - for fn1 and fn2.
What "fixes" the warning is...... guess what - adding a data member or a virtual member function in the class (a non-virtual function does not help). Sounds like a compiler bug to me.
Update 2: Actually adding a member or a virtual function disables the warning completely, so just calling fn1(); does NOT produce the warning anymore.

what is wrong with the gcc internal symbol decoration?

#include <stdio.h>
namespace myname{
double var = 42;
}
extern "C" double _ZN6myname3varE = 10.0;
int main(){
printf("%d\n", _ZN6myname3varE);
return 0;
}
The gcc compile result is:
Jim#ubuntu:~/workspace/vi_edit$ g++ testSymble.cpp -o testSymble
testSymble.cpp:7:19: warning: ‘_ZN6myname3varE’ initialized and declared ‘extern’ [enabled by default]
testSymble.cpp: In function ‘int main()’:
testSymble.cpp:10:32: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat]
/tmp/cczIjRfH.s: Assembler messages:
/tmp/cczIjRfH.s:14: Error: symbol `_ZN6myname3varE' is already defined
Why _ZN6myname3varE is redefined?
What does the warning ‘_ZN6myname3varE’ initialized and declared ‘extern’ [enabled by default] mean?
If the program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this clause, the behavior is undefined.
17.4.3.1.2 Global names
Each name that contains a double underscore (_ _) or begins with an underscore followed by an uppercase
letter (2.11) is reserved to the implementation for any use.
Why _ZN6myname3varE is redefined?
The C++ variable myname::var is name-mangled to _ZN6myname3varE by GCC. You've also defined a C (i.e. non-mangled) variable called _ZN6myname3varE. Therefore you have multiple definitions of the same symbol.
What does the warning [...] mean?
Standard usage is:
foo.h
extern "C" int myvariable;
foo.c/cc
#include "foo.h"
int myvariable = 42;
I'm not sure whether the C++ standard permits initialization of extern "C" variables (i.e. like you're doing). But the compiler is certainly warning you that what you're doing probably doesn't make sense.
The first warning message means that if you include extern in a variable's declaration, you cannot also include an initializer. Thus, both these lines generate that warning:
extern "C" int i = 9;
extern int j = 10;
You can either write:
int i = 9;
int j = 10;
or:
extern "C" int i;
extern int j;
or (as Adam Rosenfield points out in a comment), you can include braces in the line to allow an initializer:
extern "C" { int i = 9; }
Applied to your code, you cannot put the initializer = 42 in the extern "C" line, or you need to write:
extern "C" { double _ZN6myname3varE = 10.0; }
In isolation, and ignoring the final issue, that should 'work'.
The second warning means that namespace myname { double var = 42; } is a double so the %d conversion specification is wrong; it should be %f or %e or %g or variants on this theme.
printf("%f\n", myname::var);
The third message, the error, is from the assembler. Because the first message was only a warning, you actually have two different definitions which, when mangled, translate to _ZN6myname3varE, with two different initializers. You're only allowed one definition — the One Definition Rule.
However, names starting with an underscore followed by an upper-case letter are reserved for the implementation, so by trying to use the name _ZN6myname3varE directly, you are invoking undefined behaviour. Don't mess around with undefined behaviour; avoid it.

g++ special handling of printf

Anyone knows why the following code works under g++ 4.7.2? If I change the name printf to another name such as f, it has compiler error saying constexpr can't contain non-const function calls (which I think is the correct behavior).
[hidden]$ cat d.cpp
extern "C" { extern int printf(const char* s, ...); }
constexpr int g() { return printf(""), 0; }
template <int N> struct X { const static int value = N; };
int n = X<g()>::value;
[hidden]$ g++ -std=c++11 -c d.cpp
[hidden]$ g++ -v |& tail -1
gcc version 4.7.2 20121109 (Red Hat 4.7.2-8) (GCC)
Note I don't include any header files.
printf() is handled as a builtin function by GCC/g++ in many cases (though I think this behavior is still a bug). From http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html:
The ISO C90 functions ... printf ... are all recognized as built-in functions unless -fno-builtin is specified (or -fno-builtin-function is specified for an individual function)
You get the correct diagnostic if you use the -fno-builtin option.
The bug appears to be fixed in 4.8.0.
I think stdio.h is included by default
I try it with puts and works for me [gcc version 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1)]
extern "C" { extern int puts(const char* s); }
constexpr int g() { return puts(""), 0; }
template <int N> struct X { const static int value = N; };
int n = X<g()>::value;
Edit:
#Keith Thompson
Before I wrote "included by default" I tried the code below without #include <stdio.h>. It compiles with some warnings but runs - so (for some reason) printf, scanf, puts works without #include <stdio.h>. Maybe stdio.h is not included by default, maybe library with printf, scanf, puts is linked by default.
int main()
{
char one;
printf("Hello ");
scanf("%c", &one);
puts("world!");
}

Suppress unused variable warning in C++ => Compiler bug or code bug?

Presently, I am using the following function template to suppress unused variable warnings:
template<typename T>
void
unused(T const &) {
/* Do nothing. */
}
However, when porting to cygwin from Linux, I am now getting compiler errors on g++ 3.4.4 (On linux I am 3.4.6, so maybe this is a bug fix?):
Write.cpp: In member function `void* Write::initReadWrite()':
Write.cpp:516: error: invalid initialization of reference of type 'const volatile bool&' from expression of type 'volatile bool'
../../src/common/Assert.h:27: error: in passing argument 1 of `void unused(const T&) [with T = volatile bool]'
make[1]: *** [ARCH.cygwin/release/Write.o] Error 1
The argument to unused is a member variable declared as:
volatile bool readWriteActivated;
Is this a compiler bug or a bug in my code?
Here is the minimal test case:
template<typename T>
void unused(T const &) { }
int main() {
volatile bool x = false;
unused(!x); // type of "!x" is bool
}
The actual way of indicating you don't actually use a parameter is not giving it a name:
int f(int a, float) {
return a*2;
}
will compile everywhere with all warnings turned on, without warning about the unused float. Even if the argument does have a name in the prototype (e.g. int f(int a, float f);), it still won't complain.
I'm not 100% sure that this is portable, but this is the idiom I've usually used for suppressing warnings about unused variables. The context here is a signal handler that is only used to catch SIGINT and SIGTERM, so if the function is ever called I know it's time for the program to exit.
volatile bool app_killed = false;
int signal_handler(int signum)
{
(void)signum; // this suppresses the warnings
app_killed = true;
}
I tend to dislike cluttering up the parameter list with __attribute__((unused)), since the cast-to-void trick works without resorting to macros for Visual C++.
It is a compiler bug and there are no known work arounds:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42655
It is fixed in v4.4.
In GCC, you can define a macro as follows:
#ifdef UNUSED
#elif defined(__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
#elif defined(__LCLINT__)
# define UNUSED(x) /*#unused#*/ x
#else
# define UNUSED(x) x
#endif
Any parameters marked with this macro will suppress the unused warning GCC emits (and renames the parameter with a prefix of UNUSED_). For Visual Studio, you can suppress warnings with a #pragma directive.
The answer proposed by haavee (amended by ur) is the one I would normally use:
int f(int a, float /*epsilon*/) {
return a*2;
}
The real problem happens when the argument is sometimes but not always used in the method, e.g.:
int f(int a, float epsilon) {
#ifdef LOGGING_ENABLED
LOG("f: a = %d, epsilon = %f\n", a, epsilon);
#endif
return a*2;
}
Now, I can't comment out the parameter name epsilon because that will break my logging build (I don't want to insert another #ifdef in the argument list because that makes the code much harder to read).
So I think the best solution would be to use Tom's suggestion:
int f(int a, float epsilon) {
(void) epsilon; // suppress compiler warning for possibly unused arg
#ifdef LOGGING_ENABLED
LOG("f: a = %d, epsilon = %f\n", a, epsilon);
#endif
return a*2;
}
My only worry would be that some compilers might warn about the "(void) epsilon;" statement, e.g. "statement has no effect" warning or some such - I guess I'll just have to test on all the compilers I'm likely to use...