[[maybe_unused]] for a function - c++

I don't quite understand when [[maybe_unused]] on a function itself could be useful.
By reading the paper, it only said the attribute may be applied to the declaration of a function. My question is that if it implies compiler will raise warning on an unused function, then for any public header of a library, everything should have the attribute to avoid warning as users might only use parts of the library.
Is my understanding correct?
Thank you.

Inspired from here:
namespace {
[[maybe_unused]] void foo() {}
void bar() {}
}
int main() {}
Functions declared in the unnamed namespace can only be used in this translation unit, hence the compiler can warn when the functions are not used. And indeed gcc warns for bar (error because of -Wall -Werror) but due to [[maybe_unused]] not for foo :
<source>:5:10: error: 'void {anonymous}::bar()' defined but not used [-Werror=unused-function]
5 | void bar() {}
| ^~~
Live
The original example in the page linked above is a little more motivating, as it uses conditional compilation where depending on some symbols being set a function is used or not.

The compiler warns about functions that it can tell are unused. If it is unsure - if your function ends up in a place where others could call it, like in a library - the compiler assumes it is used.
For example, if you have a translation unit with these functions (ref):
int square(int num) {
return num * num;
}
static int cube(int num) {
return num * num * num;
}
square could be called by other functions from other translation units. It's unused here but may be used somewhere else. The compiler doesn't know about these other places, so it cannot flag the function as unused. There is no warning; adding the attribute has no effect.
cube, on the other hand, is static - so if it's used anywhere, it must be in this translation unit. Since it isn't used here, the compiler (at least gcc with -Wunused-function) warns about this.
Adding [[maybe_unused]] to cube then silences that warning. It basically says "I know that you know that this is unused; don't warn about it."

Related

What happens if the same static member variable has different values

1.cc
struct foo{
const static int bar = 5;
};
int main(){
return foo::bar;
}
2.cc
struct foo{
const static int bar = 6;
};
g++ 1.cc 2.cc doesn't give a link error.
Does this go against the one definition rule and cause undefined behaviour?
Additionally i'm not sure why const int foo::bar; was not even needed as suggested by this article: https://www.ibm.com/docs/en/zos/2.1.0?topic=members-static-data
which says:
Note that the constant initializer is not a definition. You still need to define the static member in an enclosing namespace.
But mine compiles with or without it.
You are breaking the One Definition Rule: Class definitions in multiple translation units have to be the same. This makes your program ill-formed, but compiler's don't have to warn you about it.
If you had multiple definitions (const int foo::bar;), you would probably run into a linker error. But without any definitions, it is difficult for the compiler to detect this at link time, so it just isn't.
In practice, if you had a definition in 1.cc, you would find that usages in 1.cc would always evaluate to 5, and in 2.cc they would sometimes be 6 (always 6 in constant expressions) and sometimes be 5.
The reason you don't need a definition to have return foo::bar; is that this does not ODR-use foo::bar, it is simply a constant expression that evaluates to 5 (without needing a definition of foo::bar). If you instead had something like:
int copy(const int& x) {
return x;
}
int main() {
return copy(foo::bar);
}
Binding the reference const int& x would ODR-use foo::bar, and the linker would complain about there not being a definition for foo::bar.

C++ accepting function argument without variable name [duplicate]

