From 377b2211f7b8a5ec26b59cc4fe3d168ee1292258 Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Mon, 4 May 2015 16:44:39 +0000 Subject: [PATCH] Instantiate incomplete class used in template method. If a class is absent from instantiation and is incomplete, instantiate it as an incomplete class thus avoiding compiler crash. This change fixes PR18653. Differential Revision: http://reviews.llvm.org/D8281 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@236426 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaTemplateInstantiate.cpp | 5 + lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 ++ test/SemaTemplate/instantiate-local-class.cpp | 129 ++++++++++++++++++ 3 files changed, 142 insertions(+) diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 62b506276e..1874782553 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -2788,6 +2788,11 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) { isa(D)) return nullptr; + // Tag type may be referenced prior to definition, in this case it does not + // have instantiation yet. + if (isa(D)) + return nullptr; + // If we didn't find the decl, then we either have a sema bug, or we have a // forward reference to a label declaration. Return null to indicate that // we have an uninstantiated label. diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 8f2e95a615..41245d9b3f 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4434,6 +4434,14 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (D->isInvalidDecl()) return nullptr; + // Tag type may be referenced prior to definition, in this case it must be + // instantiated now. + if (const TagDecl *TD = dyn_cast(D)) { + Decl *Inst = SubstDecl(D, CurContext, TemplateArgs); + CurrentInstantiationScope->InstantiatedLocal(D, Inst); + return cast(Inst); + } + // If we didn't find the decl, then we must have a label decl that hasn't // been found yet. Lazily instantiate it and return it now. assert(isa(D)); diff --git a/test/SemaTemplate/instantiate-local-class.cpp b/test/SemaTemplate/instantiate-local-class.cpp index 367134a2a5..3365c37407 100644 --- a/test/SemaTemplate/instantiate-local-class.cpp +++ b/test/SemaTemplate/instantiate-local-class.cpp @@ -213,3 +213,132 @@ namespace PR23194 { return make_seed_pair(); } } + +namespace PR18653 { + // Forward declarations + + template void f1() { + void g1(struct x1); + struct x1 {}; + } + template void f1(); + + template void f2() { + void g2(enum x2); // expected-error{{ISO C++ forbids forward references to 'enum' types}} + enum x2 { nothing }; + } + template void f2(); + + template void f3() { + void g3(enum class x3); + enum class x3 { nothing }; + } + template void f3(); + + + template void f4() { + void g4(struct x4 {} x); // expected-error{{'x4' cannot be defined in a parameter type}} + } + template void f4(); + + + template void f(); + template struct S1 { + void m() { + f(); + } + }; + template struct S1; + + template struct S2 { + void m() { + f(); // expected-error{{ISO C++ forbids forward references to 'enum' types}} + } + }; + template struct S2; + + template struct S3 { + void m() { + f(); + } + }; + template struct S3; + + template struct S4 { + struct local {}; + void m() { + f(); + } + }; + template struct S4; + + template struct S5 { + enum local { nothing }; + void m() { + f(); + } + }; + template struct S5; + + template struct S7 { + enum class local { nothing }; + void m() { + f(); + } + }; + template struct S7; + + + template void fff(T *x); + template struct S01 { + struct local { }; + void m() { + local x; + fff(&x); + } + }; + template struct S01; + + template struct S02 { + enum local { nothing }; + void m() { + local x; + fff(&x); + } + }; + template struct S02; + + template struct S03 { + enum class local { nothing }; + void m() { + local x; + fff(&x); + } + }; + template struct S03; + + + template struct S04 { + void m() { + struct { } x; + fff(&x); + } + }; + template struct S04; + + template struct S05 { + void m() { + enum { nothing } x; + fff(&x); + } + }; + template struct S05; + + template struct S06 { + void m() { + class { virtual void mmm() {} } x; + fff(&x); + } + }; + template struct S06; +} -- 2.40.0