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. 


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127129 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2011-03-06 20:12:45 +00:00
Родитель f0594d8b64
Коммит eff1dbec93
3 изменённых файлов: 54 добавлений и 7 удалений

Просмотреть файл

@ -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_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_name_of_class : Error<"member %0 has the same name as its class">;
def err_member_def_undefined_record : Error<

Просмотреть файл

@ -3001,11 +3001,14 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// If our context used to be dependent, we may need to instantiate
// it before performing lookup into that context.
bool IsBeingInstantiated = false;
if (CXXRecordDecl *Spec = dyn_cast<CXXRecordDecl>(ParentDC)) {
if (!Spec->isDependentContext()) {
QualType T = Context.getTypeDeclType(Spec);
const RecordType *Tag = T->getAs<RecordType>();
assert(Tag && "type of non-dependent record is not a RecordType");
if (Tag->isBeingDefined())
IsBeingInstantiated = true;
if (!Tag->isBeingDefined() &&
RequireCompleteType(Loc, T, diag::err_incomplete_type))
return 0;
@ -3032,12 +3035,28 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
ParentDC->decls_end());
}
if (!Result) {
if (isa<UsingShadowDecl>(D)) {
// UsingShadowDecls can instantiate to nothing because of using hiding.
// Note: this assertion end up firing in invalid code even when none of the
// AST invariants have been broken, so we explicitly check whether any
// errors have been emitted
assert((Result || isa<UsingShadowDecl>(D) || Diags.hasErrorOccurred()) &&
"Unable to find instantiation of declaration!");
} else if (Diags.hasErrorOccurred()) {
// We've already complained about something, so most likely this
// 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;
}

Просмотреть файл

@ -1,5 +1,28 @@
// 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>
class X {
public: