Skip to content

Attempting to assign to a function name produces uncompilable C++ #1101

@WardBrian

Description

@WardBrian

Current Behavior:

The following Stan model compiles in stanc3:

functions {
   real foo(int x){
     return 1.0;
   }

   real bar(int y){
     return 2.0;
   }

   void baz(){
     // NB: putting this in later blocks produce an error due to assigning to a global variable
     foo = bar;
   }
}

model {
     print(foo(1));
    baz();
   print(foo(1));
}

but the C++ fails to compile:

Cmdstan output
Building fun.stan
make: Entering directory '/home/brian/Dev/cpp/cmdstan'
cd /home/brian/Dev/ml/stanc3 && echo "--- Rebuilding stanc ---\n" && dune build @install
--- Rebuilding stanc ---\n
cp /home/brian/Dev/ml/stanc3/_build/default/src/stanc/stanc.exe bin/stanc

--- Translating Stan model to C++ code ---
bin/stanc  --o=../../ml/stanc3/fun.hpp ../../ml/stanc3/fun.stan

--- Compiling, linking C++ code ---
g++ -std=c++1y -pthread -D_REENTRANT -Wno-sign-compare -Wno-ignored-attributes      -I stan/lib/stan_math/lib/tbb_2020.3/include    -O3 -I src -I stan/src -I lib/rapidjson_1.1.0/ -I lib/CLI11-1.9.1/ -I stan/lib/stan_math/ -I stan/lib/stan_math/lib/eigen_3.3.9 -I stan/lib/stan_math/lib/boost_1.75.0 -I stan/lib/stan_math/lib/sundials_6.0.0/include -I stan/lib/stan_math/lib/sundials_6.0.0/src/sundials    -DBOOST_DISABLE_ASSERTS          -c -Wno-ignored-attributes   -x c++ -o ../../ml/stanc3/fun.o ../../ml/stanc3/fun.hpp
In file included from stan/lib/stan_math/stan/math/prim/meta/is_eigen_matrix_base.hpp:6,
                 from stan/lib/stan_math/stan/math/prim/meta/is_eigen.hpp:5,
                 from stan/lib/stan_math/stan/math/prim/meta/base_type.hpp:6,
                 from stan/lib/stan_math/stan/math/prim/meta/return_type.hpp:6,
                 from stan/lib/stan_math/stan/math/prim/meta/append_return_type.hpp:5,
                 from stan/lib/stan_math/stan/math/prim/meta.hpp:176,
                 from stan/lib/stan_math/stan/math/rev/core/accumulate_adjoints.hpp:4,
                 from stan/lib/stan_math/stan/math/rev/core.hpp:4,
                 from stan/lib/stan_math/stan/math/rev.hpp:8,
                 from stan/lib/stan_math/stan/math.hpp:19,
                 from stan/src/stan/model/model_header.hpp:4:
