Parameter pack and constexpr static - c++11

Using parameter pack expansion with rvalue references and const class member data causes a link error on Clang 5 and 6, and GCC 4.8.5 and 5.3. I first encountered the problem with a function with the same signature as std::make_shared but have simplified it to the following test case showing 6 different ways that I would expect to work.
#include <utility>
constexpr int global_value = 3;
struct Foo {
static constexpr int value = 3;
};
struct Bar {
static const int value = 3;
};
using Baz = std::integral_constant<int, 3>;
template<class... Args>
int* make(Args&&... args)
{
return new int(std::forward<Args>(args)...);
}
template<class... Args>
int* make_nofwd(Args&&... args)
{
return new int(args...);
}
template<class... Args>
int* make_norvalue(Args... args)
{
return new int(args...);
}
int main(int, char** )
{
#if ATTEMPT == 0
int* v = make(Foo::value); // FAIL
#elif ATTEMPT == 1
int* v = make_nofwd(Foo::value); // FAIL
#elif ATTEMPT == 2
int* v = make_norvalue(Foo::value); // OK
#elif ATTEMPT == 3
int* v = make(global_value); // OK
#elif ATTEMPT == 4
int* v = make(Bar::value); // OK
#elif ATTEMPT == 5
int* v = make(Baz::value); // OK
#endif
return (*v == 3 ? 0 : 1);
}
Running each attempt shows that the struct's constant and constexpr data aren't getting inserted when passed as rvalues.
$ for i in {0..4}; do echo "=== Attempt $i ==="; g++ derp.cc -Wall -Wextra -std=c++11 -D ATTEMPT=$i -o derp.exe && ./derp.exe && echo "SUCCESS" ; done
=== Attempt 0 ===
/tmp/ccC5TyiZ.o: In function `main':
derp.cc:(.text+0x10): undefined reference to `Foo::value'
collect2: error: ld returned 1 exit status
=== Attempt 1 ===
/tmp/ccCwlV85.o: In function `main':
derp.cc:(.text+0x10): undefined reference to `Foo::value'
collect2: error: ld returned 1 exit status
=== Attempt 2 ===
SUCCESS
=== Attempt 3 ===
SUCCESS
=== Attempt 4 ===
/tmp/ccnfzmHk.o: In function `main':
derp.cc:(.text+0x10): undefined reference to `Bar::value'
collect2: error: ld returned 1 exit status
=== Attempt 5 ===
SUCCESS
And, I just discovered that running with any optimization magically fixes it:
for i in {0..4}; do echo "=== Attempt $i ==="; $CXX derp.cc -Wall -Wextra -std=c++11 -D ATTEMPT=$i -O2 -o derp.exe && ./derp.exe && echo "SUCCESS" ; done;
=== Attempt 0 ===
SUCCESS
=== Attempt 1 ===
SUCCESS
=== Attempt 2 ===
SUCCESS
=== Attempt 3 ===
SUCCESS
=== Attempt 4 ===
SUCCESS
=== Attempt 5 ===
SUCCESS
Am I somehow using unspecified behavior here? Why isn't Args&& passing the int through by value?

Related

Detecting uninitialized variables in gcc

The following (broken) example code scanf's an input string to an integer, but allow an empty string through to as 0:
#include <stdio.h>
#include <string.h>
int parse(const char *p)
{
int value; // whoops! forgot to 0 here.
if (*p && sscanf(p, "%d", &value) != 1)
return -1;
return value;
}
int main(int argc, char **argv)
{
const char *p = argc > 1 ? argv[1] : "";
int value = parse(p);
printf("value = %d\n", value);
}
but it compiles clean with -Wall.
https://godbolt.org/z/sPbx99Ms5
but fails with obvious problems:
$ ./test 123
value = 123
$ ./test xxx
value = -1
$ ./test ""
value = 32765
I realise it's quite hard for it to work out that the scanf might not fill in a value as it
can't see the code, but is there a flag or a scanner I could run on a (large) body of code to try and find if there are places where uninitialized variables are being passed by pointer?
... even something that would just find all uninitialized variables would be useful.

How to prevent accidental emission of constexpr functions

Ben Deane mentions the throw trick, which ensures a link error when a constexpr function is used in a non-constexpr context.
Here is my take:
#include <iostream>
struct Exc;
constexpr int foo( int a )
{
if( a == 42 )
{
throw Exc{};
}
return 666;
}
int main()
{
constexpr auto ret = foo(43);
std::cout << ret << "\n";
return ret;
}
But I couldn't make it work (clang++ 3.8.1-23 and g++ 6.3.0):
$ clang++ -std=c++14 main.cpp
main.cpp:9:15: error: invalid use of incomplete type 'ExcBase'
throw ExcBase{};
^~~~~~~~~
main.cpp:3:8: note: forward declaration of 'ExcBase'
struct ExcBase;
^
1 error generated.
A comment in this thread suggests another trick:
#include <iostream>
constexpr int foo( int a )
{
if( a == 42 )
{
(void)reinterpret_cast<int>(a);
}
return 666;
}
int main()
{
constexpr auto ret = foo(43);
std::cout << ret << "\n";
return ret;
}
Which works: no errors or warnings; when the invocation is replaced with foo(42), clang returns:
$ clang++ -std=c++14 main.cpp
main.cpp:19:20: error: constexpr variable 'ret' must be initialized by a constant expression
constexpr auto ret = foo(42);
^ ~~~~~~~
main.cpp:10:15: note: reinterpret_cast is not allowed in a constant expression
(void)reinterpret_cast<int>(a);
^
main.cpp:19:26: note: in call to 'foo(42)'
constexpr auto ret = foo(42);
^
1 error generated.
Which is great. But gcc compiles the code happily in both cases. And now the question. How can a constexpr function be written in such a way, that it cannot be used in non-constexpr environments?
The problem is you actually instantiate (call constructor) a struct which is of incomplete type. This trick you talk about requires any symbol which will not be found at link time. So instead of struct you may use int:
http://coliru.stacked-crooked.com/a/3df5207827c8888c
#include <iostream>
extern int Exc;
constexpr int foo( int a )
{
if( a == 42 )
{
throw Exc;
}
return 666;
}
int main()
{
// Compiles
constexpr auto ret = foo(43);
std::cout << ret << "\n";
// This will show linker error as expected:
// /tmp/ccQfT6hd.o: In function `main':
// main.cpp:(.text.startup+0x4c): undefined reference to `Exc'
// collect2: error: ld returned 1 exit status
int nn;
std::cin >> nn;
auto ret2 = foo(nn);
return ret;
}

Issues with Inheritance and OpenCL

