Summary: | [4.8/4.9 Regression] Introducing an unrelated template parameter causes compilation to fail | ||
---|---|---|---|
Product: | gcc | Reporter: | Max Gerlach <m> |
Component: | c++ | Assignee: | Jason Merrill <jason> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | daniel.kruegler, jakub, jason |
Priority: | P2 | Keywords: | rejects-valid |
Version: | 4.9.1 | ||
Target Milestone: | 4.9.3 | ||
Host: | Target: | ||
Build: | Known to work: | 4.6.3, 4.7.3 | |
Known to fail: | 4.8.2, 4.8.3, 4.9.1 | Last reconfirmed: | 2014-09-06 00:00:00 |
Attachments: |
Archive containing output.txt, arma_template_test.ii and arma_no_template_test.ii
Compiler error messages from g++ 4.9.1 |
Description
Max Gerlach
2014-08-25 13:52:46 UTC
Confirmed on g++ 4.8.3, Fedora 20, 64 bit. gcc version 4.8.3 20140624 (Red Hat 4.8.3-1) (GCC) When the irrelevant template parameter is used (arma_template_test.ii), g++ thinks that "value" in the following code can't be determined at compile time: template<typename T> struct is_Col_fixed_only { typedef char yes[1]; typedef char no[2]; template<typename X> static yes& check(typename X::Col_fixed_type*); template<typename> static no& check(...); static const bool value = ( sizeof(check<T>(0)) == sizeof(yes) ); }; Created attachment 33397 [details]
Compiler error messages from g++ 4.9.1
The bug is still present on g++ 4.9.1. $ g++-4.9 --version g++-4.9 (Ubuntu 4.9.1-3ubuntu2~14.04.1) 4.9.1 Copyright (C) 2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Output of $ g++-4.9 -c arma_template_test.cpp -Wall -Wextra -std=c++11 &> output-4.9.1.txt has been attached. gcc 4.7.3 compiles the code without errors. $ g++-4.7 --version g++-4.7 (Ubuntu/Linaro 4.7.3-12ubuntu1) 4.7.3 Copyright (C) 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. This started to be rejected with r197613 (one needs -std=c++11 -mfxsr to compile it BTW). Whether it is valid or not I'll defer to the C++ folks. The problem with this testcase is that in evaluating arma::is_Mat_fixed_only<arma::eOp<arma::Col<double>, arma::eop_exp> >::value we need to look up check<arma::eOp<arma::Col<double>, arma::eop_exp>>, which means looking up arma::eOp<arma::Col<double>, arma::eop_exp>::Mat_fixed_type, which means instantiating arma::eOp<arma::Col<double>, arma::eop_exp> if it isn't already complete. Which means instantiating arma::Base<double, arma::eOp<arma::Col<double>, arma::eop_exp>> Which means substituting into arma::Base_eval<elem_type, derived, arma::is_Mat<derived>::value> Which depends on arma::is_Mat_fixed_only<arma::eOp<arma::Col<double>, arma::eop_exp> >::value, which is where we started. So instantiating the decl ends up requiring its own definition, though the actual value does not depend on itself, so we could probably allow it. The loop would be avoided if arma::eOp<arma::Col<double>, arma::eop_exp> is instantiated before we try to instantiate the value. Here's a simpler testcase that doesn't happen to fail with GCC for some reason, but does with clang: template <class T> struct B; template <bool b> struct C { }; template <class T> struct A: C<B<A<T>>::value> { typedef T Type; }; template<class T> struct B { template<typename X> static int check(typename X::Type*); template<typename> static char check(...); static const bool value = (sizeof(check<T>(0)) == sizeof(int)); }; int main() { return B<A<int>>::value; } And here's a reduced testcase that GCC and EDG reject, but clang accepts. template <typename T> struct Test { template <typename X> static void check(typename X::Undefined *); template <typename> static int &check(...); static const int value = sizeof (check<T>()); }; template <int> struct Sink { }; template <typename T> struct Base : Sink<Test<T>::value> {}; template <typename T> class Derived : Base<Derived<T> > {}; int i[Test<Derived<int> >::value]; And one rejected by all of GCC, Clang and EDG (but also accepted by 4.7): template <typename T> struct Test { template<typename X> static int check(typename X::Type*); template<typename> static char check(...); static const int value = sizeof(check<T>(0)); }; template <int> struct Sink { }; template <typename T> class Derived : Sink<Test<Derived<T> >::value> {}; Sink<Test<Derived<int> >::value> s; If we somehow cause Derived<int> to be instantiated before the last line, such as by declaring a Derived<int> variable, everything is fine. We only run into trouble because it hasn't been. r197613 caused this to start breaking because before that change we had briefly been instantiating classes in more situations, but that caused its own problems. It's not clear to me that this needs to be ill-formed; the value is not dependent on itself, it's just an accident of instantiation context. We could decide to just handle this. I think I'll make that change and also bring it up with the committee. Author: jason Date: Tue Sep 9 11:59:45 2014 New Revision: 215062 URL: https://gcc.gnu.org/viewcvs?rev=215062&root=gcc&view=rev Log: PR c++/62255 * pt.c (instantiate_decl): Handle recursive instantiation of static data member. Added: trunk/gcc/testsuite/g++.dg/template/recurse4.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/pt.c GCC 4.8.4 has been released. Author: jason Date: Thu Feb 26 02:43:58 2015 New Revision: 220997 URL: https://gcc.gnu.org/viewcvs?rev=220997&root=gcc&view=rev Log: PR c++/62255 * pt.c (instantiate_decl): Handle recursive instantiation of static data member. Added: branches/gcc-4_9-branch/gcc/testsuite/g++.dg/template/recurse4.C Modified: branches/gcc-4_9-branch/gcc/cp/ChangeLog branches/gcc-4_9-branch/gcc/cp/pt.c Fixed for 4.9.3/5. |