We may fail to map a declaration in a template to its instantiated

declaration because of interesting ordering dependencies while
instantiating a class template or member class thereof. Complain,
rather than asserting (+Asserts) or silently rejecting the code
(-Asserts).

Fixes the crash-on-invalid in PR8965. 

llvm-svn: 127129
This commit is contained in:
Douglas Gregor 2011-03-06 20:12:45 +00:00
parent d9bb152821
commit 528ad93924
3 changed files with 54 additions and 7 deletions

View File

@ -2439,6 +2439,11 @@ def warn_subscript_is_char : Warning<"array subscript is of type 'char'">,
def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">; def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">;
def err_no_member : Error<"no member named %0 in %1">; def err_no_member : Error<"no member named %0 in %1">;
def err_member_not_yet_instantiated : Error<
"no member %0 in %1; it has not yet been instantiated">;
def note_non_instantiated_member_here : Note<
"not-yet-instantiated member is declared here">;
def err_member_redeclared : Error<"class member cannot be redeclared">; def err_member_redeclared : Error<"class member cannot be redeclared">;
def err_member_name_of_class : Error<"member %0 has the same name as its class">; def err_member_name_of_class : Error<"member %0 has the same name as its class">;
def err_member_def_undefined_record : Error< def err_member_def_undefined_record : Error<

View File

@ -3001,11 +3001,14 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// If our context used to be dependent, we may need to instantiate // If our context used to be dependent, we may need to instantiate
// it before performing lookup into that context. // it before performing lookup into that context.
bool IsBeingInstantiated = false;
if (CXXRecordDecl *Spec = dyn_cast<CXXRecordDecl>(ParentDC)) { if (CXXRecordDecl *Spec = dyn_cast<CXXRecordDecl>(ParentDC)) {
if (!Spec->isDependentContext()) { if (!Spec->isDependentContext()) {
QualType T = Context.getTypeDeclType(Spec); QualType T = Context.getTypeDeclType(Spec);
const RecordType *Tag = T->getAs<RecordType>(); const RecordType *Tag = T->getAs<RecordType>();
assert(Tag && "type of non-dependent record is not a RecordType"); assert(Tag && "type of non-dependent record is not a RecordType");
if (Tag->isBeingDefined())
IsBeingInstantiated = true;
if (!Tag->isBeingDefined() && if (!Tag->isBeingDefined() &&
RequireCompleteType(Loc, T, diag::err_incomplete_type)) RequireCompleteType(Loc, T, diag::err_incomplete_type))
return 0; return 0;
@ -3032,13 +3035,29 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
ParentDC->decls_end()); ParentDC->decls_end());
} }
// UsingShadowDecls can instantiate to nothing because of using hiding. if (!Result) {
// Note: this assertion end up firing in invalid code even when none of the if (isa<UsingShadowDecl>(D)) {
// AST invariants have been broken, so we explicitly check whether any // UsingShadowDecls can instantiate to nothing because of using hiding.
// errors have been emitted } else if (Diags.hasErrorOccurred()) {
assert((Result || isa<UsingShadowDecl>(D) || Diags.hasErrorOccurred()) && // We've already complained about something, so most likely this
"Unable to find instantiation of declaration!"); // declaration failed to instantiate. There's no point in complaining
// further, since this is normal in invalid code.
} else if (IsBeingInstantiated) {
// The class in which this member exists is currently being
// instantiated, and we haven't gotten around to instantiating this
// member yet. This can happen when the code uses forward declarations
// of member classes, and introduces ordering dependencies via
// template instantiation.
Diag(Loc, diag::err_member_not_yet_instantiated)
<< D->getDeclName()
<< Context.getTypeDeclType(cast<CXXRecordDecl>(ParentDC));
Diag(D->getLocation(), diag::note_non_instantiated_member_here);
} else {
// We should have found something, but didn't.
llvm_unreachable("Unable to find instantiation of declaration!");
}
}
D = Result; D = Result;
} }

View File

@ -1,5 +1,28 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s // RUN: %clang_cc1 -fsyntax-only -verify %s
namespace PR8965 {
template<typename T>
struct X {
typedef int type;
T field; // expected-note{{in instantiation of member class}}
};
template<typename T>
struct Y {
struct Inner;
typedef typename X<Inner>::type // expected-note{{in instantiation of template class}}
type; // expected-note{{not-yet-instantiated member is declared here}}
struct Inner {
typedef type field; // expected-error{{no member 'type' in 'PR8965::Y<int>'; it has not yet been instantiated}}
};
};
Y<int> y; // expected-note{{in instantiation of template class}}
}
template<typename T> template<typename T>
class X { class X {
public: public: