Given the following source code:
#include <memory>
#include <typeinfo>
struct Base {
virtual ~Base();
};
struct Derived : Base { };
int main() {
std::unique_ptr<Base> ptr_foo = std::make_unique<Derived>();
typeid(*ptr_foo).name();
return 0;
}
and compiled it with:
clang++ -std=c++14 -Wall -Wextra -Werror -Wpedantic -g -o test test.cpp
Enviroment setup:
linux x86_64
clang version 5.0.0
It does not compile because of warning (note -Werror):
error: expression with side effects will be evaluated
despite being used as an operand to 'typeid'
[-Werror,-Wpotentially-evaluated-expression]
typeid(*ptr_foo).name();
(Just a note: GCC does not claim that kind of potential problematic)
Question
Is there a way to get the information about the type pointed by a unique_ptr without generating that kind of warning?
Note: I am not talking about disabling -Wpotentially-evaluated-expression or avoiding -Werror.
Looks like following should work without warnings and give correct result for derived class
std::unique_ptr<Foo> ptr_foo = std::make_unique<Bar>();
if(ptr_foo.get()){
auto& r = *ptr_foo.get();
std::cout << typeid(r).name() << '\n';
}
Related
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.
Consider the following code
#include <iostream>
template<typename Value>
struct Wrapper {
Value m_value;
Wrapper() {}
Wrapper(const Wrapper<Value> ©_from) : m_value(copy_from.m_value) {}
};
template<typename Value>
struct DefaultContainer {
Value m_default;
DefaultContainer(const Value& def) : m_default(def) {}
};
template<typename Value>
struct DefaultContainerUser : public DefaultContainer<Value> {
DefaultContainerUser() : DefaultContainer<Value>(Value()) {}
};
int main() {
DefaultContainerUser<Wrapper<double>> user;
std::cout << user.m_default.m_value << std::endl;
}
When I compile this with c++ -O1 -Werror -Wall test.cpp, I get the following error:
test.cpp: In function ‘int main()’:
test.cpp:8:63: error: ‘<anonymous>.Wrapper<double>::m_value’ is used uninitialized in this function [-Werror=uninitialized]
8 | Wrapper(const Wrapper<Value> ©_from) : m_value(copy_from.m_value) {}
| ~~~~~~~~~~^~~~~~~
cc1plus: all warnings being treated as errors
If I disable optimizations using -O0, everything works fine. Adding -Wno-error=maybe-uninitialized with optimizations still turned on doesn't help. What am I doing wrong here?
The compiler that I'm using is c++ (GCC) 10.2.1 20201016 (Red Hat 10.2.1-6).
It is normal that the warnings reported by a compiler varies depending on the optimization level. Warnings are usually a bi-product of optimization in the sense that the analysis needed for a particular optimization may uncover possible problems in the code or that transformations applied during optimization may uncover possible errors. This implies that when optimization is off and the analysis and transformations are not performed the problems are not detected.
I have the following SSCCE:
#include <iostream>
#include <string>
void foo(const std::string &a) {
std::cout << a << std::endl;
}
template <typename... Args>
void bar(Args &&... args) {
[&]() {
[&]() {
foo(args...);
}();
}();
}
int main() {
const std::string x("Hello World!");
bar(x);
}
Under clang++ (3.9.1) this compiles and emits "Hello World". Gcc 6.3 fails with a segmentation fault under -O3.
I can fix the problem by explicitly passing the pointer and the pack by reference, replacing [&]() with [&args...](). However, up to now, I thought that [&] would do the same as listing all arguments one by one.
So what is going wrong here?
P.S:
This is not limited to -O3. -O0 does not segfault but does not return the expected result ("Hello World!"):
[:~/tmp] $ g++-6 -std=c++1z param.cpp && ./a.out
[:~/tmp] $
P.P.S: Further reduced SSCCE. Now I don't even get a diagnostic with -Wall -Wextra anymore.
I strongly suspect a g++ bug.
Here are some notes:
replacing std::string with any elementary type, e.g., int still does not work
clang and VC++ will work just as intended
not passing parameter pack by reference causes an internal compiler error with g++ 7.0.1 with the following output:
internal compiler error: in make_decl_rtl, at varasm.c:1304
...
Please
submit a full bug report, with preprocessed source if appropriate.
Please include the complete backtrace with any bug report. See
http://gcc.gnu.org/bugs.html for instructions.
i was just making a few changes to my program, when all of a sudden g++ complained with an internal compiler error.
Clang however compiles it without any problems and also does not give any warnings, that would indicate anything weird.
I distilled the problem down to this:
#include <functional>
template<typename T>
class A{
T someVar;
};
template<typename T>
class B {
int x;
std::function<A<double>(A<int>&)> someLambda = [&](A<int>& aInt){
int xVar = x;
A<double> aRet;
return aRet;
};
};
int main(int argc, char** argv){
B<int> a;
return 0;
}
I tried both GCC 4.9.2 and 4.8.4, with both failing (internal compiler error).
Flags I used:
g++ -std=c++11 -O0 -g -Wall main.cpp -o gccBin
clang++ -std=c++11 -O0 -g -Wall main.cpp -o clangBin
main.cpp: In instantiation of 'struct B<int>::<lambda(class A<int>&)>':
main.cpp:10:7: required from here
main.cpp:14:24: internal compiler error: in tsubst_copy, at cp/pt.c:12569
int xVar = x;
^
libbacktrace could not find executable to open
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.
Clang++(3.5.1) compiles it without a problem, as I mentioned.
I also tried multiple machines, everywhere the same.
Is there some kind of error I overlooked? I searched a bit on the internet and the only similar problems i could find should have been fixed by now (as the bugtracker states).
Could maybe someone try and run this code on their machine or give other advice?
Thank you,
Lazarus
It's a compiler bug. Just go ahead and file a bug report to the GCC dudes!
I'm lost as to why Clang rejects the following code:
#include <typeinfo>
#include <exception>
const char* get_name( const std::exception_ptr eptr )
{
return eptr.__cxa_exception_type()->name();
}
int main() {}
It OK with GCC, but Clang complains about type_info being an incomplete type:
$ g++-4.7 -std=c++0x -O3 -Wall -Wextra t.cc -o t
$ clang++-3.2 -std=c++0x -O3 -Wall -Wextra t.cc -o t
t.cc:6:37: error: member access into incomplete type 'const class type_info'
return eptr.__cxa_exception_type()->name();
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/bits/exception_ptr.h:144:19: note: forward declaration of
'std::__exception_ptr::type_info'
const class type_info*
^
1 error generated.
$
Question: How do I fix it with Clang? Or am I missing something and Clang is right to reject the code?
Thanks to #HowardHinnant's comment, I managed to fix the problem. The problem became obvious in the preprocessor output: libstdc++ includes <exception> from <type_info> before it even declared std::type_info. That made Clang assume a new forward-declaration std::__exception_ptr::type_info. The solution is as simple as it is illegal:
namespace std { class type_info; }
#include <typeinfo>
#include <exception>
const char* get_name( const std::exception_ptr eptr )
{
return eptr.__cxa_exception_type()->name();
}
int main() {}
Seems like I should check if libstdc++ already has a bug report for that and, if not, create one.
UPDATE: Bug #56468 is now fixed for GCC 4.7.3+