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

llvm-svn: 236426
This commit is contained in:
Serge Pavlov 2015-05-04 16:44:39 +00:00
parent 19f731f0ea
commit 4c51174677
3 changed files with 142 additions and 0 deletions

View File

@ -2788,6 +2788,11 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
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))
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.

View File

@ -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<TagDecl>(D)) {
Decl *Inst = SubstDecl(D, CurContext, TemplateArgs);
CurrentInstantiationScope->InstantiatedLocal(D, Inst);
return cast<TypeDecl>(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<LabelDecl>(D));

View File

@ -213,3 +213,132 @@ namespace PR23194 {
return make_seed_pair();
}
}
namespace PR18653 {
// Forward declarations
template<typename T> void f1() {
void g1(struct x1);
struct x1 {};
}
template void f1<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 f2<int>();
template<typename T> void f3() {
void g3(enum class x3);
enum class x3 { nothing };
}
template void f3<int>();
template<typename T> void f4() {
void g4(struct x4 {} x); // expected-error{{'x4' cannot be defined in a parameter type}}
}
template void f4<int>();
template <class T> void f();
template <class T> struct S1 {
void m() {
f<class newclass>();
}
};
template struct S1<int>;
template <class T> struct S2 {
void m() {
f<enum new_enum>(); // expected-error{{ISO C++ forbids forward references to 'enum' types}}
}
};
template struct S2<int>;
template <class T> struct S3 {
void m() {
f<enum class new_enum>();
}
};
template struct S3<int>;
template <class T> struct S4 {
struct local {};
void m() {
f<local>();
}
};
template struct S4<int>;
template <class T> struct S5 {
enum local { nothing };
void m() {
f<local>();
}
};
template struct S5<int>;
template <class T> struct S7 {
enum class local { nothing };
void m() {
f<local>();
}
};
template struct S7<int>;
template <class T> void fff(T *x);
template <class T> struct S01 {
struct local { };
void m() {
local x;
fff(&x);
}
};
template struct S01<int>;
template <class T> struct S02 {
enum local { nothing };
void m() {
local x;
fff(&x);
}
};
template struct S02<int>;
template <class T> struct S03 {
enum class local { nothing };
void m() {
local x;
fff(&x);
}
};
template struct S03<int>;
template <class T> struct S04 {
void m() {
struct { } x;
fff(&x);
}
};
template struct S04<int>;
template <class T> struct S05 {
void m() {
enum { nothing } x;
fff(&x);
}
};
template struct S05<int>;
template <class T> struct S06 {
void m() {
class { virtual void mmm() {} } x;
fff(&x);
}
};
template struct S06<int>;
}