[cfe-dev] Issue 11851

Richard Smith richard at metafoo.co.uk
Thu Mar 22 14:41:36 PDT 2012


Hi Andrew,

On Wed, Mar 21, 2012 at 10:27 AM, Andrew Sutton <asutton.list at gmail.com>wrote:

> > I was going to try to fix this problem, but I'm not sure where to
> > start. What's the right way to ensure that the definition of an
> > instantiated template is available in this context i.e., not deferred?
>
> This solves the problem, but causes a couple regressions.
>
> So, it seems that the problem is that constexpr function template
> calls in the signatures of function templates cannot be evaluated
> because their uses occur in dependent contexts (apparently
> instantiating a function template signature as part of overload
> resolution occurs within the context of the function template being
> instantiated?). The result is that body of the constexpr function
> template isn't instantiated in time to be evaluated, hence the
> substitution failures.
>
> This patch just ensures that definitions are emitted for those calls.
> I tested against the examples given in the bug report, and they seemed
> to compile just fine. I also ran the patch against some of my own
> examples, and they work well. I neglected to include those in the
> patch though.
>
> Unfortunately the patch causes definitions to be emitted for some
> functions that aren't actually used, so I didn't quite get it right.
> Is there a deeper problem, or do the criteria for generating
> definitions just need to be adjusted?


I don't think this patch is quite the right approach -- we should not be
instantiating function template specializations which are called within
unevaluated operands, even if they're constexpr.

One problem is in IsPotentiallyEvaluatedContext: we do not instantiate
functions and variables if they are used within a dependent context. This
causes us to incorrectly reject code such as:

  template<typename T> struct S {
    static const int n;
  };
  template<typename T> const int S<T>::n = sizeof(T);
  template<typename T> void g() {
    int arr[S<int>::n] = { 1, 2, 3, 4 };
  }

It looks like fixing that is sufficient for us to correctly handle
instantiations of constexpr functions triggered by explicitly-specified
template arguments (we treat such substitutions as being in a dependent
context). Interestingly, my testing indicates that g++ instantiates
non-dependent specializations which are odr-used in dependent contexts in
C++11 mode, and does not instantiate them in C++98 mode.

Another problem is that we treat some of the relevant contexts as
unevaluated contexts (in particular, when substituting deduced template
arguments into a declaration), when they are not. This also causes other
bugs, such as our incorrectly accepting this:

template<typename T> void f(T) {
  static_assert(sizeof(T) == 100, "");
}
template<typename T, void(*)(T) = f> struct S {};
template<typename T> S<T> g(T);
void h() { g(0); }

The substitution of T=int into S<T> is incorrectly being treated as an
unevaluated context, resulting in us failing to notice that f<int> is
odr-used and thus failing to instantiate it.

- Richard
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20120322/9ad12c0c/attachment.html>


More information about the cfe-dev mailing list