Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Jason_B_
Beginner
52 Views

Assertion failed in templates.c at line 30947

I received the following compiler error using Intel C++ compiler 17.0 under Visual Studio 2015 Update 3:

error : assertion failed at: "shared/cfe/edgcpfe/templates.c", line 30947

template <typename T, typename... Vs>
   class task_t  : public task_base_t
      {
      static auto task_relay(const T& t, Vs&& ...params)
         {
         return t(std::forward<Vs>(params)...);
         }
      using task_result_t = decltype(task_relay(std::declval<T>(), std::declval<Vs>()...)); // assertion failure

      ...

This assertion failure does not present under Intel C++ compiler 17.0 under Visual Studio 2013 Update 5.

The workaround for this issue is revising the using statement thusly:

      using task_result_t = decltype(std::declval<T>()(std::forward<Vs>(std::declval<Vs>())...));

Hopefully, this can be resolved in an upcoming patch release.

Regards,

Jason 

0 Kudos
5 Replies
Judith_W_Intel
Employee
52 Views

 

Hi Jason,

Please post or attach a complete (compilable) example. The easiest way to do that is to preprocess the file (using the same commands as you used to compile it but add -E or -P) and attach the resulting preprocessed file which will have all the header files and macros expanded.

I'm sorry to tell you that if this isn't already fixed then it is too late for the next upcoming 17.0 update. I'm glad to hear you have a workaround in the meantime.

thanks!

Judy

Jason_B_
Beginner
52 Views

Hi Judith,

Unfortunately, the addition of either -E or -P appears to mask whatever is triggering the assertion failure. I was, however, able to distill the bug to a very succinct repro case which I have attached here. Hopefully, this will prove sufficient for your dev team.

For reference, I did include the .i output (-P) despite having not experienced the assertion error output when this option was applied.

Here is the full output of the assertion text:

1>Bug30947.cpp(18): error : assertion failed at: "shared/cfe/edgcpfe/templates.c", line 30947

1>
1>          using task_result_t = decltype(task_relay(std::declval<T>(), std::declval<Vs>()...));
1>                                         ^

 

This code also triggers the assertion failure:

 

using task_result_t = std::result_of<decltype(task_relay)&(T, Vs...)>::type;
1>Bug30947.cpp(18): error : assertion failed at: "shared/cfe/edgcpfe/templates.c", line 30947
1>
1>          using task_result_t = std::result_of<decltype(task_relay)&(T, Vs...)>::type;
1>                                                        ^

Hope this information proves helpful.

Thank you.

Jason

Judith_W_Intel
Employee
52 Views

Hi Jason.

Thanks for the reproducer. I have good news and bad news...

I was able to reproduce the internal error and reduced it down to this test case:

template <typename T>
class task_t
{
  static auto task_relay(const T& t) { return 0; }
  using task_result_t = decltype(task_relay(T()));
};

int main()
{
   task_t<int> t;
   return 0;
}

We just fixed this bug, here is a description of the fix:

2/3/17
Function with deduced return type as template static data member initializer

An internal error (in force_instantiation_to_deduce_return_type) could
result if a static member function with a deduced return type was used
in a way that required the return type to be determined, and that use was
in a context that was part of the "normal" parsing of the class template
(i.e., not one of the contexts in which parsing is done once the class
definition is complete).  This usage is not allowed in normal (non-template)
classes and the validity in class templates is unclear.  The front end now
accepts this usage pending possible clarification by the standards committee.

  template <class ...> struct A {
    static auto f() {}
    static constexpr auto I = f;
  };
  auto g () -> A<>;
  int main() {
    g();
  }

Unfortunately this fix was made too late for the upcoming 17.0 update.

Note that if task_t was not a template class a valid compilation error would occur (with both cl and icl) so that is why this usage is
questionable...

Judy

Jason_B_
Beginner
52 Views

Great write up and fascinating.

I understand the ambiguity now (in the context of parsing a template class). Though, in my mind, a template expansion should be able to resolve the return type provided the static member is both declared and visible at the time of deduction (it would seem cl, gcc, and clang also agree). I do agree, however, that the inconsistency presented between the template vs non-template class case presents a logical conundrum and despite the rationale for allowing it, consistency almost asks that it not be. More fodder for the committee!

Glad to hear this is resolved. We have a reasonable workaround for the moment. Given the explanation here - we have an even better option by just moving the static member out of the enclosing class which resolves the issue and works in all cases. Private encapsulation can be achieved by enclosing the static method in a helper friend class.

template <typename T>
class task_helper_t
{
  static auto task_relay(const T& t) { return 0; }
  template <class T> friend class task_t;
};

template <typename T>
class task_t
{
  using task_result_t = decltype(task_helper_t<T>::task_relay(T()));
};

int main()
{
   task_t<int> t;
   return 0;
}

Win!

Will have something to look forward to in Update 3 (or 18.x which ever happens first). Thanks for the follow up on this and the lesson in type deduction of static members!

J

 

Jason_B_
Beginner
52 Views

Confirmed this "bug" has been fixed in Update 4.