I am trying to port some code to linux from Windows. I have gotten pretty far, but now I am stuck on an error with inheritance. But I can't figure out what's not working. It appears that It's not importing the header, but I can't figure out why because it seems to me that is should be working.
here is the error output:
/usr/bin/c++ -DHAVE_CLOGS -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NO_DEBUG -DQT_WIDGETS_LIB -std=c++11 -I/code/cuda/JF-Cut/src/build -I/code/cuda/JF-Cut/src/QVisualizer -I/code/cuda/clogs-install/include -I/usr/local/cuda-7.5/targets/x86_64-linux/include -isystem /opt/Qt/5.5/gcc_64/include -isystem /opt/Qt/5.5/gcc_64/include/QtWidgets -isystem /opt/Qt/5.5/gcc_64/include/QtGui -isystem /opt/Qt/5.5/gcc_64/include/QtCore -isystem /opt/Qt/5.5/gcc_64/./mkspecs/linux-g++ -fPIC -o CMakeFiles/QGCWidget.dir/Graph_Cut/QGCWidget.cpp.o -c /code/cuda/JF-Cut/src/QVisualizer/Graph_Cut/QGCWidget.cpp
In file included from /code/cuda/JF-Cut/src/QVisualizer/Graph_Cut/QGCWidget.cpp:44:0:
/code/cuda/JF-Cut/src/QVisualizer/Graph_Cut/../infrastructures/QError.h:45:11: error: ‘cl::Error’ has not been declared
using cl::Error;
^
/code/cuda/JF-Cut/src/QVisualizer/Graph_Cut/../infrastructures/QError.h:48:1: error: expected class-name before ‘{’ token
{
^
/code/cuda/JF-Cut/src/QVisualizer/Graph_Cut/../infrastructures/QError.h: In member function ‘void QError::serialize(std::ostringstream&, cl_int)’:
/home/sansomk/code/cuda/JF-Cut/src/QVisualizer/Graph_Cut/../infrastructures/QError.h:68:13: error: ‘cl::Error’ has not been declared
cl::Error::serialize(s, code);
Here is the Code for QError.h
#ifndef QERROR_H
#define QERROR_H
#ifndef __CL_ENABLE_EXCEPTIONS
#define __CL_ENABLE_EXCEPTIONS
#endif
// removed #include "../3rdParty/cl/cl_stacktrace.hpp"
#if defined(__APPLE__) || defined(__MACOSX)
#include <OpenCL/cl.hpp>
#else
#include <CL/cl.hpp>
#endif
#define Q_LOGIC_ERROR -100
#define Q_INVALID_ARGUMENT -101
#define Q_LENGTH_ERROR -102
#define Q_OUT_OF_RANGE -103
#define Q_FUTURE_ERROR -104
#define Q_RUNTIME_ERROR -110
#define Q_RANGE_ERROR -111
#define Q_OVERFLOW_ERROR -112
#define Q_UNDERFLOW_ERROR -113
#define Q_SYSTEM_ERROR -114
using cl::Error;
class QError : public cl::Error
{
protected:
cl_int level_;
void serialize(std::ostringstream& s, cl_int code)
{
std::string error;
switch (code)
{
case Q_LOGIC_ERROR: error = "Q_LOGIC_ERROR"; break;
case Q_INVALID_ARGUMENT: error = "Q_INVALID_ARGUMENT"; break;
case Q_LENGTH_ERROR: error = "Q_LENGTH_ERROR"; break;
case Q_OUT_OF_RANGE: error = "Q_OUT_OF_RANGE"; break;
case Q_FUTURE_ERROR: error = "Q_FUTURE_ERROR"; break;
case Q_RUNTIME_ERROR: error = "Q_RUNTIME_ERROR"; break;
case Q_RANGE_ERROR: error = "Q_RANGE_ERROR"; break;
case Q_OVERFLOW_ERROR: error = "Q_OVERFLOW_ERROR"; break;
case Q_UNDERFLOW_ERROR: error = "Q_UNDERFLOW_ERROR"; break;
case Q_SYSTEM_ERROR: error = "Q_SYSTEM_ERROR"; break;
}
if (!error.empty()) s << " > " << error << ", ";
cl::Error::serialize(s, code);
}
public:
QError(cl_int level, cl_int err, const char * errStr = NULL) : level_(level), cl::Error(err, errStr) {}
~QError() throw() {}
cl_int level(void) const { return level_; }
virtual const char * what() throw ()
{
std::ostringstream s;
serialize(s, err_);
errStr_ = s.str();
return errStr_.c_str();
}
};
#endif // QERROR_H
In order to use cl::Error you need to define __CL_ENABLE_EXCEPTIONS.
I can see you have it there, but that file is a header file. If you include OpenCL headers somewhere else earlier in the compilation unit (.cpp) without defining __CL_ENABLE_EXCEPTIONS. Then the later includes will simply skip (due to ifdefs in the header file to avoid multiple instances of the same .h file).
What you should do for these types of global compilation defines, is declare them in the command line.
g++ ... -D__CL_ENABLE_EXCEPTIONS
That way you ensure the defines are enabled at the very beginning of the compilation.

Issue with LLVM FunctionPass iterator?

I have a very basic pass that need to print how many BasicBlocks are there in a Function.
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/Support/raw_ostream.h"
#include "iostream"
using namespace llvm;
namespace {
struct Mypass : public FunctionPass {
public:
static char ID; // Pass identification
Mypass() : FunctionPass(ID){}
bool runOnFunction(Function &F) override {
errs()<<"Function Name:";
errs()<<F.getName()<<"\n";
Function::iterator bb_i = F.begin();
int bb_count = 0;
for (Function::iterator I = F.begin(); I != F.end(); I++){
std::cout<< "Basic Block: BB"<<bb_count++<<std::endl;
}
return false;
}
};
}
char Mypass::ID = 0;
static RegisterPass<Mypass> X("Epass","Pass",true,false);
I run the pass using opt. And get this error:
> Function Name:testfnc1
> Basic Block: BB0 0 libLLVM-3.4.so 0x000000388b1935d2 llvm::sys::PrintStackTrace(_IO_FILE*) + 34 1 libLLVM-3.4.so
> 0x000000388b193dfa 2 libpthread.so.0 0x0000003feaa0f790 3
> EstimatePass.so 0x00007f04eb789737 4 libLLVM-3.4.so
> 0x000000388aad12b4 llvm::FPPassManager::runOnFunction(llvm::Function&)
> + 468 5 libLLVM-3.4.so 0x000000388aad139b llvm::FPPassManager::runOnModule(llvm::Module&) + 43 6 libLLVM-3.4.so
> 0x000000388aad0f1e llvm::legacy::PassManagerImpl::run(llvm::Module&) +
> 686 7 opt 0x000000000041f8d9 main + 5977 8 libc.so.6
> 0x0000003fea21ed5d __libc_start_main + 253 9 opt
> 0x000000000040ebf9 Stack dump:
> 0. Program arguments: opt -load /net/home/shaheen/llvm/mypass/EstimatePass.so -Epass -time-passes
> test.bc
> 1. Running pass 'Function Pass Manager' on module 'test.bc'.
> 2. Running pass 'Pass' on function '#testfnc1' Segmentation fault
I narrowed down to the issue and it happens when I increment the iterator. But I dont know why.
Here is the test file I am running my pass on:
#include "stdio.h"
void testfnc1(){
int i=1;int j=0;
for(i=1;i<10;i++)
for(j=1;j<10;j++)
printf("test");
};
int main()
{
int i;
printf("hello\n");
for(i=0;i<3;i++){
printf("hello:");
for(i=1;i<4;i++)
printf("asd");}
testfnc1();
}
The problem was that I was using llvm 3.6 while compiling the pass and the bitcode file I was generating was from clang version 3.4.
I just changed the Clang version to 3.6 and its now clompletely working fine.
Thank you

Problems with building the gcc plugin

I am trying to build the simple gcc plugin. I am a newbie, but I want to implement more complicated plugins in the future.
I read a lot of manuals, and it seems that I did everything right, but something is wrong.
I can't build it. Every time I try to build my plugin I get an error:
/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
/tmp/ccjmG33v.o: In function `plugin_init':
plugin.c:(.text+0x9e): undefined reference to `register_callback'
plugin.c:(.text+0xc6): undefined reference to `register_callback'
collect2: ld returned 1 exit status
make: *** [plugin.o] Error 1
I have no idea what is wrong. I performed the same steps as described in all the manuals I found.
I have Ubuntu 12.04 with gcc-4.6.3 compiler.
I installed gcc-4.6-plugin-dev.
I even tried to build the plugin, based on gcc_4.6.4, that was carefully downloaded and built by myself. But the result is the same.
My Makefile:
PLUGINS_DIR = /usr/lib/gcc/i686-linux-gnu/4.6/plugin/include
INCLUDES = \
-I$(PLUGINS_DIR)
DEFINES = -Dbool=int -DTRUE=1 -DFALSE=0
plugin.so : plugin.o
gcc -shared -Wl,-export-dynamic -o plugin.so plugin.o
%.o : %.c
gcc $(DEFINES) $(INCLUDES) -fPIC -o $# $^
clean :
rm *.o *.so
Plugin source code:
#include <aspell.h>
#include <gcc-plugin.h>
#include <coretypes.h>
#include <diagnostic.h>
#include <gimple.h>
#include <tree.h>
#include <tree-flow.h>
#include <tree-pass.h>
#define is_alpha(c) (((c)>64 && (c)<91) || ((c)>96 && (c)<123))
int plugin_is_GPL_compatible = 1;
static AspellSpeller *speller_g;
/* Help info about the plugin if one were to use gcc's --version --help */
static struct plugin_info speller_info =
{
.version = "42",
.help = "Hahahaha yeaaaaa....",
};
static struct plugin_gcc_version speller_ver =
{
.basever = "4.6",
};
/* We don't need to run any tests before we execute our plugin pass */
static bool speller_gate(void)
{
return true;
}
static const_tree is_str_cst(const_tree node)
{
/*
const_tree str = node;
// Filter out types we are ignoring
if (TREE_CODE(str) == VAR_DECL)
{
if (!(str = DECL_INITIAL(node)))
return NULL_TREE;
else if (TREE_OPERAND_LENGTH(str))
str = TREE_OPERAND(str, 0);
}
else if (TREE_CODE(str) == ADDR_EXPR &&
TREE_OPERAND_LENGTH(str) > 0)
str = TREE_OPERAND(str, 0);
if (TREE_CODE(str) != STRING_CST &&
TREE_OPERAND_LENGTH(str) > 0)
str = TREE_OPERAND(str, 0);
if (TREE_CODE(str) != STRING_CST)
return NULL_TREE;
else
return str;
*/
}
static AspellSpeller *init_spellchecker(void)
{
/*
AspellConfig *cfg;
AspellCanHaveError *err;
// Configure and instantiate a spell checker
cfg = new_aspell_config();
aspell_config_replace(cfg, "lang", "en_US");
err = new_aspell_speller(cfg);
if (aspell_error_number(err) != 0)
{
puts(aspell_error_message(err));
return NULL;
}
return to_aspell_speller(err);
*/
}
static void spell_check(const_gimple stmt, const_tree str)
{
/*
char buf[32] = {0};
const char *data, *end;
data = TREE_STRING_POINTER(str);
printf("Spell checking string: \'%s\'\n", data);
while (*data)
{
// Skip non alphas including whitespace
while (!is_alpha(data[0]))
{
if (data[0] == '\0')
return;
++data;
}
// Find the end of the word
end = data;
while (is_alpha(end[0]))
++end;
if ((end - data) > sizeof(buf))
return;
memcpy(buf, data, end - data);
buf[end-data] = '\0';
if (!(aspell_speller_check(speller_g, buf, end - data)))
warning_at(gimple_location(stmt), 0, "%s (bad spelling)", buf);
data = end;
}
*/
}
static unsigned speller_exec(void)
{
/*
unsigned i;
const_tree str, op;
basic_block bb;
gimple stmt;
gimple_stmt_iterator gsi;
FOR_EACH_BB(bb)
for (gsi=gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi))
{
stmt = gsi_stmt(gsi);
for (i=0; i<gimple_num_ops(stmt); ++i)
if ((op = gimple_op(stmt, i)) && (str = is_str_cst(op)))
spell_check(stmt, str);
}
return 0;
*/
}
/* See tree-pass.h for a list and desctiptions for the fields of this struct */
static struct gimple_opt_pass speller_pass =
{
.pass.type = GIMPLE_PASS,
.pass.name = "speller", /* For use in the dump file */
.pass.gate = speller_gate,
.pass.execute = speller_exec, /* Pass handler/callback */
};
/* Return 0 on success or error code on failure */
int plugin_init(struct plugin_name_args *info, /* Argument infor */
struct plugin_gcc_version *ver) /* Version of GCC */
{
struct register_pass_info pass;
if (strncmp(ver->basever, speller_ver.basever, strlen("4.6")))
return -1; /* Incorrect version of gcc */
pass.pass = &speller_pass.pass;
pass.reference_pass_name = "ssa";
pass.ref_pass_instance_number = 1;
pass.pos_op = PASS_POS_INSERT_AFTER;
/* Tell gcc we want to be called after the first SSA pass */
register_callback("speller", PLUGIN_PASS_MANAGER_SETUP, NULL, &pass);
register_callback("speller", PLUGIN_INFO, NULL, &speller_info);
/* Initilize our spell checker */
if (!(speller_g = init_spellchecker()))
return -1;
return 0;
}
The commented source code contains the function calls undefined for the linker too. As I understand, the problem is the same as for the register_callback function.
Could someone help me to cope with this trouble? The good, detailed, not out-of-date, manual about gcc plugins writing would be very useful too.
Any help would be greatly appreciated.
Try changing the second last line of the Makefile to:
%.o : %.c
gcc $(DEFINES) $(INCLUDES) -fPIC -o $# -c $^
Note the "-c" that I have added which tells it to compile, but not link during this phase.
This is exactly an example found online if not mistaken. When compiling the plugin, if gcc prompts that some of the libraries are not found, rather than using -I to specify each library one by one when compiling the plugin, can we use a Makefileto specify all these directories instead? Thanks

Resources