Clean up and simplify RequireCompleteType.

No functional change intended, except that we will now produce more
"declared here" notes.

llvm-svn: 339187
This commit is contained in:
Richard Smith 2018-08-07 21:35:41 +00:00
parent 51ed131ed2
commit 96cb356911
4 changed files with 44 additions and 58 deletions

View File

@ -209,11 +209,13 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
if (!tag || tag->isDependentContext())
return false;
// Grab the tag definition, if there is one.
QualType type = Context.getTypeDeclType(tag);
tag = type->getAsTagDecl();
// If we're currently defining this type, then lookup into the
// type is okay: don't complain that it isn't complete yet.
QualType type = Context.getTypeDeclType(tag);
const TagType *tagType = type->getAs<TagType>();
if (tagType && tagType->isBeingDefined())
if (tag->isBeingDefined())
return false;
SourceLocation loc = SS.getLastQualifierNameLoc();
@ -229,13 +231,13 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
// Fixed enum types are complete, but they aren't valid as scopes
// until we see a definition, so awkwardly pull out this special
// case.
const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType);
if (!enumType)
auto *EnumD = dyn_cast<EnumDecl>(tag);
if (!EnumD)
return false;
if (enumType->getDecl()->isCompleteDefinition()) {
if (EnumD->isCompleteDefinition()) {
// If we know about the definition but it is not visible, complain.
NamedDecl *SuggestedDef = nullptr;
if (!hasVisibleDefinition(enumType->getDecl(), &SuggestedDef,
if (!hasVisibleDefinition(EnumD, &SuggestedDef,
/*OnlyNeedComplete*/false)) {
// If the user is going to see an error here, recover by making the
// definition visible.
@ -249,11 +251,11 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
// Try to instantiate the definition, if this is a specialization of an
// enumeration temploid.
EnumDecl *ED = enumType->getDecl();
if (EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
MemberSpecializationInfo *MSI = ED->getMemberSpecializationInfo();
if (EnumDecl *Pattern = EnumD->getInstantiatedFromMemberEnum()) {
MemberSpecializationInfo *MSI = EnumD->getMemberSpecializationInfo();
if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) {
if (InstantiateEnum(loc, ED, Pattern, getTemplateInstantiationArgs(ED),
if (InstantiateEnum(loc, EnumD, Pattern,
getTemplateInstantiationArgs(EnumD),
TSK_ImplicitInstantiation)) {
SS.SetInvalid(SS.getRange());
return true;

View File

@ -7684,39 +7684,24 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
return false;
}
const TagType *Tag = T->getAs<TagType>();
const ObjCInterfaceType *IFace = T->getAs<ObjCInterfaceType>();
TagDecl *Tag = dyn_cast_or_null<TagDecl>(Def);
ObjCInterfaceDecl *IFace = dyn_cast_or_null<ObjCInterfaceDecl>(Def);
// If there's an unimported definition of this type in a module (for
// instance, because we forward declared it, then imported the definition),
// import that definition now.
//
// FIXME: What about other cases where an import extends a redeclaration
// chain for a declaration that can be accessed through a mechanism other
// than name lookup (eg, referenced in a template, or a variable whose type
// could be completed by the module)?
//
// FIXME: Should we map through to the base array element type before
// checking for a tag type?
// Give the external source a chance to provide a definition of the type.
// This is kept separate from completing the redeclaration chain so that
// external sources such as LLDB can avoid synthesizing a type definition
// unless it's actually needed.
if (Tag || IFace) {
NamedDecl *D =
Tag ? static_cast<NamedDecl *>(Tag->getDecl()) : IFace->getDecl();
// Avoid diagnosing invalid decls as incomplete.
if (D->isInvalidDecl())
if (Def->isInvalidDecl())
return true;
// Give the external AST source a chance to complete the type.
if (auto *Source = Context.getExternalSource()) {
if (Tag) {
TagDecl *TagD = Tag->getDecl();
if (TagD->hasExternalLexicalStorage())
Source->CompleteType(TagD);
} else {
ObjCInterfaceDecl *IFaceD = IFace->getDecl();
if (IFaceD->hasExternalLexicalStorage())
Source->CompleteType(IFace->getDecl());
}
if (Tag && Tag->hasExternalLexicalStorage())
Source->CompleteType(Tag);
if (IFace && IFace->hasExternalLexicalStorage())
Source->CompleteType(IFace);
// If the external source completed the type, go through the motions
// again to ensure we're allowed to use the completed type.
if (!T->isIncompleteType())
@ -7727,32 +7712,31 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// If we have a class template specialization or a class member of a
// class template specialization, or an array with known size of such,
// try to instantiate it.
QualType MaybeTemplate = T;
while (const ConstantArrayType *Array
= Context.getAsConstantArrayType(MaybeTemplate))
MaybeTemplate = Array->getElementType();
if (const RecordType *Record = MaybeTemplate->getAs<RecordType>()) {
if (auto *RD = dyn_cast_or_null<CXXRecordDecl>(Tag)) {
bool Instantiated = false;
bool Diagnosed = false;
if (ClassTemplateSpecializationDecl *ClassTemplateSpec
= dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
if (RD->isDependentContext()) {
// Don't try to instantiate a dependent class (eg, a member template of
// an instantiated class template specialization).
// FIXME: Can this ever happen?
} else if (auto *ClassTemplateSpec =
dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
Diagnosed = InstantiateClassTemplateSpecialization(
Loc, ClassTemplateSpec, TSK_ImplicitInstantiation,
/*Complain=*/Diagnoser);
Instantiated = true;
}
} else if (CXXRecordDecl *Rec
= dyn_cast<CXXRecordDecl>(Record->getDecl())) {
CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass();
if (!Rec->isBeingDefined() && Pattern) {
MemberSpecializationInfo *MSI = Rec->getMemberSpecializationInfo();
} else {
CXXRecordDecl *Pattern = RD->getInstantiatedFromMemberClass();
if (!RD->isBeingDefined() && Pattern) {
MemberSpecializationInfo *MSI = RD->getMemberSpecializationInfo();
assert(MSI && "Missing member specialization information?");
// This record was instantiated from a class within a template.
if (MSI->getTemplateSpecializationKind() !=
TSK_ExplicitSpecialization) {
Diagnosed = InstantiateClass(Loc, Rec, Pattern,
getTemplateInstantiationArgs(Rec),
Diagnosed = InstantiateClass(Loc, RD, Pattern,
getTemplateInstantiationArgs(RD),
TSK_ImplicitInstantiation,
/*Complain=*/Diagnoser);
Instantiated = true;
@ -7783,15 +7767,15 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// If the type was a forward declaration of a class/struct/union
// type, produce a note.
if (Tag && !Tag->getDecl()->isInvalidDecl())
Diag(Tag->getDecl()->getLocation(),
if (Tag && !Tag->isInvalidDecl())
Diag(Tag->getLocation(),
Tag->isBeingDefined() ? diag::note_type_being_defined
: diag::note_forward_declaration)
<< QualType(Tag, 0);
<< Context.getTagDeclType(Tag);
// If the Objective-C class was a forward declaration, produce a note.
if (IFace && !IFace->getDecl()->isInvalidDecl())
Diag(IFace->getDecl()->getLocation(), diag::note_forward_class);
if (IFace && !IFace->isInvalidDecl())
Diag(IFace->getLocation(), diag::note_forward_class);
// If we have external information that we can use to suggest a fix,
// produce a note.

View File

@ -108,7 +108,7 @@ void g() {
extern int incomplete[];
for (auto a : incomplete) // expected-error {{cannot use incomplete type 'int []' as a range}}
;
extern struct Incomplete also_incomplete[2]; // expected-note {{forward declaration}}
extern struct Incomplete also_incomplete[2]; // expected-note 2{{forward declaration}}
for (auto &a : also_incomplete) // expected-error {{cannot use incomplete type 'struct Incomplete [2]' as a range}}
;

View File

@ -410,7 +410,7 @@ void test16(void) {
[v test16_6: 0];
}
@class Test17; // expected-note 2{{forward declaration of class here}}
@class Test17; // expected-note 3{{forward declaration of class here}}
@protocol Test17p
- (void) test17;
+ (void) test17;