erik.pilkington created this revision. erik.pilkington added reviewers: rsmith, aaron.ballman. Herald added subscribers: ributzka, dexonsmith, jkorous. Herald added a project: clang.
This patch adds support for `#pragma clang deprecated`, which emits a deprecated warning whenever it is encountered. This is intended to be used to deprecate macros, but it seems like it could be useful for deprecating include files as well (rather than `#warning`). This is similar to `#pragma GCC warning`, but that can't emit a diagnostic under `-Wdeprecated`, so these warnings wouldn't be controlled by traditional deprecation disabling methods. (`-Wno-deprecated`, `#pragma clang diagnostic ignored`). rdar://problem/50356322 clang should provide a pragma to allow us to deprecate macros Repository: rC Clang https://reviews.llvm.org/D67935 Files: clang/docs/LanguageExtensions.rst clang/include/clang/Basic/DiagnosticGroups.td clang/include/clang/Basic/DiagnosticLexKinds.td clang/lib/Lex/Pragma.cpp clang/test/Lexer/pragma-deprecated.c
Index: clang/test/Lexer/pragma-deprecated.c =================================================================== --- /dev/null +++ clang/test/Lexer/pragma-deprecated.c @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -verify -Wdeprecated-pragma %s + +#define STR(x) #x +#define DEPRECATED_MACRO(entity, message) \ + _Pragma(STR(clang deprecated(entity, message))) + +#define FOO DEPRECATED_MACRO("foo", "use bar") 43 + +__attribute__((deprecated)) +int f(); + +int main() { + return FOO; // expected-warning{{'foo' is deprecated: use bar}} +} + +// expected-warning@+1{{'"flerp.h"' is deprecated: use "flarp.h" instead}} +#pragma clang deprecated("\"flerp.h\"", "use \"flarp.h\" instead") + +// expected-warning@+1{{'flerp' is deprecated}} +#pragma clang deprecated("flerp") + +// expected-error@+1 {{expected '('}} +#pragma clang deprecated +// expected-error@+1 {{expected string literal in #pragma clang deprecated}} +#pragma clang deprecated(43) +// expected-error@+1 {{expected string literal in #pragma clang deprecated}} +#pragma clang deprecated ("foo", 33) +// expected-error@+1 {{expected ')'}} +#pragma clang deprecated ("foo", "bar" +// expected-warning@+2 {{extra tokens at end of #pragma directive}} +// expected-warning@+1 {{'foo' is deprecated: bar}} +#pragma clang deprecated ("foo", "bar") baz Index: clang/lib/Lex/Pragma.cpp =================================================================== --- clang/lib/Lex/Pragma.cpp +++ clang/lib/Lex/Pragma.cpp @@ -1517,6 +1517,59 @@ } }; +/// Handle '#pragma clang deprecated'. The syntax is: +/// +/// \code +/// #pragma clang deprecated("entity", "message") +/// \endcode +/// +/// The message is optional. This is used to deprecate macros (via _Pragma), or +/// files. +struct PragmaDeprecatedHandler : public PragmaHandler { + PragmaDeprecatedHandler() : PragmaHandler("deprecated") {} + + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &NameTok) override { + SourceLocation Loc = NameTok.getLocation(); + std::string EntityString, MessageString; + Token Tok; + + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Loc, diag::err_expected) << tok::l_paren; + return; + } + + PP.Lex(Tok); + if (!PP.FinishLexStringLiteral(Tok, EntityString, + "#pragma clang deprecated", + /*AllowMacroExpansion=*/true)) + return; + + if (Tok.is(tok::comma)) { + PP.Lex(Tok); + if (!PP.FinishLexStringLiteral(Tok, MessageString, + "#pragma clang deprecated", + /*AllowMacroExpansion=*/true)) + return; + } + + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Loc, diag::err_expected) << tok::r_paren; + return; + } + + PP.Lex(Tok); + if (Tok.isNot(tok::eod)) + PP.Diag(Loc, diag::ext_pp_extra_tokens_at_eol) << "pragma"; + + unsigned DiagID = MessageString.empty() ? diag::warn_pragma_deprecated + : diag::warn_pragma_deprecated_msg; + DiagnosticBuilder Builder = PP.Diag(Loc, DiagID) + << EntityString << MessageString; + } +}; + /// Handle the clang \#pragma module import extension. The syntax is: /// \code /// #pragma clang module import some.module.name @@ -1858,6 +1911,7 @@ AddPragmaHandler("clang", new PragmaDiagnosticHandler("clang")); AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler()); AddPragmaHandler("clang", new PragmaAssumeNonNullHandler()); + AddPragmaHandler("clang", new PragmaDeprecatedHandler); // #pragma clang module ... auto *ModuleHandler = new PragmaNamespace("module"); Index: clang/include/clang/Basic/DiagnosticLexKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticLexKinds.td +++ clang/include/clang/Basic/DiagnosticLexKinds.td @@ -511,6 +511,12 @@ ExtWarn<"#pragma warning expected a warning number">, InGroup<UnknownPragmas>; +// - #pragma clang deprecated +def warn_pragma_deprecated : + Warning<"'%0' is deprecated">, InGroup<DeprecatedPragma>; +def warn_pragma_deprecated_msg : + Warning<"'%0' is deprecated: %1">, InGroup<DeprecatedPragma>; + // - #pragma execution_character_set(...) def warn_pragma_exec_charset_expected : ExtWarn<"#pragma execution_character_set expected '%0'">, Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -128,6 +128,7 @@ def DeprecatedAttributes : DiagGroup<"deprecated-attributes">; def DeprecatedCommaSubscript : DiagGroup<"deprecated-comma-subscript">; def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">; +def DeprecatedPragma : DiagGroup<"deprecated-pragma">; def UnavailableDeclarations : DiagGroup<"unavailable-declarations">; def UnguardedAvailabilityNew : DiagGroup<"unguarded-availability-new">; def UnguardedAvailability : DiagGroup<"unguarded-availability", @@ -146,6 +147,7 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAttributes, DeprecatedCommaSubscript, DeprecatedDeclarations, + DeprecatedPragma, DeprecatedDynamicExceptionSpec, DeprecatedIncrementBool, DeprecatedRegister, Index: clang/docs/LanguageExtensions.rst =================================================================== --- clang/docs/LanguageExtensions.rst +++ clang/docs/LanguageExtensions.rst @@ -3501,3 +3501,27 @@ ``__builtin_object_size(buffer, 0)`` into ``-1``. However, if this was written as ``__builtin_dynamic_object_size(buffer, 0)``, Clang will fold it into ``size``, providing some extra runtime safety. + +Deprecating Macros and Files +============================ + +Clang supports the pragma ``#pragma clang deprecated``, which is useful for +deprecating macros or files. For instance: + +.. code-block:: c + + #define STR(x) #x + #define DEPRECATED_MACRO(entity, message) \ + _Pragma(STR(clang deprecated(entity, message))) + + #define SWAP(x, y) \ + DEPRECATED_MACRO("SWAP", "use std::swap instead") \ + ((x) ^= (y), (y) ^= (x), (x) ^= (y)) + + void f(int a, int b) { + SWAP(a, b); // warning: SWAP is deprecated: use std::swap instead + } + +``#pragma clang deprecated`` should be preferred for this purpose over +``#pragma GCC warning`` because the warning can be controlled with +``-Wdeprecated``.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits