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
  • [PATCH] D67935: Add `#prag... Erik Pilkington via Phabricator via cfe-commits

Reply via email to