How to use GCC diagnostic pragma with C++ template functions? - c++

I would like to use g++ and -Werror, so I have now to disable warnings for 3rd-party libraries I have no control of. The solution provided by http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html works very well, allowing simply to wrap the includes of 3rd party headers with pragmas. Unfortunately, that did no longer work for me in a certain setup where templates are involved. I created the following minimal example of where this approach did not work as expected:
Source file main.cpp
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include "hdr.hpp"
#pragma GCC diagnostic error "-Wunused-parameter"
int main() {
return mytemplatefunc(2) + mystandardfunc(3); // will print ONLY ONE warning
}
and the header hdr.hpp
template<typename T>
int mytemplatefunc(T t) {
return 42;
}
int mystandardfunc(int i) {
return 53;
}
compiled using Makefile
CPPFLAGS+=-Wunused-parameter -Werror
main: main.cpp
will produce the following compiler error
g++ -Wunused-parameter -Werror main.cpp -o main
In file included from main.cpp:3:
hdr.hpp: In instantiation of ‘int mytemplatefunc(T) [with T = int]’:
main.cpp:29: instantiated from here
hdr.hpp:2: error: unused parameter ‘t’
make: *** [main] Error 1
shell returned 2
Note that explicit instantiation in main.cpp directly after including the header did not work, and wrapping the call to the template function in main.cpp did not work either. What was puzzling that putting #pragma GCC diagnostic ignored "-Wunused-parameter" in front of the main function silenced the compiler, whilst then adding #pragma GCC diagnostic error "-Wunused-parameter" at the very end of the file caused the compiler to produce the error again. How to solve this puzzle?
(Note, there are dozens of threads about this pragma, but I could not find anyone
that involved such a setup)

The issue is that the instantiation of the template is compiled when you use it, not when it is parsed by the compiler in the header file so it will not issue the warning until it replaces T by int and parses it as a regular function outside the context of the pragma silencing.

The usual way to indicate that you don't intend to use a parameter is to not give it a name:
template<typename T>
int mytemplatefunc(T /* t */)
{ return 42; }
int mystandardfunc(int /* i */)
{ return 53; }

Related

C++: Template Specialization causes different result in Debug / Release

In the following code, I create a Builder template, and provide a default implementation to return nothing. I then specialize the template with int, to return a value 37.
When I compile with -O0, the code prints 37, which is the expected result. But when I compile using -O3, the code prints 0.
The platform is Ubuntu 20.04, with GCC 9.3.0
Can anyone helps me understand the behavior?
builder.h
class Builder {
public:
template<typename C>
static C build() {
return 0;
}
};
builder.cc
#include "builder.h"
template<>
int Builder::build<int>() {
return 37;
}
main.cc
#include "builder.h"
#include <iostream>
int main() {
std::cout << Builder::build<int>() << '\n';
}
makefile
CXX_FLAG = -O0 -g
all:
g++ $(CXX_FLAG) builder.cc -c -o builder.o
g++ $(CXX_FLAG) main.cc builder.o -o main
clean:
rm *.o
rm main
You should add a forward declaration for build<int>() to builder.h, like so:
template<>
int Builder::build<int>();
Otherwise, while compiling main.cc, the compiler sees only the generic template, and is allowed to inline an instance of the generic build() function. If you add the forward declaration, the compiler knows you provided a specialization elsewhere, and will not inline it.
With -O3, the compiler tries to inline, with -O0 it will not inline anything, hence the difference.
Your code actually violates the "One Definition Rule": it will create two definitions for Builder::build<int>(), but they are not the same. The standard says the result is undefined, but no diagnostics are required. That is a bit unfortunate in this case, as it would have been helpful if a warning or error message was produced.

clang++ error on <experimental/any>