While getting started with some VS2005-generated MFC code, I noticed it overrode a method with something like this:
void OnDraw(CDC* /*pDC*/)
{
...
// TODO: Add your code here
}
So of course, as soon as I added something I realized I needed to un-comment the pDC formal argument in order to compile, but I'm confused as to how/why a C++ function can compile (with no warnings) when the formal argument only has a type and not a name:
void foo(int)
{
int x = 3;
}
int main()
{
foo(5);
return 0;
}
Shouldn't this generate at least a warning (with -Wall or /W4)? It doesn't seem to. Am I missing something? Is there a case where this is useful or is it just because the compiler can't tell the difference between a function declaration (only types required) and a definition (fully specified) until after the line has been processed?
Because sometimes you have a parameter that's required by an interface but the function doesn't use it. Maybe the parameter is no longer necessary, is only necessary in other functions that must use the same signature (especially so they can be called through pointers) or the functionality hasn't been implemented yet. Having parameters that aren't used can be particularly common in generated or framework code for this reason (and that's probably why the MFC generated code has the name commented out).
As to why there's no warning - I guess it's because whether this is a problem is a subjective thing and other people (particularly compiler implementers) don't see it as a problem. Once you actually go to use the parameter, you'll get the compiler to complain if you forget to uncomment the name so you get the compiler complaining only when you really need it to (the compiler's version of the agile YAGNI: "You Aren’t Gonna Neet It" philosophy).
The opposite does seem to generally occur when you crank up warnings - named parameters that aren't used generate warnings - again that's probably why the generated function has the name commented out.
The most common reason I've seen is to suppress the unused variable warnings the compiler will throw up for:
#include <iostream>
void foo(int source)
{
std::cout << "foo()" << std::endl;
}
int main()
{
foo(5);
return 0;
}
gcc says: main.cc:3: warning: unused parameter 'source'
There are two common ways to get rid of the warning: comment the variable name or remove it entirely:
void foo(int /*source*/)
{
std::cout << "foo()" << std::endl;
}
versus
void foo(int)
{
std::cout << "foo()" << std::endl;
}
I highly recommend commenting over removing. Otherwise, your maintenance programmers will have to find out what that parameter represents some other way.
Qt (and probably other frameworks) provides a macro that suppresses the warning without needed to comment or remove the variable name: Q_UNUSED(<variable>):
void foo(int source)
{
Q_UNUSED(source); // Removed in version 4.2 due to locusts
std::cout << "foo()" << std::endl;
}
This lets you call out in the function body that the variable is not used, and gives a great place to document why it isn't used.
C++11 N3337 standard draft
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf says it is legal at 8.4.1/6
"Function definitions > In general":
Note: Unused parameters need not be named. For example,
void print(int a, int) {
std::printf("a = %d\n",a);
}
More precisely, 8.4.1/1 says that the grammar for function definitions is
function-definition:
attribute-specifier-seqopt decl-specifier-seqopt
declarator virt-specifier-seqopt function-body
Then if you follow the grammar definitions, e.g. under "Annex A Grammar summary", you will see that the names are optional.
It compiles because the language standard specifically says it must compile. There's no other answer. This is one of the bits that make C++ different from C. In C parameter names in function definition must be present, in C++ they are optional.
I actually wonder why you ask your "why" question. Do you see anything unnatural, unusual or illogical in this behavior?

Forward-declaration of a `constexpr` function inside another function -- Compiler bug?

While producing a MCVE for this problem I stumbled upon, I've found the following discrepancy between compilers:
Consider the following code :
// constexpr int f(); // 1
constexpr int g() {
constexpr int f(); // 2
return f();
}
constexpr int f() {
return 42;
}
int main() {
constexpr int i = g();
return i;
}
This code compiles on Clang 3.8.0, but fails on GCC 6.1.0 with:
error: 'constexpr int f()' used before its definition
Commenting out // 2 and uncommenting // 1 works on both compilers.
Interestingly, moving f's definition in place of // 1 compiles, but triggers a warning at // 2:
warning: inline function 'constexpr int f()' used but never defined
Which compiler is right ?
Replacing the constexpr functions with inline functions retains the exact same problem (it is okay with the global declaration 1, but not with the function-scope declaration 2.) Since constexpr implies inline this seems like the cause.
In this case, with declaration 2, GCC complains:
warning: 'inline' specifier invalid for function 'f' declared out of global scope
and warning: inline function 'int f()' used but never defined.
It fails to link ("undefined reference to 'f()'").
So it looks like it gives up on inlining, puts in a call, but doesn't bother emitting code for f() because all uses are inlined (?), so the link fails.
and Clang complains:
error: inline declaration of 'f' not allowed in block scope
Since constexpr implies inline, it seems that this rule that inline declarations are not allowed in block scope should also apply to constexpr, and so GCC is correct. But the standard does not seem to come out and say this. In the draft I examined, the rule about inline is in §7.1.2 [dcl.fct.spec], part 3: "The inline specifier shall not appear on a block scope function declaration", but nothing similar appears about constexpr.

Return type of function declaration & definition didn't match, compiler was ok with it though?

I made an error in my program where I declared my function to return type bool even though the function returned an unsigned long long. In one source file:
#include <iostream>
using namespace std;
bool base(unsigned, unsigned);
int main(){
int i = 27;
cout << base(i,3);
}
And in another defining the function (and an additional function power):
unsigned long long power(int base, int exponent){
unsigned long long temp = 1;
if(exponent == 0) return 1;
for(int i = 1; i <= exponent; ++i)
temp *= base;
return temp;
}
unsigned long long base(unsigned x, unsigned base){
unsigned long long result = 0;
int i = 0;
while(x != 0){
result += (x%base)*power(10,i);
x = (x-(x%base))/base;
++i;
}
return result;
}
The function works out the number in the base given (here we are working out 27 in base 3). Surprisingly to me the program compiled, but unsurprisingly the output gave the wrong answer (232 instead of the expected 1000) because the return type is wrong. I was wondering why the compiler let through that the return type in the declaration is bool even though that doesn't correspond to the return type in the definition. I was under the impression the function prototype had to match exactly to its corresponding definition, otherwise the function cannot be found? It was just odd because I spent some time trying to look for the issue since the compiler didn't bring it up.
What you see is undefined behavior: when you define a function in an incompatible way to its forward declaration, your program is ill-formed:
7.5.5: If two declarations declare functions with the same name and parameter-type-list (8.3.5) to be members of the same namespace or declare objects with the same name to be members of the same namespace and the
declarations give the names different language linkages, the program is ill-formed; no diagnostic is required if the declarations appear in different translation units.
When you proceed to calling such function, the behavior is undefined. Undefined behavior may manifest itself in any way it wishes. In your case, the call succeeds, but the returned value is incorrect.
The compiler has no way to figure it out without help from you, because the connection between the two functions is made by the linker, not by the compiler. It is too late for the compiler to do anything, so you need to use a different approach: you avoid errors like this by making a header file with a declaration of your function, and then including the same header in both the files where you define and the files where you call the function.
Part of the reason is that they are two separate compilation units, and the declaration of base() above main() is not visible to the compiler when compiling the second compilation unit (aka source file, in rough terms). Similarly, the actual definition of base() is not visible to the compiler when compiling main().
The second part of the reason is that deciding what function to call only uses the type of arguments, not the return type. That means name mangling (the adornment of names so overloaded function can be accepted by the linker as distinct functions) only needs to encode information about types of function arguments, not the return type. The linker will therefore see the definition in your second compilation unit as matching the declaration in the first.
The net result is undefined behaviour.
The fix is to ensure the declaration of base() you have in the first compilation unit is visible to the compiler when compiling the second unit. In other words, put the declaration in a header file, and #include it in both source files. The compiler will then reject the definition of base() since it doesn't match the preceding declaration.

Unexpected success of C Code

I am testing the following code in Code::Blocks v 12.11:
#include <stdio.h>
int main()
{
display();
return 0;
}
void display()
{
printf("\nHi");
}
It compiles successfully and runs well.I am unable to understand why?
My queries are as follows:
A function or variable needs to be at least declared before getting used in C/C++. Here,there is no declaration before we called the function display().
By default,all functions have return type as int.So,I am expecting a compilation error here but it went through successfully.The compiler would have assumed display() to be int display() and then we defined it as void display().
In C++, functions must be declared or defined before being use; that code cannot be C++.
In C89 or pre-standard C, if the compiler encounters an identifier followed by an open parenthesis, it is a function call, and if there is no declaration or definition in effect, then the return type is implicitly int and the number and types of the arguments is unspecified. (Thus, in the example, display() is a function returning an int and taking an indefinite — but not variable — number of arguments.)
In C99 or C11, in any strict compliance mode, you must have a declaration or definition of the function in scope before calling. It still doesn't have to be a prototype (the inferred declaration int display(); is not a prototype, and the definition is also not a prototype — it would need to be int display(void) to provide a prototype!).
Because of the inferred type for display() and the contradictory definition, you should get a compilation error, I believe. It would be at best a sloppy compiler that allowed it through, even in C89 mode. Indeed, I think even a pre-standard compiler should complain about the difference between the assumed and actual return types, but of course there was no standard so you couldn't complain (and, in any case, that standard is 24 years old now — compilers that only support that are verging on the archaic).
Which compiler (and version) are you using on which platform?
GCC 4.8.2 on Mac OS X 10.9, even with things set as permissive as possible, says:
dec.c:9:6: warning: conflicting types for ‘display’ [enabled by default]
void display()
^
dec.c:5:5: note: previous implicit declaration of ‘display’ was here
display();
^
Your code works perfectly well as a .c file and shows error when it is executed as a .cpp file
I hope this post explains why.
Why are function declaration mandatory in C++ and not in C?