ticktac-project/tchecker

Compilation fails with g++

osankur opened this issue · 9 comments

I wasn't able to compile the release v0.7 with g++ 10.5.0. I get the following error:

[  8%] Building CXX object src/parsing/program_parser/CMakeFiles/program_parsing_static.dir/program.tab.cc.o
In file included from program.yy:25,
                 from /home/osankur/tools/tchecker/build/src/parsing/program_parser/program.tab.cc:42:
/usr/include/c++/10/limits: In instantiation of ‘struct std::numeric_limits<tchecker::statement_t>’:
/usr/local/include/boost/rational.hpp:123:7:   required from ‘const bool boost::rational_detail::is_compatible_integer<tchecker::statement_t, long int, void>::value’
/usr/local/include/boost/rational.hpp:184:21:   required by substitution of ‘template<class T> constexpr boost::rational<long int>::rational(const T&, const typename boost::enable_if_c<boost::rational_detail::is_compatible_integer<T, long int, void>::value, void>::type*) [with T = tchecker::statement_t]’
program.yy:192:29:   required from ‘void tchecker::parsing::program::parser_t::yy_print_(std::ostream&, const tchecker::parsing::program::parser_t::basic_symbol<Base>&) const [with Base = tchecker::parsing::program::parser_t::by_state; std::ostream = std::basic_ostream<char>]’
/home/osankur/tools/tchecker/build/src/parsing/program_parser/program.tab.cc:696:7:   required from here
/usr/include/c++/10/limits:317:7: error: invalid abstract return type ‘tchecker::statement_t’
  317 |       min() _GLIBCXX_USE_NOEXCEPT { return _Tp(); }
      |       ^~~
In file included from /home/osankur/tools/tchecker/src/../include/tchecker/parsing/parsing.hh:16,
                 from program.yy:31,
                 from /home/osankur/tools/tchecker/build/src/parsing/program_parser/program.tab.cc:42:
/home/osankur/tools/tchecker/src/../include/tchecker/statement/statement.hh:31:7: note:   because the following virtual functions are pure within ‘tchecker::statement_t’:
   31 | class statement_t : private boost::noncopyable {
      |       ^~~~~~~~~~~
/home/osankur/tools/tchecker/src/../include/tchecker/statement/statement.hh:76:26: note:     ‘virtual std::ostream& tchecker::statement_t::do_output(std::ostream&) const’
   76 |   virtual std::ostream & do_output(std::ostream & os) const = 0;
      |                          ^~~~~~~~~
/home/osankur/tools/tchecker/src/../include/tchecker/statement/statement.hh:81:35: note:     ‘virtual tchecker::statement_t* tchecker::statement_t::do_clone() const’
   81 |   virtual tchecker::statement_t * do_clone() const = 0;
      |                                   ^~~~~~~~
/home/osankur/tools/tchecker/src/../include/tchecker/statement/statement.hh:87:16: note:     ‘virtual void tchecker::statement_t::do_visit(tchecker::statement_visitor_t&) const’
   87 |   virtual void do_visit(tchecker::statement_visitor_t & v) const = 0;
      |                ^~~~~~~~
In file included from program.yy:25,
                 from /home/osankur/tools/tchecker/build/src/parsing/program_parser/program.tab.cc:42:
/usr/include/c++/10/limits:321:7: error: invalid abstract return type ‘tchecker::statement_t’
  321 |       max() _GLIBCXX_USE_NOEXCEPT { return _Tp(); }
      |       ^~~
/usr/include/c++/10/limits:327:7: error: invalid abstract return type ‘tchecker::statement_t’
  327 |       lowest() noexcept { return _Tp(); }
      |       ^~~~~~
/usr/include/c++/10/limits:333:7: error: invalid abstract return type ‘tchecker::statement_t’
  333 |       epsilon() _GLIBCXX_USE_NOEXCEPT { return _Tp(); }
      |       ^~~~~~~
/usr/include/c++/10/limits:337:7: error: invalid abstract return type ‘tchecker::statement_t’
  337 |       round_error() _GLIBCXX_USE_NOEXCEPT { return _Tp(); }
      |       ^~~~~~~~~~~
/usr/include/c++/10/limits:341:7: error: invalid abstract return type ‘tchecker::statement_t’
  341 |       infinity() _GLIBCXX_USE_NOEXCEPT { return _Tp(); }
      |       ^~~~~~~~
/usr/include/c++/10/limits:346:7: error: invalid abstract return type ‘tchecker::statement_t’
  346 |       quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return _Tp(); }
      |       ^~~~~~~~~
/usr/include/c++/10/limits:351:7: error: invalid abstract return type ‘tchecker::statement_t’
  351 |       signaling_NaN() _GLIBCXX_USE_NOEXCEPT { return _Tp(); }
      |       ^~~~~~~~~~~~~
