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``. 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/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; +// - #pragma clang deprecated +def warn_pragma_deprecated : + Warning<"'%0' is deprecated">, InGroup; +def warn_pragma_deprecated_msg : + Warning<"'%0' is deprecated: %1">, InGroup; + // - #pragma execution_character_set(...) def warn_pragma_exec_charset_expected : ExtWarn<"#pragma execution_character_set expected '%0'">, 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/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