beanz updated this revision to Diff 361480.
beanz added a comment.

Updating comment about remaining bits.
Rather than subtracting one, I re-added up the bits. The bitfield is now at
40 bits, so it only has 24 bits remaining (someone please check my math).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106732/new/

https://reviews.llvm.org/D106732

Files:
  clang/docs/LanguageExtensions.rst
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/include/clang/Basic/DiagnosticLexKinds.td
  clang/include/clang/Basic/IdentifierTable.h
  clang/include/clang/Lex/Preprocessor.h
  clang/lib/Lex/PPMacroExpansion.cpp
  clang/lib/Lex/Pragma.cpp
  clang/test/Lexer/deprecate-macro.c

Index: clang/test/Lexer/deprecate-macro.c
===================================================================
--- /dev/null
+++ clang/test/Lexer/deprecate-macro.c
@@ -0,0 +1,42 @@
+// RUN: not %clang_cc1 -Wdeprecated %s -fsyntax-only
+
+// expected-error@+1{{expected '(' in #pragma clang deprecated}}
+#pragma clang deprecated
+
+// expected-error@+1{{expected string literal in #pragma clang deprecated}}
+#pragma clang deprecated(4
+
+// expected-error@+1{{expected string literal in #pragma clang deprecated}}
+#pragma clang deprecated(foo)
+
+// expected-warning@+1{{'foo' is not a defined macro for #pragma clang deprecated}}
+#pragma clang deprecated("foo")
+
+#define bar 1
+#pragma clang deprecated("bar", "bar is deprecated use 1")
+
+// expected-warning@+1{{macro 'bar' has been marked as deprecated: Bar is deprecated use 1}}
+#if bar
+#endif
+
+#define foo 1
+#pragma clang deprecated("foo")
+
+// expected-error@+1{{expected ')' in #pragma clang deprecated}}
+#pragma clang deprecated("foo"
+
+// expected-warning@+1{{macro 'foo' has been marked as deprecated}}
+#if foo
+#endif
+
+// expected-warning@+1{{macro 'foo' has been marked as deprecated}}
+#if defined(foo)
+#endif
+
+int main(int argc, char** argv) {
+  // expected-warning@+1{{#pragma clang deprecate 'main' is not a defined macro}}
+#pragma clang deprecated("main")
+
+  // expected-warning@+1{{macro 'foo' has been marked as deprecated}}
+  return foo;
+}
Index: clang/lib/Lex/Pragma.cpp
===================================================================
--- clang/lib/Lex/Pragma.cpp
+++ clang/lib/Lex/Pragma.cpp
@@ -1911,6 +1911,54 @@
   }
 };
 
+/// "\#pragma deprecate()"
+///
+/// The syntax is
+/// \code
+///   #pragma clang deprecate(MACRO_NAME)
+/// \endcode
+struct PragmaDeprecatedHandler : public PragmaHandler {
+  PragmaDeprecatedHandler() : PragmaHandler("deprecated") {}
+
+  void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
+                    Token &Tok) override {
+    std::string Macro, MessageString;
+
+    PP.Lex(Tok);
+    if (Tok.isNot(tok::l_paren)) {
+      PP.Diag(Tok, diag::err_pragma_deprecated_expected) << "(";
+      return;
+    }
+
+    PP.Lex(Tok);
+    if (!PP.FinishLexStringLiteral(Tok, Macro, "#pragma clang deprecated",
+                                   /*AllowMacroExpansion=*/true))
+      return;
+    IdentifierInfo *II = PP.getIdentifierInfo(Macro);
+
+    if (!II->hasMacroDefinition() || !II->hadMacroDefinition()) {
+      PP.Diag(Tok, diag::warn_pragma_deprecated_not_a_macro) << II->getName();
+      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(Tok, diag::err_pragma_deprecated_expected) << ")";
+      return;
+    }
+
+    II->setIsDeprecatedMacro(true);
+    PP.addMacroDeprecationMsg(II, std::move(MessageString));
+  }
+};
+
 } // namespace
 
 /// RegisterBuiltinPragmas - Install the standard preprocessor pragmas:
@@ -1939,6 +1987,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/lib/Lex/PPMacroExpansion.cpp
===================================================================
--- clang/lib/Lex/PPMacroExpansion.cpp
+++ clang/lib/Lex/PPMacroExpansion.cpp
@@ -471,6 +471,16 @@
 /// expanded as a macro, handle it and return the next token as 'Identifier'.
 bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
                                                  const MacroDefinition &M) {
+  if (Identifier.getIdentifierInfo()->isDeprecatedMacro()) {
+    auto MsgEntry = MacroDeprecationMsgs.find(Identifier.getIdentifierInfo());
+    if (MsgEntry == MacroDeprecationMsgs.end())
+      Diag(Identifier, diag::warn_pragma_deprecated_macro_use)
+          << Identifier.getIdentifierInfo()->getName();
+    else
+      Diag(Identifier, diag::warn_pragma_deprecated_macro_use_msg)
+          << Identifier.getIdentifierInfo()->getName() << MsgEntry->second;
+  }
+
   MacroInfo *MI = M.getMacroInfo();
 
   // If this is a macro expansion in the "#if !defined(x)" line for the file,
Index: clang/include/clang/Lex/Preprocessor.h
===================================================================
--- clang/include/clang/Lex/Preprocessor.h
+++ clang/include/clang/Lex/Preprocessor.h
@@ -786,6 +786,9 @@
   using WarnUnusedMacroLocsTy = llvm::SmallDenseSet<SourceLocation, 32>;
   WarnUnusedMacroLocsTy WarnUnusedMacroLocs;
 
+  /// Deprecation messages for macros provided in #pragma clang deprecated
+  llvm::DenseMap<const IdentifierInfo *, std::string> MacroDeprecationMsgs;
+
   /// A "freelist" of MacroArg objects that can be
   /// reused for quick allocation.
   MacroArgs *MacroArgCache = nullptr;
@@ -2385,6 +2388,10 @@
   /// warnings.
   void markMacroAsUsed(MacroInfo *MI);
 
+  void addMacroDeprecationMsg(IdentifierInfo *II, std::string Msg) {
+    MacroDeprecationMsgs.insert(std::make_pair(II, Msg));
+  }
+
 private:
   Optional<unsigned>
   getSkippedRangeForExcludedConditionalBlock(SourceLocation HashLoc);
Index: clang/include/clang/Basic/IdentifierTable.h
===================================================================
--- clang/include/clang/Basic/IdentifierTable.h
+++ clang/include/clang/Basic/IdentifierTable.h
@@ -121,7 +121,10 @@
   // True if this is a mangled OpenMP variant name.
   unsigned IsMangledOpenMPVariantName : 1;
 
-  // 28 bits left in a 64-bit word.
+  // True if this is a deprecated macro
+  unsigned IsDeprecatedMacro : 1;
+
+  // 24 bits left in a 64-bit word.
 
   // Managed by the language front-end.
   void *FETokenInfo = nullptr;
@@ -134,7 +137,8 @@
         IsPoisoned(false), IsCPPOperatorKeyword(false),
         NeedsHandleIdentifier(false), IsFromAST(false), ChangedAfterLoad(false),
         FEChangedAfterLoad(false), RevertedTokenID(false), OutOfDate(false),
-        IsModulesImport(false), IsMangledOpenMPVariantName(false) {}
+        IsModulesImport(false), IsMangledOpenMPVariantName(false),
+        IsDeprecatedMacro(false) {}
 
 public:
   IdentifierInfo(const IdentifierInfo &) = delete;
@@ -192,6 +196,17 @@
     return HadMacro;
   }
 
+  bool isDeprecatedMacro() const { return IsDeprecatedMacro; }
+
+  void setIsDeprecatedMacro(bool Val) {
+    if (IsDeprecatedMacro == Val)
+      return;
+    if (Val) {
+      NeedsHandleIdentifier = true;
+      IsDeprecatedMacro = true;
+    }
+  }
+
   /// If this is a source-language token (e.g. 'for'), this API
   /// can be used to cause the lexer to map identifiers to source-language
   /// tokens.
Index: clang/include/clang/Basic/DiagnosticLexKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticLexKinds.td
+++ clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -519,6 +519,19 @@
   ExtWarn<"#pragma warning expected a warning number">,
   InGroup<UnknownPragmas>;
 
+// - #pragma deprecate(...)
+def err_pragma_deprecated_expected :
+  Error<"expected '%0' in #pragma clang deprecate">;
+def warn_pragma_deprecated_not_a_macro :
+  ExtWarn<"'%0' is not a defined macro for #pragma clang deprecate">,
+  InGroup<DeprecatedPragma>;
+def warn_pragma_deprecated_macro_use :
+  ExtWarn<"macro '%0' has been marked as deprecated">,
+  InGroup<DeprecatedPragma>;
+def warn_pragma_deprecated_macro_use_msg :
+  ExtWarn<"macro '%0' has been marked as 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
@@ -184,6 +184,7 @@
 def DeprecatedVolatile : DiagGroup<"deprecated-volatile">;
 def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings",
                                       [CXX11CompatDeprecatedWritableStr]>;
+def DeprecatedPragma : DiagGroup<"deprecated-pragma">;
 // FIXME: Why is DeprecatedImplementations not in this group?
 def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
                                           DeprecatedArrayCompare,
@@ -198,6 +199,7 @@
                                           DeprecatedEnumEnumConversion,
                                           DeprecatedEnumFloatConversion,
                                           DeprecatedIncrementBool,
+                                          DeprecatedPragma,
                                           DeprecatedRegister,
                                           DeprecatedThisCapture,
                                           DeprecatedVolatile,
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -3864,6 +3864,24 @@
 as ``__builtin_dynamic_object_size(buffer, 0)``, Clang will fold it into
 ``size``, providing some extra runtime safety.
 
+Deprecating Macros
+==================
+
+Clang supports the pragma ``#pragma clang deprecated``, which can be used to
+provide deprecation warnings for macro uses. For example:
+
+.. code-block:: c
+   #define MIN(x, y) x < y ? x : y
+   #pragma clang deprecated("MIN", "use std::min instead")
+
+   void min(int a, int b) {
+     return MIN(a, b); // warning: MIN is deprecated: use std::min instead
+   }
+
+``#pragma clang deprecated`` should be preferred for this purpose over
+``#pragma GCC warning`` because the warning can be controlled with
+``-Wdeprecated``.
+
 Extended Integer Types
 ======================
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to