I get an error when compile code containing <experimental/any>.
Code in main.cpp:
#include <experimental/any>
int main() { }
Compile this (clang version is 3.9):
clang++ main.cpp -o main -std=c++1z
Error after the compiling:
In file included from main.cpp:2:
/usr/lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/experimental/any:364:34: error:
no template named '__any_caster'; did you mean 'any_cast'?
return static_cast<_ValueType*>(__any_caster<_ValueType>(__any));
^
/usr/lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/experimental/any:361:30: note:
'any_cast' declared here
inline const _ValueType* any_cast(const any* __any) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/experimental/any:372:34: error:
no template named '__any_caster'; did you mean 'any_cast'?
return static_cast<_ValueType*>(__any_caster<_ValueType>(__any));
^
/usr/lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/experimental/any:369:24: note:
'any_cast' declared here
inline _ValueType* any_cast(any* __any) noexcept
^
2 errors generated.
As #chris mentioned in the comments:
You could try with libc++. Perhaps there's an incompatibility with Clang in libstdc++'s new header.
This turns out to be true. Clang 3.9 is still experimental, and so it uses experimental headers, including a experimental C++ standard library. By default, it is provided by GCC, and so an incompatibility occurs between the GCC implementation and the Clang implementation.

different behavior depending on the optimization options

I found an example where the output is different depending on the optimization settings (-O3 vs none), yet GCC 4.8.2 produces no warnings, even with the -std=c++11 -Wall -pedantic options.
In this particular case, I'm assuming that "forgetting" the commented line in header.h is a mistake, and with -O3, c<int>::get() gets inlined.
However, is there any way to protect yourself against these kinds of mistakes -- a compiler or linker option perhaps?
header.h:
#ifndef HEADER_H
#define HEADER_H
template<class T>
struct c
{
int get() { return 0; }
};
// template<> int c<int>::get();
#endif
imp.cpp:
#include "header.h"
template<>
int c<int>::get()
{
return 1;
}
main.cpp:
#include <iostream>
#include "header.h"
int main()
{
c<int> i;
std::cout << i.get() << '\n'; // prints 0 with -O3, and 1 without
}
build:
c++ -std=c++11 -pedantic -Wall -O3 -c imp.cpp
c++ -std=c++11 -pedantic -Wall -O3 -c main.cpp
c++ -std=c++11 -pedantic -Wall -O3 imp.o main.o
What you get if you have the line in your header-file, is a declaration of an explicit specialization for that member-function.
Thus, main.cpp is assured of a definition in some other compilation-unit, and things work.
If you leave it out, you have a violation of the ODR:
That specific instantiation of your class-template is different in the compilation-units. Resulting in "ill-formed, no diagnostic required", so anything goes.
And there is (currently?) no compiler-option to force gcc to diagnose it.
The true mistake here is the way you're laying out your source files and building them. When c<int>::get() is used, its definition should be available in order to instantiate the template. To fix this, header.h should #include "imp.cpp" rather than the other way around. You may want to rename imp.cpp to imp.inl or something else.
When you define templates which are used outside of a single .cpp file, those definitions should be visible to anyone who includes their header.
As an aside: I don't think there's any way to make the compiler or linker warn you about what you've done here. But if you structure your project as I've described, this problem won't happen, because the forward declaration will be unnecessary.

Workaround for debug symbol error with auto member function?

There seems to be an issue with debug symbols and auto.
I have an auto function in a class:
#include <cstddef>
template <typename T>
struct binary_expr {
auto operator()(std::size_t i){
return 1;
}
};
int main(){
binary_expr<double> b;
return 0;
}
When I compile with G++ (4.8.2) and -g, I have this error:
g++ -g -std=c++1y auto.cpp
auto.cpp: In instantiation of ‘struct binary_expr<double>’:
auto.cpp:11:25: required from here
auto.cpp:4:8: internal compiler error: in gen_type_die_with_usage, at dwarf2out.c:19484
struct binary_expr {
^
Please submit a full bug report,
with preprocessed source if appropriate.
See <https://bugs.gentoo.org/> for instructions.
With clang++ (3.4) and -g, I have this:
clang++ -g -std=c++1y auto.cpp
error: debug information for auto is not yet supported
1 error generated.
If I remove the -g or set the type explicitly, it works perfectly.
Isn't clang++ supposed to be C++14 feature complete ?
Is there a workaround for these limitations or I'm screwed ?
This now seems to works on Clang 3.5 SVN. Live Example. It seems that the culprit was a commit from May 2013, see this message on the Clang mailing list.
PR16091: Error when attempting to emit debug info for undeduced auto
return types
Perhaps we should just suppress this, rather than erroring, but since
we have the infrastructure for it I figured I'd use it - if this is
determined to be not the right thing we should probably remove that
infrastructure entirely. I guess it's lying around from the early days
of implementing debug info support.
// RUN: %clang_cc1 -emit-llvm-only -std=c++1y -g %s 2>&1 | FileCheck %s
2
3 struct foo {
4 auto func(); // CHECK: error: debug information for auto is not yet supported
5 };
6
7 foo f;
However, I cannot find the commit that removed this info, perhaps there was an improvement that now prevents that this behavior is being triggered.
Even after some time, the only workaround I have found is to make the function template, pretty stupid workaround... Apparently, clang has no problem with auto functions that are template. I don't know if this works in every case, but until now it had worked for me.
#include <cstddef>
template <typename T>
struct binary_expr {
template<typename E = void>
auto operator()(std::size_t i){
return 1;
}
};
int main(){
binary_expr<double> b;
return 0;
}

Why does -Wunused-variable in GCC produce an error even on static const?

I have a header, core/types.hh, used by several different build targets. It has the following declaration:
core/types.hh
typedef std::size_t Size;
static const Size SZ_MAX = std::numeric_limits<Size>::max();
...
Some of the targets use this constant, some don't. So I get:
error: 'core::SZ_MAX' defined but not used"
I use scons with GCC 4.7.3 on Linux. I have -Wall set and want to keep it that way.
As far as I understand from the GCC documentation, this shouldn't give a warning:
-Wunused-variable
Warn whenever a local variable or non-constant static variable is unused aside from its declaration. This warning is enabled by -Wall.
So I don't see why I get a warning (which turns into an error).
On other answers, people were advised to make the declaration extern and to do the assignment in the file that uses the constant. This file is used by many other files, so it would loose its constant-ness if I do that. Furthermore, this file has header guards, so I think this should mean that the constant is actually created only once.
I'd appreciate any help!
Yuval
Possible duplicates:
How to use typed constants with “unused variable” warnings?
c++ static array declared in h file gives warning 'defined but not used'
It seems that this was not the error that halted compilation.
Rather, if GCC find another error, it would still report on this too.
I actually had another unused variable, and that's what caused this error in the first place.
For example, when creating the following files:
file1.cc
#include "head1.hh"
int main() {
int bad_unused_variable;
return my_ns::JUST_ANOTHER_CONST;
}
head1.hh
#ifndef HEAD1
#define HEAD1
#include <stdint.h>
#include <cstddef>
#include <limits>
namespace my_ns {
typedef std::size_t Size;
static const Size SZ_MAX = std::numeric_limits<Size>::max();
static const Size JUST_ANOTHER_CONST = 8;
}
#endif
You get:
> g++ -Wall -Werror file1.cc -O2 -std=c++98 -o file1
file1.cc: In function 'int main()':
file1.cc:4:6: error: unused variable 'bad_unused_variable' [-Werror=unused-variable]
In file included from file1.cc:1:0:
head1.hh: At global scope:
head1.hh:10:20: error: 'my_ns::SZ_MAX' defined but not used [-Werror=unused-variable]
cc1plus: all warnings being treated as errors
EDIT
This also seems to have been answered here: gcc warnings: defined but not used vs unused variable - there they mention the subtle differences between the two warning messages (unused variable vs defined but not used). Still, it doesn't really answer as to why GCC behaves this way...