Refactor Objective-C @catch parameter checking by detangling it from

function-parameter checking and splitting it into the normal
ActOn*/Build* pair in Sema. We now use VarDecl to represent the @catch
parameter rather than the ill-fitting ParmVarDecl.

llvm-svn: 102347
This commit is contained in:
Douglas Gregor 2010-04-26 17:32:49 +00:00
parent 46a572b871
commit f356419bf5
6 changed files with 115 additions and 25 deletions

View File

@ -2083,6 +2083,15 @@ def err_catch_param_not_objc_type : Error<
"@catch parameter is not a pointer to an interface type">;
def err_illegal_qualifiers_on_catch_parm : Error<
"illegal qualifiers on @catch parameter">;
def err_storage_spec_on_catch_parm : Error<
"@catch parameter cannot have storage specifier %select{|'typedef'|'extern'|"
"'static'|'auto'|'register'|'__private_extern__'|'mutable'}0">;
def warn_register_objc_catch_parm : Warning<
"'register' storage specifier on @catch parameter will be ignored">;
def err_qualified_objc_catch_parm : Error<
"@catch parameter declarator cannot be qualified">;
def warn_setter_getter_impl_required : Warning<
"property %0 requires method %1 to be defined - "
"use @synthesize, @dynamic or provide a method implementation">;

View File

@ -82,8 +82,9 @@ public:
class DeclSpec {
public:
// storage-class-specifier
// Note: The order of these enumerators is important for diagnostics.
enum SCS {
SCS_unspecified,
SCS_unspecified = 0,
SCS_typedef,
SCS_extern,
SCS_static,

View File

@ -812,7 +812,6 @@ public:
SourceLocation NameLoc,
VarDecl::StorageClass StorageClass,
VarDecl::StorageClass StorageClassAsWritten);
virtual DeclPtrTy ActOnObjCExceptionDecl(Scope *S, Declarator &D);
virtual void ActOnParamDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
ExprArg defarg);
@ -1675,6 +1674,13 @@ public:
SourceLocation RParenLoc,
bool MSAsm = false);
VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType,
IdentifierInfo *Name, SourceLocation NameLoc,
bool Invalid = false);
virtual DeclPtrTy ActOnObjCExceptionDecl(Scope *S, Declarator &D);
virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen,
DeclPtrTy Parm, StmtArg Body);

View File

@ -1707,10 +1707,92 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
}
}
Sema::DeclPtrTy Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
// FIXME: Perform checking on the declaration here.
DeclPtrTy Dcl = ActOnParamDeclarator(S, D);
if (Dcl.get())
cast<VarDecl>(Dcl.getAs<Decl>())->setDeclContext(CurContext);
return Dcl;
/// \brief Build a type-check a new Objective-C exception variable declaration.
VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo,
QualType T,
IdentifierInfo *Name,
SourceLocation NameLoc,
bool Invalid) {
// ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
// duration shall not be qualified by an address-space qualifier."
// Since all parameters have automatic store duration, they can not have
// an address space.
if (T.getAddressSpace() != 0) {
Diag(NameLoc, diag::err_arg_with_address_space);
Invalid = true;
}
// An @catch parameter must be an unqualified object pointer type;
// FIXME: Recover from "NSObject foo" by inserting the * in "NSObject *foo"?
if (Invalid) {
// Don't do any further checking.
} else if (!T->isObjCObjectPointerType()) {
Invalid = true;
Diag(NameLoc ,diag::err_catch_param_not_objc_type);
} else if (T->isObjCQualifiedIdType()) {
Invalid = true;
Diag(NameLoc, diag::err_illegal_qualifiers_on_catch_parm);
}
VarDecl *New = VarDecl::Create(Context, CurContext, NameLoc, Name, T, TInfo,
VarDecl::None, VarDecl::None);
if (Invalid)
New->setInvalidDecl();
return New;
}
Sema::DeclPtrTy Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
const DeclSpec &DS = D.getDeclSpec();
// We allow the "register" storage class on exception variables because
// GCC did, but we drop it completely. Any other storage class is an error.
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
Diag(DS.getStorageClassSpecLoc(), diag::warn_register_objc_catch_parm)
<< FixItHint::CreateRemoval(SourceRange(DS.getStorageClassSpecLoc()));
} else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
Diag(DS.getStorageClassSpecLoc(), diag::err_storage_spec_on_catch_parm)
<< DS.getStorageClassSpec();
}
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
D.getMutableDeclSpec().ClearStorageClassSpecs();
DiagnoseFunctionSpecifiers(D);
// Check that there are no default arguments inside the type of this
// exception object (C++ only).
if (getLangOptions().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
TypeSourceInfo *TInfo = 0;
TagDecl *OwnedDecl = 0;
QualType ExceptionType = GetTypeForDeclarator(D, S, &TInfo, &OwnedDecl);
if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) {
// Objective-C++: Types shall not be defined in exception types.
Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type)
<< Context.getTypeDeclType(OwnedDecl);
}
VarDecl *New = BuildObjCExceptionDecl(TInfo, ExceptionType, D.getIdentifier(),
D.getIdentifierLoc(),
D.isInvalidType());
// Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
Diag(D.getIdentifierLoc(), diag::err_qualified_objc_catch_parm)
<< D.getCXXScopeSpec().getRange();
New->setInvalidDecl();
}
// Add the parameter declaration into this scope.
S->AddDecl(DeclPtrTy::make(New));
if (D.getIdentifier())
IdResolver.AddDecl(New);
ProcessDeclAttributes(S, New, D);
if (New->hasAttr<BlocksAttr>())
Diag(New->getLocation(), diag::err_block_on_nonlocal);
return DeclPtrTy::make(New);
}

View File

@ -1527,23 +1527,11 @@ Action::OwningStmtResult
Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen, DeclPtrTy Parm,
StmtArg Body) {
ParmVarDecl *PVD = cast_or_null<ParmVarDecl>(Parm.getAs<Decl>());
// PVD == 0 implies @catch(...).
if (PVD) {
// If we already know the decl is invalid, reject it.
if (PVD->isInvalidDecl())
return StmtError();
if (!PVD->getType()->isObjCObjectPointerType())
return StmtError(Diag(PVD->getLocation(),
diag::err_catch_param_not_objc_type));
if (PVD->getType()->isObjCQualifiedIdType())
return StmtError(Diag(PVD->getLocation(),
diag::err_illegal_qualifiers_on_catch_parm));
}
return Owned(new (Context) ObjCAtCatchStmt(AtLoc, RParen, PVD,
VarDecl *Var = cast_or_null<VarDecl>(Parm.getAs<Decl>());
if (Var && Var->isInvalidDecl())
return StmtError();
return Owned(new (Context) ObjCAtCatchStmt(AtLoc, RParen, Var,
Body.takeAs<Stmt>()));
}

View File

@ -2,12 +2,16 @@
struct some_struct;
@interface NSObject
@end
// Note: NSException is not declared.
void f0(id x) {
@try {
} @catch (NSException *x) { // expected-error {{unknown type name 'NSException'}}
} @catch (struct some_struct x) { // expected-error {{@catch parameter is not a pointer to an interface type}}
} @catch (int x) { // expected-error {{@catch parameter is not a pointer to an interface type}}
} @catch (static NSObject *y) { // expected-error {{@catch parameter cannot have storage specifier 'static'}}
} @catch (...) {
}
}