stan/lib/stan_math/stan/math/prim/meta/is_base_pointer_convertible.hpp: In instantiation of ‘struct stan::is_base_pointer_convertible<Eigen::EigenBase, double (&)(const int&, std::basic_ostream<char>*)>’:
stan/lib/stan_math/stan/math/prim/meta/is_var_matrix.hpp:18:8:   recursively required by substitution of ‘template<class T> struct stan::value_type<T, typename std::enable_if<stan::is_eigen<T>::value, void>::type> [with T = double (&)(const int&, std::basic_ostream<char>*)]’
stan/lib/stan_math/stan/math/prim/meta/is_var_matrix.hpp:18:8:   required from ‘struct stan::is_var_matrix<double (&)(const int&, std::basic_ostream<char>*)>’
stan/lib/stan_math/stan/math/prim/meta/conjunction.hpp:17:8:   required from ‘struct stan::math::conjunction<stan::is_var_matrix<double (&)(const int&, std::basic_ostream<char, std::char_traits<char> >*)>, stan::is_eigen<double (&)(const int&, std::basic_ostream<char, std::char_traits<char> >*)> >’
stan/lib/stan_math/stan/math/prim/meta/require_helpers.hpp:63:24:   required by substitution of ‘template<class ... Checks> using require_any_not_t = std::enable_if_t<(! stan::math::conjunction<T>::value)> [with Checks = {stan::is_var_matrix<double (&)(const int&, std::basic_ostream<char, std::char_traits<char> >*)>, stan::is_eigen<double (&)(const int&, std::basic_ostream<char, std::char_traits<char> >*)>}]’
stan/src/stan/model/indexing/access_helpers.hpp:43:65:   required by substitution of ‘template<class T1, class T2, stan::require_any_not_t<stan::is_var_matrix<Container>, stan::is_eigen<T_actual> >* <anonymous> > void stan::model::internal::assign_impl(T1&&, T2&&) [with T1 = double (&)(const int&, std::basic_ostream<char>*); T2 = double (&)(const int&, std::basic_ostream<char>*); stan::require_any_not_t<stan::is_var_matrix<Container>, stan::is_eigen<T_actual> >* <anonymous> = <missing>]’
stan/src/stan/model/indexing/assign.hpp:57:24:   required from ‘void stan::model::assign(T&&, U&&, const char*) [with T = double (&)(const int&, std::basic_ostream<char>*); U = double (&)(const int&, std::basic_ostream<char>*); stan::require_t<std::is_assignable<typename std::decay<_Tp>::type&, typename std::decay<_Func>::type> >* <anonymous> = 0]’
../../ml/stanc3/fun.hpp:73:61:   required from here
stan/lib/stan_math/stan/math/prim/meta/is_base_pointer_convertible.hpp:29:17: error: no matching function for call to ‘stan::is_base_pointer_convertible<Eigen::EigenBase, double (&)(const int&, std::basic_ostream<char>*)>::f(double (*)(const int&, std::basic_ostream<char>*))’
   29 |     = decltype(f(std::declval<std::remove_reference_t<Derived> *>()))::value
      |                ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
stan/lib/stan_math/stan/math/prim/meta/is_base_pointer_convertible.hpp:24:26: note: candidate: ‘static std::false_type stan::is_base_pointer_convertible<Base, Derived>::f(const void*) [with Base = Eigen::EigenBase; Derived = double (&)(const int&, std::basic_ostream<char>*); std::false_type = std::integral_constant<bool, false>]’ <near match>
   24 |   static std::false_type f(const void *);
      |                          ^
stan/lib/stan_math/stan/math/prim/meta/is_base_pointer_convertible.hpp:24:26: note:   conversion of argument 1 would be ill-formed:
stan/lib/stan_math/stan/math/prim/meta/is_base_pointer_convertible.hpp:29:17: error: invalid conversion from ‘double (*)(const int&, std::basic_ostream<char>*)’ to ‘const void*’ [-fpermissive]
   29 |     = decltype(f(std::declval<std::remove_reference_t<Derived> *>()))::value
      |                ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                 |
      |                 double (*)(const int&, std::basic_ostream<char>*)
stan/lib/stan_math/stan/math/prim/meta/is_base_pointer_convertible.hpp:26:25: note: candidate: ‘template<class OtherDerived> static std::true_type stan::is_base_pointer_convertible<Base, Derived>::f(const Base<OtherDerived>*) [with OtherDerived = OtherDerived; Base = Eigen::EigenBase; Derived = double (&)(const int&, std::basic_ostream<char>*)]’
   26 |   static std::true_type f(const Base<OtherDerived> *);
      |                         ^
stan/lib/stan_math/stan/math/prim/meta/is_base_pointer_convertible.hpp:26:25: note:   template argument deduction/substitution failed:
stan/lib/stan_math/stan/math/prim/meta/is_base_pointer_convertible.hpp:29:17: note:   mismatched types ‘const Eigen::EigenBase<Derived>’ and ‘double(const int&, std::basic_ostream<char>*)’
   29 |     = decltype(f(std::declval<std::remove_reference_t<Derived> *>()))::value
      |                ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
make: *** [make/program:58: ../../ml/stanc3/fun] Error 1
make: Leaving directory '/home/brian/Dev/cpp/cmdstan'

Expected Behavior:

At the moment I would expect this to be an error. After something like #742 or lambdas, I would expect the C++ generated to compile.

This is probably a low-priority issue as the cases it comes up are obviously pathological, I just wanted to document it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions