Use Sema::RequireCompleteType to check for the completeness of

Objective-C classes. This has two purposes: to consistently provide
"forward declaration here" notes when we hit an incomplete type, and
to give LLDB a chance to complete the type.

RequireCompleteType bits from Sean Callanan!

llvm-svn: 144573
This commit is contained in:
Douglas Gregor 2011-11-14 22:10:01 +00:00
parent 1fcdaa9c05
commit 4123a86fae
18 changed files with 110 additions and 79 deletions

View File

@ -373,6 +373,8 @@ def warn_property_attribute : Warning<
def warn_property_types_are_incompatible : Warning<
"property type %0 is incompatible with type %1 inherited from %2">;
def err_undef_interface : Error<"cannot find interface declaration for %0">;
def err_category_forward_interface : Error<
"cannot define %select{category|class extension}0 for undefined class %1">;
def err_class_extension_after_impl : Error<
"cannot declare class extension for %0 after class implementation">;
def note_implementation_declared : Note<
@ -3617,7 +3619,7 @@ def err_property_not_as_forward_class : Error<
"property %0 refers to an incomplete Objective-C class %1 "
"(with no @interface available)">;
def note_forward_class : Note<
"forward class is declared here">;
"forward declaration of class here">;
def err_duplicate_property : Error<
"property has a previous declaration">;
def ext_gnu_void_ptr : Extension<

View File