/usr/include/c++/10/limits:357:7: error: invalid abstract return type ‘tchecker::statement_t’
  357 |       denorm_min() _GLIBCXX_USE_NOEXCEPT { return _Tp(); }
      |       ^~~~~~~~~~
[...]

This compiles without any issue with clang-10.0.0.

alzeha commented

+1

EDIT: The problem is solved for me. It was sitting in front of the computer and could not read the installation instructions properly.

Hi @alzeha,

How did you fix the problem ? With g++10 the only way I have found to fix it, is to comment the declaration of

std::ostream & operator<<(std::ostream & os, tchecker::clock_rational_value_t v);

in tchecker/basicypes.hh. Up to now I failed to understand why the g++ 10 tries to instantiate struct std::numeric_limits with a non scalar type when this operator<< is declared.

alzeha commented

The first time I tried it, I set the build directory as a subdirectory of tchecker and the installation directory as well. But they have to be next to each other, then it suddenly works.

I have also made the action live on my fork (https://github.com/Echtzeitsysteme/tchecker). So you can take a look inside to see how you have to call the various commands.

Thanks. Your docker image use Boost 1.81 and GCC 12.
I'm trying to solve the problem for the default packages for Ubuntu 22.04 (Boost 1.74 and GCC 10).

alzeha commented

Sure. Locally, I use g++ 11, but also with boost 1.81. I'm sorry I can't help you further.

Hi,

I've reduced the problem to the following lines. Operator << for clock_rational_value_t is used instead of the one declared for statement_t. I don't have a clue why this happens ! If the declarations of operators are reversed the problem disappears.

#include <boost/rational.hpp>

using clock_rational_value_t = boost::rational<int64_t>;

std::ostream & operator<<(std::ostream & os, clock_rational_value_t v);

class statement_t {
public:
  virtual void func() = 0;
};

std::ostream & operator<<(std::ostream & os, statement_t const & stmt);


void f(std::ostream & os, statement_t *s)
{
  os  << *s;
}

Thanks @pictavien , here is a similar example, without boost:

#include <iostream>
#include <limits>
#include <type_traits>

template <class IntType> class rational {
public:
    template <class T>
    rational(const T& n,
             typename std::enable_if_t<std::numeric_limits<T>::is_specialized>::type const * = 0) {}
};

using clock_rational_value_t = rational<int64_t>;

std::ostream & operator<<(std::ostream & os, clock_rational_value_t b);

class statement_t {
public:
    virtual void func() = 0;
};

std::ostream & operator<<(std::ostream & os, statement_t const & s);

void f(std::ostream & os, statement_t * s)
{
    os << *s;
}

I get the same error messages as mentionned in @osankur post above. However, I get no error if the initializer = 0 on the second paramater of constructor rational::rational is removed, or if the first parameter of the constructor is removed.

I finally wrote a simpler, standalone, example:

#include <cstdint>
#include <ostream>

template <class T> class A {
public:
    typedef T type;
    T f() {}
};

template <class IntType> class rational {
public:
    template <class T>
    rational(const T & n, typename A<T>::type const * = nullptr) {}
};

using clock_rational_value_t = rational<int64_t>;

std::ostream & operator<<(std::ostream & os, clock_rational_value_t b);

class statement_t {
public:
    virtual ~statement_t() {}
    virtual void func() = 0;
};

std::ostream & operator<<(std::ostream & os, statement_t const & s);

void f(std::ostream & os, statement_t * s)
{
    os << *s;
}

The compiler message is clearer now:

bar.cc: In instantiation of ‘class A<statement_t>’:
bar.cc:13:5:   required by substitution of ‘template<class T> rational<long int>::rational(const T&, const typename A<T>::type*) [with T = statement_t]’
bar.cc:30:12:   required from here
bar.cc:7:7: error: invalid abstract return type ‘statement_t’
    7 |     T f() {}
      |       ^
bar.cc:20:7: note:   because the following virtual functions are pure within ‘statement_t’:
   20 | class statement_t {
      |       ^~~~~~~~~~~
bar.cc:23:18: note:     ‘virtual void statement_t::func()’
   23 |     virtual void func() = 0;
      |                  ^~~~

What happens is that instruction os << *s in function f calls operator<< on clock_rational_value_t instead of on statement_t const &. Due to = nullptr initializer to the second argument of rational::rational, it looks like implicit conversion constructor clock_rational_value_t::rational<statement_t>(const statement_t &) has higher priority than statement_t const & to chose the variant of operator<< for g++-10. If the constructor of class rational is maked explicit then the error disappears. This is strange.

Finally I have reduced the problem to the following example. g++10 fails to compile it while it works with g++ 12.

#include <limits>

class statement_t {
public:
  virtual void func() = 0;
};

static_assert(! std::numeric_limits<statement_t>::is_specialized);