Instantiate local class at the end of its definition

Michael Park mcypark at gmail.com
Mon Feb 23 00:08:06 PST 2015


Hi Richard,

I forgot about this for long time but I had a chance this weekend to
revisit it.

I've added the part to save and restore the pending local instantiations
around the calls to instantiate the class body and its members. But I'm
uncertain whether we need/want the vtable related code here since I don't
think we actually have a way to use the vtable in this context. It also
seems that we don't need an instance of *LocalInstantiationScope* here
since we don't have any template parameters to store at this level.

Sorry for the delay in the follow-up, once I get feedback from you the
subsequent ones will be much quicker.

Thanks,

MPark.




On 29 September 2014 at 11:05, Richard Smith <richard at metafoo.co.uk> wrote:

> On Tue, Sep 23, 2014 at 2:33 PM, Michael Park <mcypark at gmail.com> wrote:
>
>> I tried adding *LocalInstantiationScope* around
>> *PerformPendingInstantiation*, like so:
>>
>> // A static constexpr member function of a local class can be used in
>>> // a constexpr expression right after the local class' definition.
>>> // We need to instantiate them now, otherwise it may be too late.
>>> LocalInstantiationScope Local(SemaRef);
>>> SemaRef.PerformPendingInstantiations(/*LocalOnly=*/true);
>>> Local.Exit();
>>
>>
>> but it didn't seem to work. I'm not sure what I'm missing here. Could you
>> give me a hint please?
>>
>
> This is the bit I was referring to:
>
>   SavePendingLocalImplicitInstantiationsRAII
>       SavedPendingLocalImplicitInstantiations(*this);
>   std::unique_ptr<SavePendingInstantiationsAndVTableUsesRAII>
>       SavePendingInstantiationsAndVTableUses;
>   if (Recursive) {
>     SavePendingInstantiationsAndVTableUses.reset(
>         new SavePendingInstantiationsAndVTableUsesRAII(*this));
>   }
>
> [...]
>
>   PerformPendingInstantiations(/*LocalOnly=*/true);
>   Scope.Exit();
>
>   if (Recursive) {
>     // Define any pending vtables.
>     DefineUsedVTables();
>
>     // Instantiate any pending implicit instantiations found during the
>     // instantiation of this template.
>     PerformPendingInstantiations();
>
>     // Restore PendingInstantiations and VTableUses.
>     SavePendingInstantiationsAndVTableUses.reset();
>   }
>
>
>
>> Thanks
>>
>> On 25 August 2014 01:30, Richard Smith <richard at metafoo.co.uk> wrote:
>>
>>> It would be better to save and restore the pending local instantiations
>>> around the calls to instantiate the class body and its members, as we do
>>> elsewhere when we perform local pending instantiations.
>>>
>>>
>>> On Fri, Aug 22, 2014 at 2:41 AM, Michael Park <mcypark at gmail.com> wrote:
>>>
>>>> Fixes http://llvm.org/bugs/show_bug.cgi?id=20625
>>>>
>>>> _______________________________________________
>>>> cfe-commits mailing list
>>>> cfe-commits at cs.uiuc.edu
>>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>>>
>>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150223/7fd65c5f/attachment.html>
-------------- next part --------------
diff --git lib/Sema/SemaTemplateInstantiateDecl.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp
index 1df0701..6980769 100644
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1265,11 +1265,19 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
   // 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()) {
+    Sema::SavePendingLocalImplicitInstantiationsRAII
+        SavedPendingLocalImplicitInstantiations(SemaRef);
+
     SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs,
                              TSK_ImplicitInstantiation,
                              /*Complain=*/true);
+
     SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,
                                     TSK_ImplicitInstantiation);
+
+    // This class may have local implicit instantiations that need to be
+    // performed within this scope.
+    SemaRef.PerformPendingInstantiations(/*LocalOnly=*/true);
   }
 
   SemaRef.DiagnoseUnusedNestedTypedefs(Record);
diff --git test/SemaTemplate/instantiate-local-class.cpp test/SemaTemplate/instantiate-local-class.cpp
index c9897b9..a945c01 100644
--- test/SemaTemplate/instantiate-local-class.cpp
+++ test/SemaTemplate/instantiate-local-class.cpp
@@ -194,3 +194,16 @@ struct B {
   void f() { F<int>(); }
 };
 }
+
+namespace PR20625 {
+template <typename T>
+void f() {
+  struct N {
+    static constexpr int get() { return 42; }
+  };
+  constexpr int n = N::get();
+  static_assert(n == 42, "n == 42");
+}
+
+void g() { f<void>(); }
+}


More information about the cfe-commits mailing list