зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
f0594d8b64
Коммит
eff1dbec93
|
@ -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,13 +3035,29 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
|
|||
ParentDC->decls_end());
|
||||
}
|
||||
|
||||
// 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!");
|
||||
|
||||
if (!Result) {
|
||||
if (isa<UsingShadowDecl>(D)) {
|
||||
// UsingShadowDecls can instantiate to nothing because of using hiding.
|
||||
} 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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче