Starting from r236426 FindInstantiatedDecl may instantiate types that
are referenced before definition. This change limit the set of types
that can be instantiated by this function.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@237434
91177308-0d34-0410-b5e6-
96231b3b80d8
isa<TemplateTemplateParmDecl>(D))
return nullptr;
- // Tag type may be referenced prior to definition, in this case it does not
- // have instantiation yet.
- if (isa<TagDecl>(D))
+ // Local types referenced prior to definition may require instantiation.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
+ if (RD->isLocalClass())
+ return nullptr;
+
+ // Enumeration types referenced prior to definition may appear as a result of
+ // error recovery.
+ if (isa<EnumDecl>(D))
return nullptr;
// If we didn't find the decl, then we either have a sema bug, or we have a
if (D->isInvalidDecl())
return nullptr;
- // Tag type may be referenced prior to definition, in this case it must be
- // instantiated now.
- if (isa<TagDecl>(D)) {
+ // Normally this function only searches for already instantiated declaration
+ // however we have to make an exclusion for local types used before
+ // definition as in the code:
+ //
+ // template<typename T> void f1() {
+ // void g1(struct x1);
+ // struct x1 {};
+ // }
+ //
+ // In this case instantiation of the type of 'g1' requires definition of
+ // 'x1', which is defined later. Error recovery may produce an enum used
+ // before definition. In these cases we need to instantiate relevant
+ // declarations here.
+ bool NeedInstantiate = false;
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
+ NeedInstantiate = RD->isLocalClass();
+ else
+ NeedInstantiate = isa<EnumDecl>(D);
+ if (NeedInstantiate) {
Decl *Inst = SubstDecl(D, CurContext, TemplateArgs);
CurrentInstantiationScope->InstantiatedLocal(D, Inst);
return cast<TypeDecl>(Inst);
}
template void f1<int>();
+ template<typename T> void f1a() {
+ void g1(union x1);
+ union x1 {};
+ }
+ template void f1a<int>();
+
template<typename T> void f2() {
void g2(enum x2); // expected-error{{ISO C++ forbids forward references to 'enum' types}}
enum x2 { nothing };
}
template void f4<int>();
+ template<typename T> void f4a() {
+ void g4(union x4 {} x); // expected-error{{'x4' cannot be defined in a parameter type}}
+ }
+ template void f4a<int>();
+
template <class T> void f();
template <class T> struct S1 {
void m() {
f<class newclass>();
+ f<union newunion>();
}
};
template struct S1<int>;
};
template struct S4<int>;
+ template <class T> struct S4a {
+ union local {};
+ void m() {
+ f<local>();
+ }
+ };
+ template struct S4a<int>;
+
template <class T> struct S5 {
enum local { nothing };
void m() {
};
template struct S01<int>;
+ template <class T> struct S01a {
+ union local { };
+ void m() {
+ local x;
+ fff(&x);
+ }
+ };
+ template struct S01a<int>;
+
template <class T> struct S02 {
enum local { nothing };
void m() {
};
template struct S04<int>;
+ template <class T> struct S04a {
+ void m() {
+ union { } x;
+ fff(&x);
+ }
+ };
+ template struct S04a<int>;
+
template <class T> struct S05 {
void m() {
enum { nothing } x;