@ -463,11 +463,12 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (!SuperClassDecl)
Diag(SuperLoc, diag::err_undef_superclass)
<< SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
else if (SuperClassDecl->isForwardDecl()) {
Diag(SuperLoc, diag::err_forward_superclass)
<< SuperClassDecl->getDeclName() << ClassName
<< SourceRange(AtInterfaceLoc, ClassLoc);
Diag(SuperClassDecl->getLocation(), diag::note_forward_class);
else if (RequireCompleteType(SuperLoc,
Context.getObjCInterfaceType(SuperClassDecl),
PDiag(diag::err_forward_superclass)
<< SuperClassDecl->getDeclName()
<< ClassName
<< SourceRange(AtInterfaceLoc, ClassLoc))) {
SuperClassDecl = 0;
}
}
@ -746,14 +747,20 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true);
/// Check that class of this category is already completely declared.
if (!IDecl || IDecl->isForwardDecl()) {
if (!IDecl
|| RequireCompleteType(ClassLoc, Context.getObjCInterfaceType(IDecl),
PDiag(diag::err_category_forward_interface)
<< (CategoryName == 0))) {
// Create an invalid ObjCCategoryDecl to serve as context for
// the enclosing method declarations. We mark the decl invalid
// to make it clear that this isn't a valid AST.
CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
ClassLoc, CategoryLoc, CategoryName,IDecl);
CDecl->setInvalidDecl();
Diag(ClassLoc, diag::err_undef_interface) << ClassName;
if (!IDecl)
Diag(ClassLoc, diag::err_undef_interface) << ClassName;
return ActOnObjCContainerStartDefinition(CDecl);
}
@ -820,9 +827,12 @@ Decl *Sema::ActOnStartCategoryImplementation(
ObjCCategoryImplDecl::Create(Context, CurContext, CatName, IDecl,
ClassLoc, AtCatImplLoc);
/// Check that class of this category is already completely declared.
if (!IDecl || IDecl->isForwardDecl()) {
if (!IDecl) {
Diag(ClassLoc, diag::err_undef_interface) << ClassName;
CDecl->setInvalidDecl();
} else if (RequireCompleteType(ClassLoc, Context.getObjCInterfaceType(IDecl),
diag::err_undef_interface)) {
CDecl->setInvalidDecl();
}
// FIXME: PushOnScopeChains?
@ -867,11 +877,9 @@ Decl *Sema::ActOnStartClassImplementation(
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
} else if ((IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl))) {
// If this is a forward declaration of an interface, warn.
if (IDecl->isForwardDecl()) {
Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
if (RequireCompleteType(ClassLoc, Context.getObjCInterfaceType(IDecl),
diag::warn_undef_interface))
IDecl = 0;
}
} else {
// We did not find anything with the name ClassName; try to correct for
// typos in the class name.

View File

@ -591,13 +591,13 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
}
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
if (IFace->isForwardDecl()) {
Diag(MemberLoc, diag::err_property_not_found_forward_class)
<< MemberName << QualType(OPT, 0);
Diag(IFace->getLocation(), diag::note_forward_class);
SourceRange BaseRange = Super? SourceRange(SuperLoc)
: BaseExpr->getSourceRange();
if (RequireCompleteType(MemberLoc, OPT->getPointeeType(),
PDiag(diag::err_property_not_found_forward_class)
<< MemberName << BaseRange))
return ExprError();
}
// Search for a declared property first.
if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
// Check whether we can reference this property.
@ -722,14 +722,10 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
QualType T = Ivar->getType();
if (const ObjCObjectPointerType * OBJPT =
T->getAsObjCInterfacePointerType()) {
const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType();
if (ObjCInterfaceDecl *IFace = IFaceT->getDecl())
if (IFace->isForwardDecl()) {
Diag(MemberLoc, diag::err_property_not_as_forward_class)
<< MemberName << IFace;
Diag(IFace->getLocation(), diag::note_forward_class);
return ExprError();
}
if (RequireCompleteType(MemberLoc, OBJPT->getPointeeType(),
PDiag(diag::err_property_not_as_forward_class)
<< MemberName << BaseExpr->getSourceRange()))
return ExprError();
}
Diag(MemberLoc,
diag::err_ivar_access_using_property_syntax_suggest)
@ -1083,13 +1079,14 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
(void)DiagnoseUseOfDecl(Class, Loc);
// Find the method we are messaging.
if (!Method) {
if (Class->isForwardDecl()) {
if (getLangOptions().ObjCAutoRefCount) {
Diag(Loc, diag::err_arc_receiver_forward_class) << ReceiverType;
} else {
Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName();
}
SourceRange TypeRange
= SuperLoc.isValid()? SourceRange(SuperLoc)
: ReceiverTypeInfo->getTypeLoc().getSourceRange();
if (RequireCompleteType(Loc, Context.getObjCInterfaceType(Class),
(getLangOptions().ObjCAutoRefCount
? PDiag(diag::err_arc_receiver_forward_class)
: PDiag(diag::warn_receiver_forward_class))
<< TypeRange)) {
// A forward class used in messaging is treated as a 'Class'
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LBracLoc, RBracLoc));
@ -1322,13 +1319,21 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// We allow sending a message to a pointer to an interface (an object).
ClassDecl = OCIType->getInterfaceDecl();
if (ClassDecl->isForwardDecl() && getLangOptions().ObjCAutoRefCount) {
Diag(Loc, diag::err_arc_receiver_forward_instance)
<< OCIType->getPointeeType()
<< (Receiver ? Receiver->getSourceRange() : SourceRange(SuperLoc));
return ExprError();
// Try to complete the type. Under ARC, this is a hard error from which
// we don't try to recover.
const ObjCInterfaceDecl *forwardClass = 0;
if (RequireCompleteType(Loc, OCIType->getPointeeType(),
getLangOptions().ObjCAutoRefCount
? PDiag(diag::err_arc_receiver_forward_instance)
<< (Receiver ? Receiver->getSourceRange()
: SourceRange(SuperLoc))
: PDiag())) {
if (getLangOptions().ObjCAutoRefCount)
return ExprError();
forwardClass = OCIType->getInterfaceDecl();
}
// FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
// faster than the following method (which can do *many* linear searches).
// The idea is to add class info to MethodPool.
@ -1338,7 +1343,6 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// Search protocol qualifiers.
Method = LookupMethodInQualifiedType(Sel, OCIType, true);
const ObjCInterfaceDecl *forwardClass = 0;
if (!Method) {
// If we have implementations in scope, check "private" methods.
Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
@ -1356,8 +1360,6 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (OCIType->qual_empty()) {
Method = LookupInstanceMethodInGlobalPool(Sel,
SourceRange(LBracLoc, RBracLoc));
if (OCIType->getInterfaceDecl()->isForwardDecl())
forwardClass = OCIType->getInterfaceDecl();
if (Method && !forwardClass)
Diag(Loc, diag::warn_maynot_respond)
<< OCIType->getInterfaceDecl()->getIdentifier() << Sel;

View File

@ -1060,13 +1060,13 @@ Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
ObjCInterfaceDecl *iface = objectType->getInterface();
// If we have a forward-declared type, we can't do this check.
if (iface && iface->isForwardDecl()) {
// This is ill-formed under ARC.
if (getLangOptions().ObjCAutoRefCount) {
Diag(forLoc, diag::err_arc_collection_forward)
<< pointerType->getPointeeType() << collection->getSourceRange();
}
// Under ARC, it is an error not to have a forward-declared class.
if (iface &&
RequireCompleteType(forLoc, QualType(objectType, 0),
getLangOptions().ObjCAutoRefCount
? PDiag(diag::err_arc_collection_forward)
<< collection->getSourceRange()
: PDiag(0))) {
// Otherwise, if we have any useful type information, check that
// the type declares the appropriate method.
} else if (iface || !objectType->qual_empty()) {

View File

@ -4098,21 +4098,36 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
return true;
const TagType *Tag = T->getAs<TagType>();
const ObjCInterfaceType *IFace = 0;
if (Tag) {
// Avoid diagnosing invalid decls as incomplete.
if (Tag->getDecl()->isInvalidDecl())
return true;
// Avoid diagnosing invalid decls as incomplete.
if (Tag && Tag->getDecl()->isInvalidDecl())
return true;
// Give the external AST source a chance to complete the type.
if (Tag && Tag->getDecl()->hasExternalLexicalStorage()) {
Context.getExternalSource()->CompleteType(Tag->getDecl());
if (!Tag->isIncompleteType())
return false;
// Give the external AST source a chance to complete the type.
if (Tag->getDecl()->hasExternalLexicalStorage()) {
Context.getExternalSource()->CompleteType(Tag->getDecl());
if (!Tag->isIncompleteType())
return false;
}
}
else if ((IFace = T->getAs<ObjCInterfaceType>())) {
// Avoid diagnosing invalid decls as incomplete.
if (IFace->getDecl()->isInvalidDecl())
return true;
// Give the external AST source a chance to complete the type.
if (IFace->getDecl()->hasExternalLexicalStorage()) {
Context.getExternalSource()->CompleteType(IFace->getDecl());
if (!IFace->isIncompleteType())
return false;
}
}
// We have an incomplete type. Produce a diagnostic.
Diag(Loc, PD) << T;
// If we have a note, produce it.
if (!Note.first.isInvalid())
Diag(Note.first, Note.second);
@ -4123,7 +4138,11 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
Diag(Tag->getDecl()->getLocation(),
Tag->isBeingDefined() ? diag::note_type_being_defined
: diag::note_forward_declaration)
<< QualType(Tag, 0);
<< QualType(Tag, 0);
// 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);
return true;
}

View File

@ -10,7 +10,7 @@ typedef struct _NSZone NSZone;
@interface NSObject <NSObject> {} @end
extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
@class NSArray;
@class NSMutableArray, NSIndexSet, NSView, NSPredicate, NSString, NSViewAnimation, NSTimer;
@class NSMutableArray, NSIndexSet, NSView, NSPredicate, NSString, NSViewAnimation, NSTimer; // expected-note{{forward declaration of class here}}
@interface FooBazController : NSObject {}
@end
typedef struct {} TazVersion;

View File

@ -378,7 +378,7 @@ void test16(void) {
[v test16_6: 0];
}
@class Test17;
@class Test17; // expected-note 2{{forward declaration of class here}}
@protocol Test17p
- (void) test17;
+ (void) test17;
@ -651,7 +651,7 @@ void test36(int first, ...) {
__builtin_va_end(arglist);
}
@class Test37;
@class Test37; // expected-note{{forward declaration of class here}}
void test37(Test37 *c) {
for (id y in c) { // expected-error {{collection expression type 'Test37' is a forward declaration}}
(void) y;

View File

@ -31,9 +31,9 @@
@interface UnknownClass (Category) @end // expected-error {{cannot find interface declaration for 'UnknownClass'}}
@class MyClass2;
@class MyClass2; // expected-note{{forward declaration of class here}}
@interface MyClass2 (Category) @end // expected-error {{cannot find interface declaration for 'MyClass2'}}
@interface MyClass2 (Category) @end // expected-error {{cannot define category for undefined class 'MyClass2'}}
@interface XCRemoteComputerManager
@end

View File

@ -31,7 +31,7 @@ typedef int INTF3; // expected-note {{previous definition is here}}
@implementation INTF4 @end // expected-warning {{cannot find interface declaration for 'INTF4'}}
@class INTF5;
@class INTF5; // expected-note{{forward declaration of class here}}
@implementation INTF5 { // expected-warning {{cannot find interface declaration for 'INTF5'}}
int x;

View File

@ -23,7 +23,7 @@
@interface E2 <p1,p2,p3> @end // expected-warning {{cannot find protocol definition for 'p3'}}
@class U1, U2; // expected-note {{forward class is declared here}}
@class U1, U2; // expected-note {{forward declaration of class here}}
@interface E3 : U1 @end // expected-error {{attempting to use the forward class 'U1' as superclass of 'E3'}}

View File

@ -33,7 +33,7 @@ void test3(Object *o) {
__sync_bool_compare_and_swap(&g, 0, o);
}
@class Incomplete_ObjC_class;
@class Incomplete_ObjC_class; // expected-note{{forward declaration of class here}}
struct Incomplete_struct; // expected-note {{forward declaration}}
void test_encode() {

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
@class FOO, BAR; // expected-note {{forward class is declared here}}
@class FOO, BAR; // expected-note {{forward declaration of class here}}
@class FOO, BAR;
@interface INTF : FOO // expected-error {{attempting to use the forward class 'FOO' as superclass of 'INTF'}}
@ -46,7 +46,7 @@ typedef NSObject <XCElementP> XCElement;
// rdar://9653341
@class B; // expected-note {{forward class is declared here}}
@class B; // expected-note {{forward declaration of class here}}
@interface A : B {} // expected-error {{attempting to use the forward class 'B' as superclass of 'A'}}
@end

View File

@ -5,7 +5,7 @@
@end
Class isa;
@class NotKnown;
@class NotKnown; // expected-note{{forward declaration of class here}}
void foo(NotKnown *n) {
[isa new];

View File

@ -97,13 +97,13 @@ typedef signed char BOOL;
@end
// rdar://8774513
@class MDAInstance; // expected-note {{forward class is declared here}}
@class MDAInstance; // expected-note {{forward declaration of class here}}
@interface MDATestDocument
@property(retain) MDAInstance *instance;
@end
id f0(MDATestDocument *d) {
return d.instance.path; // expected-error {{property 'path' cannot be found in forward class object 'MDAInstance *'}}
return d.instance.path; // expected-error {{property 'path' cannot be found in forward class object 'MDAInstance'}}
}

View File

@ -21,7 +21,7 @@ void f3(id o)
}
// rdar://8851803
@class SomeOtherClass; // expected-note {{forward class is declared here}}
@class SomeOtherClass; // expected-note {{forward declaration of class here}}
@interface MyClass {
SomeOtherClass *someOtherObject;

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -verify -fsyntax-only %s
@class I0;
@class I0; // expected-note 3{{forward declaration of class here}}
// rdar://6811884
int g0 = sizeof(I0); // expected-error{{invalid application of 'sizeof' to an incomplete type 'I0'}}

View File

@ -27,7 +27,7 @@
@end
@class C; // expected-note 5 {{forward class is declared here}}
@class C; // expected-note 5 {{forward declaration of class here}}
void test(C *c) {
[c depInA]; // expected-warning {{'depInA' maybe deprecated because receiver type is unknown}}

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
@class SUPER, Y; // expected-note 2 {{forward class is declared here}}
@class SUPER, Y; // expected-note 2 {{forward declaration of class here}}
@interface INTF :SUPER // expected-error {{attempting to use the forward class 'SUPER' as superclass of 'INTF'}}
@end