[cfe-dev] static constexpr member function of a local struct in a function template is instantiated too late

Richard Smith richard at metafoo.co.uk
Wed Aug 20 19:31:02 PDT 2014


On Tue, Aug 12, 2014 at 8:09 PM, Michael Park <mcypark at gmail.com> wrote:

> Hello,
>

Hi and welcome! (And sorry for the delay.)


> I'm new to clang development and was hoping to get some help in tackling
> this bug that I found/filed: http://llvm.org/bugs/show_bug.cgi?id=20625
>
> Example:
>
> template <typename T>
>> void F() {
>>   struct Num {
>>     static constexpr int Get() { return 42; }
>>   };
>>   constexpr int n = Num::Get();
>> }
>> int main() {
>>   F<int>();
>> }
>
>
> The summary of the issue is that the local struct *Num* and its static
> constexpr function *Get* is not yet instantiated when we validate the
> constexpr variable initialization of *n* during *F*'s instantiation.
>
> More details:
>
> *Num* and *Get* gets added to *PendingLocalImplicitInstantiations* in
> *SubstStmt* at *SemaTemplateInstantiationDecl.cpp:3437*, and is
> instantiated later by *PerformPendingInstantiations* at
> *SemaTemplateInstantiationDecl.cpp:3458*. However, the validation of the
> constexpr variable initialization of *n* happens in *SubstStmt* at which
> point we don't yet have the definition of *Get* instantiated.
>
> I'm not exactly sure what the correct approach would be to solve the
> problem. It seems that the local implicit instantiations need to be
> performed earlier, or the validation of constexpr variables need to be
> delayed.
>
> If someone can point me in the right direction it would be appreciated.
>

The implicit instantiations should be performed sooner. (FWIW, the same
problem will affect member functions of local classes that have deduced
return types.) Perhaps the easiest way to address this would be to perform
all the local implicit instantiations discovered while instantiating a
local class when we reach the end of that local class, instead of delaying
them until the end of the surrounding function. We try to delay these
instantiations as much as we can, to reduce the stack usage in recursive
template instantiation, but that's probably not going to be significant
here because there's not likely to be many layers of AST between the
function and the class definition.

One place to put this fix would be around
SemaTemplateInstantiateDecl.cpp:1104:

  // DR1484 clarifies that the members of a local class are instantiated as
part
  // of the instantiation of their enclosing entity.
  if (D->isCompleteDefinition() && D->isLocalClass()) {
    SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs,
                             TSK_ImplicitInstantiation,
                             /*Complain=*/true);
    SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,
                                    TSK_ImplicitInstantiation);
  }

You could save, perform, and restore the pending local implicit
instantiations around these calls.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20140820/20a29db4/attachment.html>


More information about the cfe-dev mailing list