Why doesn't clang warn of dead code in templates? - c++

When compiling with -Weverything, why would clang not flag the dead code in the template below, but flag it in the function? Note that in both cases, it flags the unused variable warning.
#include <iostream>
template <class Item> class ItemBase {
public:
bool performWork() {
int i;
std::cout << "foo" << std::endl;
return true;
std::cout << "dead code in template" << std::endl;
}
};
bool badFunc();
bool badFunc() {
int i;
std::cout << "foo" << std::endl;
return true;
std::cout << "dead code in function" << std::endl;
}
int main() {
ItemBase<float> tester;
tester.performWork();
badFunc();
}
clang output:
test.cpp:24:13: warning: unused variable 'i' [-Wunused-variable]
int i;
^
test.cpp:33:9: warning: unused variable 'i' [-Wunused-variable]
int i;
^
test.cpp:36:42: warning: code will never be executed [-Wunreachable-code]
std::cout << "dead code in function" << std::endl;
^~
3 warnings generated.

I don't see that there's any reason for that warning not being emitted (other than a bug in clang).
I'm guessing clang is being over-cautious about warnings in templates since it isn't able to tell that code will never be executed by any instantiation of the template (even though it's obvious to a human), so it just doesn't warn. But that's just an assumption.

Related

Emscripten: how to disable warning: explicit specialization cannot have a storage class

I am building my program by using the latest Emscripten compiler.
It is based on Clang version 14. Actually it is a small test program which is the following:
#include <iostream>
struct Test {
template<typename T>
static inline void Dump(const T& value) {
std::cout << "[generic] = '" << value << "'\n";
}
template<>
static inline void Dump<std::string>(const std::string& value) {
std::cout << "[std::string] = '" << value << "'\n";
}
};
int main() {
std::string text = "hello";
Test::Dump(text);
return 0;
}
When I build it by Emscripten compiler I got the warning:
D:\em_test>emcc a.cpp
a.cpp:10:24: warning: explicit specialization cannot have a storage class
static inline void Dump<std::string>(const std::string& value) {
~~~~~~~ ^
1 warning generated.
If I just remove static keyword from void Dump<std::string> line
then there will be no warning. However, this code will cause compilation error in Visual Studio:
D:\em_test\a.cpp(17,11): error C2352: 'Test::Dump': illegal call of non-static member function
But this error is expected and clear.
I would like to write a cross-platform program.
So, I think I should simple disable this warning in Emscripten.
However, I can not find any Emscripten (which is based on clang version 14)
command line option for that!
And I am asking advice for that.
Actually I tried to use -Wno-static-inline-explicit-instantiation command line option but it did not help:
D:\em_test>emcc -Wno-static-inline-explicit-instantiation a.cpp
a.cpp:10:24: warning: explicit specialization cannot have a storage class
static inline void Dump<std::string>(const std::string& value) {
~~~~~~~ ^
1 warning generated.
However, I see in Clang version 13 user manual description about -Wstatic-inline-explicit-instantiation option but it is about a slightly another warning text.
Also it seems that Clang version 14 is not fully released, so, there is no public Clang version 14 user manual.
I can not find any Emscripten or Clang command line option to disable the above warning.
Could somebody help me?
Explicit specialization of (both static and non-static) function templates cannot be put into class definitions.
Just put it into the enclosing namespace(i.e somewhere after the class):
#include <iostream>
struct Test {
template <typename T>
static inline void Dump(const T& value) {
std::cout << "[generic] = '" << value << "'\n";
}
};
// Notice Test::
template <>
inline void Test::Dump<std::string>(const std::string& value) {
std::cout << "[std::string] = '" << value << "'\n";
}
int main() {
std::string text = "hello";
Test::Dump(text);
return 0;
}
inline is never necessary for in-class function definitions but it has different meaning for member variables.
inline for out-class is necessary in header files because the explicit specialization is not a template anymore.

G++ command throws "expected '(' for function-style cast or type construction"

Function foo takes a vector of strings. It's defined as
bool foo(vector<string>& input);
When I call foo with:
foo(vector<string>{"abc"});
my compiler gives the following error:
error: expected '(' for function-style cast or type construction
and points to { as the start of the error. This compiles fine in Xcode but I get the error when running the following via command line with:
g++ -o -std=c++17 main.cpp
What is wrong with my g++ syntax?
G++ Version Information:
g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.3 (clang-1103.0.32.59)
Target: x86_64-apple-darwin19.4.0
Thread model: posix
Your command line specifies that the output file ("-o") should be called "-std=c++17" – it does not say anything about the language version, so you're compiling as C++03.
Remove the "-o" or add an actual file name.
Also, note that your "g++" is an alias for clang.
I took your code and tried to compile it. For me there was rather problem with trying to pass non const value to function. I changed function argument to const and it compiled and printed without any problem.
#include <iostream>
#include <vector>
bool foo(const std::vector<std::string>& v) {
for (auto& a : v) { std::cout << a << std::endl; }
return true;
}
int main()
{
bool result = foo(std::vector<std::string> {"1", "2", "3" });
// do something with result
return 0;
}
Compiled on: https://www.onlinegdb.com/online_c++_compiler
Function foo expects for an l-value.
You are generating an instance and passing it to the function. But lifetime of the object is not enough for the pass-by-reference call.
Here is an example below; instance of class A is immediately destructed.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class A {
public:
A(int m): m(m) {
cerr << __func__ << endl;
}
~A() {
cerr << __func__ << endl;
}
int m;
};
int main() {
cerr << __func__ << endl;
A(5);
cerr << __func__ << endl;
return 0;
}
Outputs:
main
A
~A
main

Different compiler behaviour when using alias as scope to get parent member

This code compiles fine on Clang and Visual C++ but not on GCC:
#include <iostream>
template <class T>
struct Test {
Test(T &t) : _t(t) {
}
void method() {
std::cout << _t.Internal::_value << "\n"; // Doesn't work on GCC
std::cout << _t.T::Internal::_value << "\n"; // Work on all compilers
}
private:
T &_t;
};
template <class T>
struct Base {
T _value = 1;
};
template <class T>
struct Child : Base<int> {
using Internal = Base<int>;
int _value = 2;
};
int main(int argc, const char * argv[]) {
Child<float> child;
Test<Child<float>> test(child);
test.method();
return 0;
}
The error message from GCC is
error: 'Internal' has not been declared
9 | std::cout << _t.Internal::_value << "\n";
| ^~~~~~~~
Which one is right ?
Visual C++ and Clang are right in accepting this code.
It was a bug in GCC that prevented it from doing the same. The error as in the question was up to GCC 10, in GCC 11 its wording changed to
error: request for member 'Internal' in non-class type 'T'
9 | std::cout << _t.Internal::_value << "\n";
| ^~~~~~~~
And GCC trunk finally accepts the code as well. Demo: https://gcc.godbolt.org/z/dj34Yhns3
So we could expect the fix in GCC 12.

Odd behaviour of g++ and clang++ with enabled optimization [duplicate]

This question already has answers here:
Why full specialization of template function is not picked up from the .cpp file without declaration?
(3 answers)
Closed 4 years ago.
Here's my program:
print.hpp:
#pragma once
#include <iostream>
template<size_t p>
void print()
{
std::cout << "" << __FILE__ << "" << __LINE__ << "" << std::endl;
exit(0);
}
print.cpp:
#include "print.hpp"
template<>
void print<13>()
{
std::cout << "Unlucky." << std::endl;
}
main.cpp:
#include <iostream>
#include "print.hpp"
int main()
{
std::cout << "Started." << std::endl;
print<13>();
std::cout << "Exiting." << std::endl;
}
When I compile that with g++ main.cpp print.cpp -O0 -std=c++11 && ./a.out it works fine (output is:
Started.
Unlucky.
Exiting.
).
However, if'd I compile that with g++ main.cpp print.cpp -O1 -std=c++11 && ./a.out it would give me a segmentation fault with the output:
Started.
Unlucky.
Speicherzugriffsfehler //German for memory access error
Almost the same with clang++, without optimization it would do its job just fine
and with -O1 or higher it outputs that:
Started.
Unlucky.
./print.hpp8
Why is that?
You need to declare the template specialization in the .hpp file.
template<size_t p>
void print()
{
std::cout << "" << __FILE__ << "" << __LINE__ << "" << std::endl;
exit(0);
}
// Declare the specialization.
template<> void print<13>();
Without the declaration in the .hpp file, I get a linker error with g++ 6.4.0.
.../Local/Temp/cctCC5MK.o:print.cc:(.text+0x0): multiple definition of `void print<13ul>()'
.../Local/Temp/ccgodRUG.o:socc.cc:(.text$_Z5printILm13EEvv[_Z5printILm13EEvv]+0x0): first defined here
collect2: error: ld returned 1 exit status
I am not sure how you are able to successfully build your program without the declaration.

Calling non template member function inside template member function

I am facing compilation problem while running the following program:
I am calling non template member function inside template member function but getting the weird compilation errors.
#include <iostream>
#include <boost\shared_ptr.hpp>
class base
{
public:
base()
{
}
void fun2(boost::shared_ptr<int> &data)
{
std::cout << "This is fun2" << std::endl;
}
void fun3(boost::shared_ptr<double> &value)
{
std::cout << "This is fun3" << std::endl;
}
template <typename T>
void fun1(int switchParam,T &resonse)
{
std::cout << "This is fun1." << std::endl;
switch(switchParam)
{
case 0:
fun2(resonse);
break;
case 1:
fun3(resonse);
break;
}
}
};
void main()
{
boost::shared_ptr<int> myInt;
int switchParam = 0;
base b1;
b1.fun1(switchParam,myInt);
}
Getting the following compilation problem:
Error 1 error C2664: 'base::fun3' : cannot convert parameter 1 from 'boost::shared_ptr<T>' to 'boost::shared_ptr<T> &'
Any help will be appreciated.
No. You cannot do that. With second phase of template code compilation for any type the switch block has to be fully compiled by compiler. It will will fail to compile. You are mixing templates with runtime behavior of program. You better write a different function.
Note that switch is runtime, not compile time. When you call it as fun1(0) the compiler still has to compile it fully for int. It won't evaluate runtime switch statement and eliminate fun3, which takes shared_ptr<double>.