diff options
-rw-r--r-- | include/clang/Parse/Action.h | 17 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 97 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 15 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 12 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 9 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 16 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 59 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 30 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 34 | ||||
-rw-r--r-- | test/Sema/attr-deprecated.c | 45 |
15 files changed, 292 insertions, 80 deletions
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 2989eb6adb..073365dced 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -161,6 +161,23 @@ public: // Declaration Tracking Callbacks. //===--------------------------------------------------------------------===// + typedef uintptr_t ParsingDeclStackState; + + /// PushParsingDeclaration - Notes that the parser has begun + /// processing a declaration of some sort. Guaranteed to be matched + /// by a call to PopParsingDeclaration with the value returned by + /// this method. + virtual ParsingDeclStackState PushParsingDeclaration() { + return ParsingDeclStackState(); + } + + /// PopParsingDeclaration - Notes that the parser has completed + /// processing a declaration of some sort. The decl will be empty + /// if the declaration didn't correspond to a full declaration (or + /// if the actions module returned an empty decl for it). + virtual void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D) { + } + /// ConvertDeclToDeclGroup - If the parser has one decl in a context where it /// needs a decl group, it calls this to convert between the two /// representations. diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index eb2ec53e6f..f34d469d98 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -571,6 +571,99 @@ private: return *ClassStack.top(); } + /// \brief RAII object used to inform the actions that we're + /// currently parsing a declaration. This is active when parsing a + /// variable's initializer, but not when parsing the body of a + /// class or function definition. + class ParsingDeclRAIIObject { + Action &Actions; + Action::ParsingDeclStackState State; + bool Popped; + + public: + ParsingDeclRAIIObject(Parser &P) : Actions(P.Actions) { + push(); + } + + ~ParsingDeclRAIIObject() { + abort(); + } + + /// Resets the RAII object for a new declaration. + void reset() { + abort(); + push(); + } + + /// Signals that the context was completed without an appropriate + /// declaration being parsed. + void abort() { + pop(DeclPtrTy()); + } + + void complete(DeclPtrTy D) { + assert(!Popped && "ParsingDeclaration has already been popped!"); + pop(D); + } + + private: + void push() { + State = Actions.PushParsingDeclaration(); + Popped = false; + } + + void pop(DeclPtrTy D) { + if (!Popped) { + Actions.PopParsingDeclaration(State, D); + Popped = true; + } + } + }; + + /// A class for parsing a DeclSpec. + class ParsingDeclSpec : public DeclSpec { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingDeclSpec(Parser &P) : ParsingRAII(P) { + } + + void complete(DeclPtrTy D) { + ParsingRAII.complete(D); + } + + void abort() { + ParsingRAII.abort(); + } + }; + + /// A class for parsing a declarator. + class ParsingDeclarator : public Declarator { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C) + : Declarator(DS, C), ParsingRAII(P) { + } + + const ParsingDeclSpec &getDeclSpec() const { + return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec()); + } + + ParsingDeclSpec &getMutableDeclSpec() const { + return const_cast<ParsingDeclSpec&>(getDeclSpec()); + } + + void clear() { + Declarator::clear(); + ParsingRAII.reset(); + } + + void complete(DeclPtrTy D) { + ParsingRAII.complete(D); + } + }; + /// \brief RAII object used to class ParsingClassDefinition { Parser &P; @@ -664,7 +757,7 @@ private: DeclGroupPtrTy ParseDeclarationOrFunctionDefinition( AccessSpecifier AS = AS_none); - DeclPtrTy ParseFunctionDefinition(Declarator &D, + DeclPtrTy ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); void ParseKNRParamDeclarations(Declarator &D); // EndLoc, if non-NULL, is filled with the location of the last token of @@ -951,7 +1044,7 @@ private: DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd); DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context, SourceLocation &DeclEnd); - DeclGroupPtrTy ParseDeclGroup(DeclSpec &DS, unsigned Context, + DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, bool AllowFunctionDefinitions, SourceLocation *DeclEnd = 0); DeclPtrTy ParseDeclarationAfterDeclarator(Declarator &D, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index a47065c2b5..e905553fd8 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -338,7 +338,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, SourceLocation &DeclEnd) { // Parse the common declaration-specifiers piece. - DeclSpec DS; + ParsingDeclSpec DS(*this); ParseDeclarationSpecifiers(DS); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" @@ -346,6 +346,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, if (Tok.is(tok::semi)) { ConsumeToken(); DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -357,11 +358,12 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, /// ParseDeclGroup - Having concluded that this is either a function /// definition or a group of object declarations, actually parse the /// result. -Parser::DeclGroupPtrTy Parser::ParseDeclGroup(DeclSpec &DS, unsigned Context, +Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, + unsigned Context, bool AllowFunctionDefinitions, SourceLocation *DeclEnd) { // Parse the first declarator. - Declarator D(DS, static_cast<Declarator::TheContext>(Context)); + ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Context)); ParseDeclarator(D); // Bail out if the first declarator didn't seem well-formed. @@ -397,6 +399,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(DeclSpec &DS, unsigned Context, llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup; DeclPtrTy FirstDecl = ParseDeclarationAfterDeclarator(D); + D.complete(FirstDecl); if (FirstDecl.get()) DeclsInGroup.push_back(FirstDecl); @@ -425,6 +428,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(DeclSpec &DS, unsigned Context, ParseDeclarator(D); DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D); + D.complete(ThisDecl); if (ThisDecl.get()) DeclsInGroup.push_back(ThisDecl); } @@ -1505,6 +1509,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { // Read struct-declarators until we find the semicolon. bool FirstDeclarator = true; while (1) { + ParsingDeclRAIIObject PD(*this); FieldDeclarator DeclaratorInfo(DS); // Attributes are only allowed here on successive declarators. @@ -1536,7 +1541,8 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { } // We're done with this declarator; invoke the callback. - (void) Fields.invoke(DeclaratorInfo); + DeclPtrTy D = Fields.invoke(DeclaratorInfo); + PD.complete(D); // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. @@ -2587,6 +2593,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, SourceLocation DSStart = Tok.getLocation(); // Parse the declaration-specifiers. + // Just use the ParsingDeclaration "scope" of the declarator. DeclSpec DS; // If the caller parsed attributes for the first argument, add them now. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index a8e127610c..91f86864f8 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1099,7 +1099,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SourceLocation DSStart = Tok.getLocation(); // decl-specifier-seq: // Parse the common declaration-specifiers piece. - DeclSpec DS; + ParsingDeclSpec DS(*this); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class); Action::MultiTemplateParamsArg TemplateParams(Actions, @@ -1112,7 +1112,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } - Declarator DeclaratorInfo(DS, Declarator::MemberContext); + ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); if (Tok.isNot(tok::colon)) { // Parse the first declarator. @@ -1231,6 +1231,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, HandleMemberFunctionDefaultArgs(DeclaratorInfo, ThisDecl); } + DeclaratorInfo.complete(ThisDecl); + // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. if (Tok.isNot(tok::comma)) diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 65d71ae481..b043dd99f3 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -698,6 +698,8 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType, DeclPtrTy IDecl, tok::ObjCKeywordKind MethodImplKind) { + ParsingDeclRAIIObject PD(*this); + // Parse the return type if present. TypeTy *ReturnType = 0; ObjCDeclSpec DSRet; @@ -724,10 +726,13 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, MethodAttrs = ParseAttributes(); Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); - return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), + DeclPtrTy Result + = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, 0, CargNames, MethodAttrs, MethodImplKind); + PD.complete(Result); + return Result; } llvm::SmallVector<IdentifierInfo *, 12> KeyIdents; @@ -800,10 +805,13 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, return DeclPtrTy(); Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(), &KeyIdents[0]); - return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), + DeclPtrTy Result + = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, &ArgInfos[0], CargNames, MethodAttrs, MethodImplKind, isVariadic); + PD.complete(Result); + return Result; } /// objc-protocol-refs: diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index a647720fb9..045acd86ad 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -190,16 +190,18 @@ Parser::ParseSingleDeclarationAfterTemplate( } // Parse the declaration specifiers. - DeclSpec DS; + ParsingDeclSpec DS(*this); ParseDeclarationSpecifiers(DS, TemplateInfo, AS); if (Tok.is(tok::semi)) { DeclEnd = ConsumeToken(); - return Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DeclPtrTy Decl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DS.complete(Decl); + return Decl; } // Parse the declarator. - Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context); + ParsingDeclarator DeclaratorInfo(*this, DS, (Declarator::TheContext)Context); ParseDeclarator(DeclaratorInfo); // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { @@ -225,6 +227,7 @@ Parser::ParseSingleDeclarationAfterTemplate( // Eat the semi colon after the declaration. ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); + DS.complete(ThisDecl); return ThisDecl; } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 6836c307d3..335a6cf362 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -526,7 +526,7 @@ bool Parser::isStartOfFunctionDefinition() { Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { // Parse the common declaration-specifiers piece. - DeclSpec DS; + ParsingDeclSpec DS(*this); ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" @@ -534,6 +534,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { if (Tok.is(tok::semi)) { ConsumeToken(); DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -549,6 +550,8 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { return DeclGroupPtrTy(); } + DS.abort(); + const char *PrevSpec = 0; unsigned DiagID; if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID)) @@ -568,6 +571,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { if (Tok.is(tok::string_literal) && getLang().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_extern && DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { + DS.abort(); DeclPtrTy TheDecl = ParseLinkage(Declarator::FileContext); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -589,7 +593,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { /// [C++] function-definition: [C++ 8.4] /// decl-specifier-seq[opt] declarator function-try-block /// -Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D, +Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo) { const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0); assert(FnTypeInfo.Kind == DeclaratorChunk::Function && @@ -641,6 +645,13 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D, D) : Actions.ActOnStartOfFunctionDef(CurScope, D); + // Break out of the ParsingDeclarator context before we parse the body. + D.complete(Res); + + // Break out of the ParsingDeclSpec context, too. This const_cast is + // safe because we're always the sole owner. + D.getMutableDeclSpec().abort(); + if (Tok.is(tok::kw_try)) return ParseFunctionTryBlock(Res); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 64007f2323..8104dd39d0 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -350,7 +350,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), ExternalSource(0), CodeCompleter(0), CurContext(0), - PreDeclaratorDC(0), CurBlock(0), PackContext(0), + PreDeclaratorDC(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0), IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0), GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated), CompleteTranslationUnit(CompleteTranslationUnit), diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 53f0d7a192..bb59e1c9f4 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -272,6 +272,15 @@ public: llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions; std::vector<DeclarationName> TentativeDefinitionList; + /// \brief The collection of delayed deprecation warnings. + llvm::SmallVector<std::pair<SourceLocation,NamedDecl*>, 8> + DelayedDeprecationWarnings; + + /// \brief The depth of the current ParsingDeclaration stack. + /// If nonzero, we are currently parsing a declaration (and + /// hence should delay deprecation warnings). + unsigned ParsingDeclDepth; + /// WeakUndeclaredIdentifiers - Identifiers contained in /// #pragma weak before declared. rare. may alias another /// identifier, declared or undeclared @@ -1586,11 +1595,14 @@ public: /// whose result is unused, warn. void DiagnoseUnusedExprResult(const Stmt *S); + ParsingDeclStackState PushParsingDeclaration(); + void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D); + void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc); + //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. - bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, - bool IgnoreDeprecated = false); + bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc); bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, ObjCMethodDecl *Getter, SourceLocation Loc); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 82d467f966..d89cb5fc97 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -138,9 +138,11 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, } assert(IIDecl && "Didn't find decl"); - + QualType T; if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) { + DiagnoseUseOfDecl(IIDecl, NameLoc); + // C++ [temp.local]p2: // Within the scope of a class template specialization or // partial specialization, when the injected-class-name is @@ -160,6 +162,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, T = getQualifiedNameType(*SS, T); } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { + DiagnoseUseOfDecl(IIDecl, NameLoc); T = Context.getObjCInterfaceType(IDecl); } else return 0; diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 3995e9b11e..a3f8eb5a0e 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1949,3 +1949,62 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { if (const AttributeList *Attrs = PD.getAttributes()) ProcessDeclAttributeList(S, D, Attrs); } + +/// PushParsingDeclaration - Enter a new "scope" of deprecation +/// warnings. +/// +/// The state token we use is the start index of this scope +/// on the warning stack. +Action::ParsingDeclStackState Sema::PushParsingDeclaration() { + ParsingDeclDepth++; + return (ParsingDeclStackState) DelayedDeprecationWarnings.size(); +} + +static bool isDeclDeprecated(Decl *D) { + do { + if (D->hasAttr<DeprecatedAttr>()) + return true; + } while ((D = cast_or_null<Decl>(D->getDeclContext()))); + return false; +} + +void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) { + assert(ParsingDeclDepth > 0 && "empty ParsingDeclaration stack"); + ParsingDeclDepth--; + + if (DelayedDeprecationWarnings.empty()) + return; + + unsigned SavedIndex = (unsigned) S; + assert(SavedIndex <= DelayedDeprecationWarnings.size() && + "saved index is out of bounds"); + + if (Ctx && !isDeclDeprecated(Ctx.getAs<Decl>())) { + for (unsigned I = 0, E = DelayedDeprecationWarnings.size(); I != E; ++I) { + SourceLocation Loc = DelayedDeprecationWarnings[I].first; + NamedDecl *&ND = DelayedDeprecationWarnings[I].second; + if (ND) { + Diag(Loc, diag::warn_deprecated) << ND->getDeclName(); + + // Prevent this from triggering multiple times. + ND = 0; + } + } + } + + DelayedDeprecationWarnings.set_size(SavedIndex); +} + +void Sema::EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc) { + // Delay if we're currently parsing a declaration. + if (ParsingDeclDepth) { + DelayedDeprecationWarnings.push_back(std::make_pair(Loc, D)); + return; + } + + // Otherwise, don't warn if our current context is deprecated. + if (isDeclDeprecated(cast<Decl>(CurContext))) + return; + + Diag(Loc, diag::warn_deprecated) << D->getDeclName(); +} diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 46c6bf45ad..93f8d0dc37 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1748,6 +1748,8 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( if (AttrList) ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList); + const ObjCMethodDecl *InterfaceMD = 0; + // For implementations (which can be very "coarse grain"), we add the // method now. This allows the AST to implement lookup methods that work // incrementally (without waiting until we parse the @end). It also allows @@ -1761,6 +1763,8 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( PrevMethod = ImpDecl->getClassMethod(Sel); ImpDecl->addClassMethod(ObjCMethod); } + InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel, + MethodType == tok::minus); if (AttrList) Diag(EndLoc, diag::warn_attribute_method_def); } else if (ObjCCategoryImplDecl *CatImpDecl = @@ -1781,6 +1785,12 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( << ObjCMethod->getDeclName(); Diag(PrevMethod->getLocation(), diag::note_previous_declaration); } + + // If the interface declared this method, and it was deprecated there, + // mark it deprecated here. + if (InterfaceMD && InterfaceMD->hasAttr<DeprecatedAttr>()) + ObjCMethod->addAttr(::new (Context) DeprecatedAttr()); + return DeclPtrTy::make(ObjCMethod); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 4dd3c2dbef..f1014c6dfe 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -43,36 +43,10 @@ using namespace clang; /// \returns true if there was an error (this declaration cannot be /// referenced), false otherwise. /// -bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, - bool IgnoreDeprecated) { +bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { // See if the decl is deprecated. if (D->getAttr<DeprecatedAttr>()) { - // Implementing deprecated stuff requires referencing deprecated - // stuff. Don't warn if we are implementing a deprecated construct. - bool isSilenced = IgnoreDeprecated; - - if (NamedDecl *ND = getCurFunctionOrMethodDecl()) { - // If this reference happens *in* a deprecated function or method, don't - // warn. - isSilenced |= ND->getAttr<DeprecatedAttr>() != 0; - - // If this is an Objective-C method implementation, check to see if the - // method was deprecated on the declaration, not the definition. - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND)) { - // The semantic decl context of a ObjCMethodDecl is the - // ObjCImplementationDecl. - if (ObjCImplementationDecl *Impl - = dyn_cast<ObjCImplementationDecl>(MD->getParent())) { - - MD = Impl->getClassInterface()->getMethod(MD->getSelector(), - MD->isInstanceMethod()); - isSilenced |= MD && MD->getAttr<DeprecatedAttr>(); - } - } - } - - if (!isSilenced) - Diag(Loc, diag::warn_deprecated) << D->getDeclName(); + EmitDeprecationWarning(D, Loc); } // See if the decl is unavailable diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 94b74fbcd1..0003b1b0c4 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -67,16 +67,6 @@ static bool isOmittedBlockReturnType(const Declarator &D) { return false; } -/// isDeclaratorDeprecated - Return true if the declarator is deprecated. -/// We do not want to warn about use of deprecated types (e.g. typedefs) when -/// defining a declaration that is itself deprecated. -static bool isDeclaratorDeprecated(const Declarator &D) { - for (const AttributeList *AL = D.getAttributes(); AL; AL = AL->getNext()) - if (AL->getKind() == AttributeList::AT_deprecated) - return true; - return false; -} - /// \brief Convert the specified declspec to the appropriate type /// object. /// \param D the declarator containing the declaration specifier. @@ -247,8 +237,7 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){ } // If the type is deprecated or unavailable, diagnose it. - TheSema.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeLoc(), - isDeclaratorDeprecated(TheDeclarator)); + TheSema.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeLoc()); assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "No qualifiers on tag names!"); @@ -303,27 +292,6 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){ } } - // If this is a reference to an invalid typedef, propagate the invalidity. - if (TypedefType *TDT = dyn_cast<TypedefType>(Result)) { - if (TDT->getDecl()->isInvalidDecl()) - TheDeclarator.setInvalidType(true); - - // If the type is deprecated or unavailable, diagnose it. - TheSema.DiagnoseUseOfDecl(TDT->getDecl(), DS.getTypeSpecTypeLoc(), - isDeclaratorDeprecated(TheDeclarator)); - } else if (ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(Result)) { - // If the type is deprecated or unavailable, diagnose it. - TheSema.DiagnoseUseOfDecl(OIT->getDecl(), DS.getTypeSpecTypeLoc(), - isDeclaratorDeprecated(TheDeclarator)); - } else if (ObjCObjectPointerType *DPT = - dyn_cast<ObjCObjectPointerType>(Result)) { - // If the type is deprecated or unavailable, diagnose it. - if (ObjCInterfaceDecl *D = DPT->getInterfaceDecl()) - TheSema.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeLoc(), - isDeclaratorDeprecated(TheDeclarator)); - } - - // TypeQuals handled by caller. break; } diff --git a/test/Sema/attr-deprecated.c b/test/Sema/attr-deprecated.c index 527f0106d4..4b889fc8aa 100644 --- a/test/Sema/attr-deprecated.c +++ b/test/Sema/attr-deprecated.c @@ -55,3 +55,48 @@ struct bar_dep *test3; // expected-warning {{'bar_dep' is deprecated}} foo_dep *test4 __attribute__((deprecated)); struct bar_dep *test5 __attribute__((deprecated)); +typedef foo_dep test6(struct bar_dep*); // expected-warning {{'foo_dep' is deprecated}} \ + // expected-warning {{'bar_dep' is deprecated}} +typedef foo_dep test7(struct bar_dep*) __attribute__((deprecated)); + +int test8(char *p) { + p += sizeof(foo_dep); // expected-warning {{'foo_dep' is deprecated}} + + foo_dep *ptr; // expected-warning {{'foo_dep' is deprecated}} + ptr = (foo_dep*) p; // expected-warning {{'foo_dep' is deprecated}} + + int func(foo_dep *foo); // expected-warning {{'foo_dep' is deprecated}} + return func(ptr); +} + +foo_dep *test9(void) __attribute__((deprecated)); +foo_dep *test9(void) { + void* myalloc(unsigned long); + + foo_dep *ptr + = (foo_dep*) + myalloc(sizeof(foo_dep)); + return ptr; +} + +void test10(void) __attribute__((deprecated)); +void test10(void) { + if (sizeof(foo_dep) == sizeof(void*)) { + } + foo_dep *localfunc(void); + foo_dep localvar; +} + +char test11[sizeof(foo_dep)] __attribute__((deprecated)); +char test12[sizeof(foo_dep)]; // expected-warning {{'foo_dep' is deprecated}} + +int test13(foo_dep *foo) __attribute__((deprecated)); +int test14(foo_dep *foo); // expected-warning {{'foo_dep' is deprecated}} + +unsigned long test15 = sizeof(foo_dep); // expected-warning {{'foo_dep' is deprecated}} +unsigned long test16 __attribute__((deprecated)) + = sizeof(foo_dep); + +foo_dep test17, // expected-warning {{'foo_dep' is deprecated}} + test18 __attribute__((deprecated)), + test19; |