From 9321ad3f970714e3ca40d7c3461ff3acdbf8f7e7 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Thu, 6 Oct 2011 23:23:20 +0000 Subject: [PATCH] When using an unavailable/deprecated interface Foo inside Foo's interface/implementation don't emit unavailable errors. llvm-svn: 141334 --- clang/include/clang/Parse/Parser.h | 4 ++-- clang/include/clang/Sema/Sema.h | 17 ++++++++++++++++- clang/lib/Parse/ParseObjc.cpp | 4 +--- clang/lib/Sema/Sema.cpp | 3 ++- clang/lib/Sema/SemaDecl.cpp | 15 +++++++++++++-- clang/lib/Sema/SemaDeclAttr.cpp | 2 +- clang/lib/Sema/SemaDeclObjC.cpp | 18 +++++++++--------- clang/lib/Sema/SemaExpr.cpp | 3 ++- clang/test/SemaObjC/attr-deprecated.m | 2 ++ clang/test/SemaObjC/class-unavail-warning.m | 10 +++++++++- 10 files changed, 57 insertions(+), 21 deletions(-) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index cf9bbbe9dd9b..a1f602c72a9e 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -520,11 +520,11 @@ private: explicit ObjCDeclContextSwitch(Parser &p) : P(p), DC(p.getObjCDeclContext()) { if (DC) - P.Actions.ActOnObjCContainerFinishDefinition(); + P.Actions.ActOnObjCTemporaryExitContainerContext(); } ~ObjCDeclContextSwitch() { if (DC) - P.Actions.ActOnObjCContainerStartDefinition(DC); + P.Actions.ActOnObjCReenterContainerContext(); } }; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4b8bbdc6eab7..6aee5900e2d6 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -202,6 +202,10 @@ public: /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; + /// \brief Generally null except when we temporarily switch decl contexts, + /// like in \see ActOnObjCTemporaryExitContainerContext. + DeclContext *OriginalLexicalContext; + /// VAListTagName - The declaration name corresponding to __va_list_tag. /// This is used as part of a hack to omit that class from ADL results. DeclarationName VAListTagName; @@ -1224,7 +1228,7 @@ public: /// struct, or union). void ActOnTagStartDefinition(Scope *S, Decl *TagDecl); - void ActOnObjCContainerStartDefinition(Decl *IDecl); + Decl *ActOnObjCContainerStartDefinition(Decl *IDecl); /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a /// C++ record definition's base-specifiers clause and are starting its @@ -1240,6 +1244,13 @@ public: void ActOnObjCContainerFinishDefinition(); + /// \brief Invoked when we must temporarily exit the objective-c container + /// scope for parsing/looking-up C constructs. + /// + /// Must be followed by a call to \see ActOnObjCReenterContainerContext + void ActOnObjCTemporaryExitContainerContext(); + void ActOnObjCReenterContainerContext(); + /// ActOnTagDefinitionError - Invoked when there was an unrecoverable /// error parsing the definition of a tag. void ActOnTagDefinitionError(Scope *S, Decl *TagDecl); @@ -6150,6 +6161,10 @@ public: Scope *getCurScope() const { return CurScope; } Decl *getObjCDeclContext() const; + + DeclContext *getCurLexicalContext() const { + return OriginalLexicalContext ? OriginalLexicalContext : CurContext; + } }; /// \brief RAII object that enters a new expression evaluation context. diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 1b4822583734..78c6b87715f9 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -336,7 +336,6 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword; SourceRange AtEnd; - Actions.ActOnObjCContainerStartDefinition(CDecl); while (1) { // If this is a method prototype, parse it. @@ -1195,6 +1194,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, SmallVector AllIvarDecls; ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope); + ObjCDeclContextSwitch ObjCDC(*this); SourceLocation LBraceLoc = ConsumeBrace(); // the "{" @@ -1441,7 +1441,6 @@ Decl *Parser::ParseObjCAtImplementationDeclaration( atLoc, nameId, nameLoc, categoryId, categoryLoc); - Actions.ActOnObjCContainerStartDefinition(ImplCatType); ObjCImpDecl = ImplCatType; PendingObjCImpDecl.push_back(ObjCImpDecl); return 0; @@ -1466,7 +1465,6 @@ Decl *Parser::ParseObjCAtImplementationDeclaration( if (Tok.is(tok::l_brace)) // we have ivars ParseObjCClassInstanceVariables(ImplClsType, tok::objc_private, atLoc); - Actions.ActOnObjCContainerStartDefinition(ImplClsType); ObjCImpDecl = ImplClsType; PendingObjCImpDecl.push_back(ObjCImpDecl); return 0; diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 679d4f658936..3f47986367c7 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -95,7 +95,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter), - CurContext(0), PackContext(0), MSStructPragmaOn(false), VisContext(0), + CurContext(0), OriginalLexicalContext(0), + PackContext(0), MSStructPragmaOn(false), VisContext(0), ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0), IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0), GlobalNewDeleteDeclared(false), diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 534cd488e759..4a4862bec4ce 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8004,13 +8004,14 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { PushDeclContext(S, Tag); } -void Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { +Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { assert(isa(IDecl) && "ActOnObjCContainerStartDefinition - Not ObjCContainerDecl"); DeclContext *OCD = cast(IDecl); assert(getContainingDC(OCD) == CurContext && "The next DeclContext should be lexically contained in the current one."); CurContext = OCD; + return IDecl; } void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, @@ -8068,7 +8069,17 @@ void Sema::ActOnObjCContainerFinishDefinition() { // Exit this scope of this interface definition. PopDeclContext(); } - + +void Sema::ActOnObjCTemporaryExitContainerContext() { + OriginalLexicalContext = CurContext; + ActOnObjCContainerFinishDefinition(); +} + +void Sema::ActOnObjCReenterContainerContext() { + ActOnObjCContainerStartDefinition(cast(OriginalLexicalContext)); + OriginalLexicalContext = 0; +} + void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast(TagD); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 940f5a86a61e..e5ea1610ad58 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4031,7 +4031,7 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message, } // Otherwise, don't warn if our current context is deprecated. - if (isDeclDeprecated(cast(CurContext))) + if (isDeclDeprecated(cast(getCurLexicalContext()))) return; if (!Message.empty()) Diag(Loc, diag::warn_deprecated_message) << D->getDeclName() diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index de48de15d77c..1a1ac2eccf13 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -374,7 +374,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, // Return the previous class interface. // FIXME: don't leak the objects passed in! - return IDecl; + return ActOnObjCContainerStartDefinition(IDecl); } else { IDecl->setLocation(ClassLoc); IDecl->setForwardDecl(false); @@ -482,7 +482,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, } CheckObjCDeclScope(IDecl); - return IDecl; + return ActOnObjCContainerStartDefinition(IDecl); } /// ActOnCompatiblityAlias - this action is called after complete parsing of @@ -578,7 +578,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, Diag(PDecl->getLocation(), diag::note_previous_definition); // Just return the protocol we already had. // FIXME: don't leak the objects passed in! - return PDecl; + return ActOnObjCContainerStartDefinition(PDecl); } ObjCList PList; PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context); @@ -611,7 +611,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, } CheckObjCDeclScope(PDecl); - return PDecl; + return ActOnObjCContainerStartDefinition(PDecl); } /// FindProtocolDeclaration - This routine looks up protocols and @@ -741,7 +741,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, ClassLoc, CategoryLoc, CategoryName,IDecl); CDecl->setInvalidDecl(); Diag(ClassLoc, diag::err_undef_interface) << ClassName; - return CDecl; + return ActOnObjCContainerStartDefinition(CDecl); } if (!CategoryName && IDecl->getImplementation()) { @@ -783,7 +783,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, } CheckObjCDeclScope(CDecl); - return CDecl; + return ActOnObjCContainerStartDefinition(CDecl); } /// ActOnStartCategoryImplementation - Perform semantic checks on the @@ -836,7 +836,7 @@ Decl *Sema::ActOnStartCategoryImplementation( } CheckObjCDeclScope(CDecl); - return CDecl; + return ActOnObjCContainerStartDefinition(CDecl); } Decl *Sema::ActOnStartClassImplementation( @@ -930,7 +930,7 @@ Decl *Sema::ActOnStartClassImplementation( ClassLoc, AtClassImplLoc); if (CheckObjCDeclScope(IMPDecl)) - return IMPDecl; + return ActOnObjCContainerStartDefinition(IMPDecl); // Check that there is no duplicate implementation of this class. if (IDecl->getImplementation()) { @@ -947,7 +947,7 @@ Decl *Sema::ActOnStartClassImplementation( dyn_cast(IDecl), IMPDecl->getLocation(), 1); } - return IMPDecl; + return ActOnObjCContainerStartDefinition(IMPDecl); } void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ec71a4e94d19..05b0bb7efc7f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -72,7 +72,8 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, break; case AR_Unavailable: - if (cast(S.CurContext)->getAvailability() != AR_Unavailable) { + if (cast(S.getCurLexicalContext())->getAvailability() != + AR_Unavailable) { if (Message.empty()) { if (!UnknownObjCClass) S.Diag(Loc, diag::err_unavailable) << D->getDeclName(); diff --git a/clang/test/SemaObjC/attr-deprecated.m b/clang/test/SemaObjC/attr-deprecated.m index 0152aca934ca..be6c51f8c415 100644 --- a/clang/test/SemaObjC/attr-deprecated.m +++ b/clang/test/SemaObjC/attr-deprecated.m @@ -85,8 +85,10 @@ int t5() { __attribute ((deprecated)) @interface DEPRECATED { @public int ivar; + DEPRECATED *ivar2; // no warning. } - (int) instancemethod; +- (DEPRECATED *) meth; // no warning. @property int prop; @end diff --git a/clang/test/SemaObjC/class-unavail-warning.m b/clang/test/SemaObjC/class-unavail-warning.m index 408647ac11c1..a0c2d5588e67 100644 --- a/clang/test/SemaObjC/class-unavail-warning.m +++ b/clang/test/SemaObjC/class-unavail-warning.m @@ -2,17 +2,25 @@ // rdar://9092208 __attribute__((unavailable("not available"))) -@interface MyClass { // expected-note 5 {{declaration has been explicitly marked unavailable here}} +@interface MyClass { // expected-note 7 {{declaration has been explicitly marked unavailable here}} @public void *_test; + MyClass *ivar; // no error. } - (id)self; - new; + (void)addObject:(id)anObject; +- (MyClass *)meth; // no error. @end +@interface Foo { + MyClass *ivar; // expected-error {{unavailable}} +} +- (MyClass *)meth; // expected-error {{unavailable}} +@end + int main() { [MyClass new]; // expected-error {{'MyClass' is unavailable: not available}} [MyClass self]; // expected-error {{'MyClass' is unavailable: not available}}