[cfe-dev] Endless operator-> chain causing infinite loop

Richard Smith richard at metafoo.co.uk
Tue Oct 22 14:54:08 PDT 2013


On Tue, Oct 22, 2013 at 2:03 PM, Karen Shaeffer <shaeffer at neuralscape.com>wrote:

> On Tue, Oct 22, 2013 at 12:14:25PM -0700, Richard Smith wrote:
> > On Tue, Oct 22, 2013 at 2:45 AM, Rahul Jain <1989.rahuljain at gmail.com
> >wrote:
> >
> > >
> > > Hi all,
> > >
> > > clang version 3.4 (192772)
> > >
> > > This is with respect to the following gcc testsuite TC:
> > >
> > > template< int n >
> > > struct a {
> > >     a< n+1 > operator->()
> > >         {
> > >         return a< n+1 >();
> > >         }
> > > };
> > >
> > > int main() {
> > >     a<0>()->x;
> > > }
> > >
> > >
> > > This TC goes into an infinite loop when compiled. Ideally it should
> throw
> > > the error
> > > recursive template instantiation exceeded maximum depth of 256.
> > >
> >
> > That's not the right behavior; there's no recursive template
> instantiation
> > here. Each operator-> is instantiated from within the context of 'main',
> > not from within some other instantiation.
> >
> > If we want to limit this, we should put a limit on the number of times we
> > go around the loop looking for an overloaded operator->
> > in Sema::ActOnStartCXXMemberReference. However, I've seen people use this
> > in practice in template metaprogramming to get around the recursive
> > template instantiation depth, so this might break existing code.
>
> Hi Richard,
>
> Just checked, and g++-4.7.2 doesn't give a 'recusive template
> instantiation' error.
> The error is:
>
> error: template instantiation depth exceeds maximum of 900 (use
> -ftemplate-depth= to increase the maximum) instantiating ‘a<(n + 1)>
> a<n>::operator->() [with int n = 900]’
>

This is their recursive template instantiation error. I'm not sure why they
chose to diagnose this problem in that way; there is no recursive
instantiation here. The loop is in [over.ref](13.5.6)p1:

"An expression x->m is interpreted as (x.operator->())->m for a class
object x of type T if T::operator->() exists and if the operator is
selected as the best match function by the overload resolution mechanism."

This rule gets applied repeatedly, outside of any template instantiation.


> In the standard at [temp.inst]
>

> <14.7.1 note d>
> There is an implementation-defined quantity that specifies the limit on
> the total depth
> of recursive instantiations, which could involve more than one template.
> The result of an
> infinite recursion in instantiation is undefined.
>

This is not what's happening in this case. Templates are mainly relevant to
this problem because they make it much more likely to happen (although,
since we already catch operator-> cycles, templates are the only way we can
have a genuinely infinite sequence of operator-> calls). If we had
generated code that looked like this:

struct T { int n; };
struct A0 { T *operator->(); };
struct A1 { A0 operator->(); };
struct A2 { A1 operator->(); };
// ...

A1000 a;
int k = a->n;

... we'd hit into exactly the same resource limitations as with the
templated code, and the same limit should presumably apply here, whatever
it is. (GCC strangely accepts this code while rejecting the corresponding
templated code.)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20131022/8ffe8ccb/attachment.html>


More information about the cfe-dev mailing list