r224512 - Fixed warnings on redefine keywords and reserved ids.

Serge Pavlov sepavloff at gmail.com
Thu Dec 18 03:14:21 PST 2014


Author: sepavloff
Date: Thu Dec 18 05:14:21 2014
New Revision: 224512

URL: http://llvm.org/viewvc/llvm-project?rev=224512&view=rev
Log:
Fixed warnings on redefine keywords and reserved ids.

Repared support for warnings -Wkeyword-macro and -Wreserved-id-macro.
The warning -Wkeyword-macro now is not issued in patterns that are used
in configuration scripts:

    #define inline

also for 'const', 'extern' and 'static'. If macro repalcement is identical
to macro name, the warning also is not issued:

    #define volatile volatile

And finally if macro replacement is also a keyword identical to the replaced
one but decorated with leading/trailing underscores:

    #define inline __inline
    #define inline __inline__
    #define inline _inline // in MSVC compatibility mode

Warning -Wreserved-id-macro is off by default, it could help catching
things like:

    #undef __cplusplus

Added:
    cfe/trunk/test/Preprocessor/macro-reserved-cxx11.cpp
    cfe/trunk/test/Preprocessor/macro-reserved-ms.c
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/lib/Lex/PPDirectives.cpp
    cfe/trunk/test/Preprocessor/macro-reserved.c
    cfe/trunk/test/Preprocessor/macro-reserved.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=224512&r1=224511&r2=224512&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Thu Dec 18 05:14:21 2014
@@ -338,6 +338,7 @@ def : DiagGroup<"sequence-point", [Unseq
 // Preprocessor warnings.
 def AmbiguousMacro : DiagGroup<"ambiguous-macro">;
 def KeywordAsMacro : DiagGroup<"keyword-macro">;
+def ReservedIdAsMacro : DiagGroup<"reserved-id-macro">;
 
 // Just silence warnings about -Wstrict-aliasing for now.
 def : DiagGroup<"strict-aliasing=0">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=224512&r1=224511&r2=224512&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Thu Dec 18 05:14:21 2014
@@ -292,6 +292,9 @@ def note_pp_ambiguous_macro_other : Note
   "other definition of %0">;
 def warn_pp_macro_hides_keyword : Extension<
   "keyword is hidden by macro definition">, InGroup<KeywordAsMacro>;
+def warn_pp_macro_is_reserved_id : Warning<
+  "macro name is a reserved identifier">, DefaultIgnore,
+  InGroup<ReservedIdAsMacro>;
 
 def pp_invalid_string_literal : Warning<
   "invalid string literal, ignoring final '\\'">;

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=224512&r1=224511&r2=224512&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Thu Dec 18 05:14:21 2014
@@ -1380,7 +1380,8 @@ public:
   /// followed by EOD.  Return true if the token is not a valid on-off-switch.
   bool LexOnOffSwitch(tok::OnOffSwitch &OOS);
 
-  bool CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef);
+  bool CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
+                      bool *ShadowFlag = nullptr);
 
 private:
 
@@ -1420,11 +1421,17 @@ private:
                                                              bool isPublic);
 
   /// \brief Lex and validate a macro name, which occurs after a
-  /// \#define or \#undef. 
+  /// \#define or \#undef.
+  ///
+  /// \param MacroNameTok Token that represents the name defined or undefined.
+  /// \param IsDefineUndef Kind if preprocessor directive.
+  /// \param ShadowFlag Points to flag that is set if macro name shadows
+  ///                   a keyword.
   ///
   /// This emits a diagnostic, sets the token kind to eod,
   /// and discards the rest of the macro line if the macro name is invalid.
-  void ReadMacroName(Token &MacroNameTok, MacroUse isDefineUndef = MU_Other);
+  void ReadMacroName(Token &MacroNameTok, MacroUse IsDefineUndef = MU_Other,
+                     bool *ShadowFlag = nullptr);
 
   /// The ( starting an argument list of a macro definition has just been read.
   /// Lex the rest of the arguments and the closing ), updating \p MI with

Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=224512&r1=224511&r2=224512&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
+++ cfe/trunk/lib/Lex/PPDirectives.cpp Thu Dec 18 05:14:21 2014
@@ -100,18 +100,56 @@ void Preprocessor::DiscardUntilEndOfDire
   } while (Tmp.isNot(tok::eod));
 }
 
-static bool shouldWarnOnMacroDef(Preprocessor &PP, IdentifierInfo *II) {
+/// \brief Enumerates possible cases of #define/#undef a reserved identifier.
+enum MacroDiag {
+  MD_NoWarn,        //> Not a reserved identifier
+  MD_KeywordDef,    //> Macro hides keyword, enabled by default
+  MD_ReservedMacro  //> #define of #undef reserved id, disabled by default
+};
+
+/// \brief Checks if the specified identifier is reserved in the specified
+/// language.
+/// This function does not check if the identifier is a keyword.
+static bool isReservedId(StringRef Text, const LangOptions &Lang) {
+  // C++ [macro.names], C11 7.1.3:
+  // All identifiers that begin with an underscore and either an uppercase
+  // letter or another underscore are always reserved for any use.
+  if (Text.size() >= 2 && Text[0] == '_' &&
+      (isUppercase(Text[1]) || Text[1] == '_'))
+      return true;
+  // C++ [global.names]
+  // Each name that contains a double underscore ... is reserved to the
+  // implementation for any use.
+  if (Lang.CPlusPlus) {
+    if (Text.find("__") != StringRef::npos)
+      return true;
+  }
+  return false;
+}
+
+static MacroDiag shouldWarnOnMacroDef(Preprocessor &PP, IdentifierInfo *II) {
   const LangOptions &Lang = PP.getLangOpts();
   StringRef Text = II->getName();
-  // Do not warn on keyword undef.  It is generally harmless and widely used.
+  if (isReservedId(Text, Lang))
+    return MD_ReservedMacro;
   if (II->isKeyword(Lang))
-    return true;
-  if (Lang.CPlusPlus && (Text.equals("override") || Text.equals("final")))
-    return true;
-  return false;
+    return MD_KeywordDef;
+  if (Lang.CPlusPlus11 && (Text.equals("override") || Text.equals("final")))
+    return MD_KeywordDef;
+  return MD_NoWarn;
 }
 
-bool Preprocessor::CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef) {
+static MacroDiag shouldWarnOnMacroUndef(Preprocessor &PP, IdentifierInfo *II) {
+  const LangOptions &Lang = PP.getLangOpts();
+  StringRef Text = II->getName();
+  // Do not warn on keyword undef.  It is generally harmless and widely used.
+  if (isReservedId(Text, Lang))
+    return MD_ReservedMacro;
+  return MD_NoWarn;
+}
+
+bool Preprocessor::CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
+                                  bool *ShadowFlag) {
   // Missing macro name?
   if (MacroNameTok.is(tok::eod))
     return Diag(MacroNameTok, diag::err_pp_missing_macro_name);
@@ -151,12 +189,28 @@ bool Preprocessor::CheckMacroName(Token
     Diag(MacroNameTok, diag::ext_pp_undef_builtin_macro);
   }
 
-  // Warn if defining/undefining reserved identifier including keywords.
+  // If defining/undefining reserved identifier or a keyword, we need to issue
+  // a warning.
   SourceLocation MacroNameLoc = MacroNameTok.getLocation();
+  if (ShadowFlag)
+    *ShadowFlag = false;
   if (!SourceMgr.isInSystemHeader(MacroNameLoc) &&
       (strcmp(SourceMgr.getBufferName(MacroNameLoc), "<built-in>") != 0)) {
-    if (isDefineUndef == MU_Define && shouldWarnOnMacroDef(*this, II))
-      Diag(MacroNameTok, diag::warn_pp_macro_hides_keyword);
+    MacroDiag D = MD_NoWarn;
+    if (isDefineUndef == MU_Define) {
+      D = shouldWarnOnMacroDef(*this, II);
+    }
+    else if (isDefineUndef == MU_Undef)
+      D = shouldWarnOnMacroUndef(*this, II);
+    if (D == MD_KeywordDef) {
+      // We do not want to warn on some patterns widely used in configuration
+      // scripts.  This requires analyzing next tokens, so do not issue warnings
+      // now, only inform caller.
+      if (ShadowFlag)
+        *ShadowFlag = true;
+    }
+    if (D == MD_ReservedMacro)
+      Diag(MacroNameTok, diag::warn_pp_macro_is_reserved_id);
   }
 
   // Okay, we got a good identifier.
@@ -170,8 +224,10 @@ bool Preprocessor::CheckMacroName(Token
 /// the macro name is invalid.
 ///
 /// \param MacroNameTok Token that is expected to be a macro name.
-/// \papam isDefineUndef Context in which macro is used.
-void Preprocessor::ReadMacroName(Token &MacroNameTok, MacroUse isDefineUndef) {
+/// \param isDefineUndef Context in which macro is used.
+/// \param ShadowFlag Points to a flag that is set if macro shadows a keyword.
+void Preprocessor::ReadMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
+                                 bool *ShadowFlag) {
   // Read the token, don't allow macro expansion on it.
   LexUnexpandedToken(MacroNameTok);
 
@@ -182,7 +238,7 @@ void Preprocessor::ReadMacroName(Token &
     LexUnexpandedToken(MacroNameTok);
   }
 
-  if (!CheckMacroName(MacroNameTok, isDefineUndef))
+  if (!CheckMacroName(MacroNameTok, isDefineUndef, ShadowFlag))
     return;
 
   // Invalid macro name, read and discard the rest of the line and set the
@@ -1918,6 +1974,52 @@ bool Preprocessor::ReadMacroDefinitionAr
   }
 }
 
+static bool isConfigurationPattern(Token &MacroName, MacroInfo *MI,
+                                   const LangOptions &LOptions) {
+  if (MI->getNumTokens() == 1) {
+    const Token &Value = MI->getReplacementToken(0);
+
+    // Macro that is identity, like '#define inline inline' is a valid pattern.
+    if (MacroName.getKind() == Value.getKind())
+      return true;
+
+    // Macro that maps a keyword to the same keyword decorated with leading/
+    // trailing underscores is a valid pattern:
+    //    #define inline __inline
+    //    #define inline __inline__
+    //    #define inline _inline (in MS compatibility mode)
+    StringRef MacroText = MacroName.getIdentifierInfo()->getName();
+    if (IdentifierInfo *II = Value.getIdentifierInfo()) {
+      if (!II->isKeyword(LOptions))
+        return false;
+      StringRef ValueText = II->getName();
+      StringRef TrimmedValue = ValueText;
+      if (!ValueText.startswith("__")) {
+        if (ValueText.startswith("_"))
+          TrimmedValue = TrimmedValue.drop_front(1);
+        else
+          return false;
+      } else {
+        TrimmedValue = TrimmedValue.drop_front(2);
+        if (TrimmedValue.endswith("__"))
+          TrimmedValue = TrimmedValue.drop_back(2);
+      }
+      return TrimmedValue.equals(MacroText);
+    } else {
+      return false;
+    }
+  }
+
+  // #define inline
+  if ((MacroName.is(tok::kw_extern) || MacroName.is(tok::kw_inline) ||
+       MacroName.is(tok::kw_static) || MacroName.is(tok::kw_const)) &&
+      MI->getNumTokens() == 0) {
+    return true;
+  }
+
+  return false;
+}
+
 /// HandleDefineDirective - Implements \#define.  This consumes the entire macro
 /// line then lets the caller lex the next real token.
 void Preprocessor::HandleDefineDirective(Token &DefineTok,
@@ -1925,7 +2027,8 @@ void Preprocessor::HandleDefineDirective
   ++NumDefined;
 
   Token MacroNameTok;
-  ReadMacroName(MacroNameTok, MU_Define);
+  bool MacroShadowsKeyword;
+  ReadMacroName(MacroNameTok, MU_Define, &MacroShadowsKeyword);
 
   // Error reading macro name?  If so, diagnostic already issued.
   if (MacroNameTok.is(tok::eod))
@@ -2102,6 +2205,10 @@ void Preprocessor::HandleDefineDirective
     }
   }
 
+  if (MacroShadowsKeyword &&
+      !isConfigurationPattern(MacroNameTok, MI, getLangOpts())) {
+    Diag(MacroNameTok, diag::warn_pp_macro_hides_keyword);
+  }
 
   // Disable __VA_ARGS__ again.
   Ident__VA_ARGS__->setIsPoisoned(true);

Added: cfe/trunk/test/Preprocessor/macro-reserved-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/macro-reserved-cxx11.cpp?rev=224512&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/macro-reserved-cxx11.cpp (added)
+++ cfe/trunk/test/Preprocessor/macro-reserved-cxx11.cpp Thu Dec 18 05:14:21 2014
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -pedantic -verify %s
+
+#define for 0    // expected-warning {{keyword is hidden by macro definition}}
+#define final 1  // expected-warning {{keyword is hidden by macro definition}}
+#define override // expected-warning {{keyword is hidden by macro definition}}
+
+int x;

Added: cfe/trunk/test/Preprocessor/macro-reserved-ms.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/macro-reserved-ms.c?rev=224512&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/macro-reserved-ms.c (added)
+++ cfe/trunk/test/Preprocessor/macro-reserved-ms.c Thu Dec 18 05:14:21 2014
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -fms-extensions -verify %s
+// expected-no-diagnostics
+
+#define inline _inline
+#undef  inline
+
+int x;

Modified: cfe/trunk/test/Preprocessor/macro-reserved.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/macro-reserved.c?rev=224512&r1=224511&r2=224512&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/macro-reserved.c (original)
+++ cfe/trunk/test/Preprocessor/macro-reserved.c Thu Dec 18 05:14:21 2014
@@ -1,25 +1,64 @@
-// RUN: %clang_cc1 -fsyntax-only %s -verify
-
-#pragma clang diagnostic warning "-Wkeyword-macro"
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
 
 #define for 0    // expected-warning {{keyword is hidden by macro definition}}
 #define final 1
 #define __HAVE_X 0
+#define __cplusplus
 #define _HAVE_X 0
 #define X__Y
 
+#undef for
+#undef final
+#undef __HAVE_X
 #undef __cplusplus
 #undef _HAVE_X
 #undef X__Y
 
+// whitelisted definitions
+#define while while
+#define const
+#define static
+#define extern
+#define inline
+
+#undef while
+#undef const
+#undef static
+#undef extern
+#undef inline
+
+#define inline __inline
+#undef  inline
+#define inline __inline__
+#undef  inline
+
+#define inline inline__  // expected-warning {{keyword is hidden by macro definition}}
+#undef  inline
+#define extern __inline  // expected-warning {{keyword is hidden by macro definition}}
+#undef  extern
+#define extern __extern	 // expected-warning {{keyword is hidden by macro definition}}
+#undef  extern
+#define extern __extern__ // expected-warning {{keyword is hidden by macro definition}}
+#undef  extern
+
+#define inline _inline   // expected-warning {{keyword is hidden by macro definition}}
+#undef  inline
+#define volatile   // expected-warning {{keyword is hidden by macro definition}}
+#undef  volatile
+
+#pragma clang diagnostic warning "-Wreserved-id-macro"
+
 #define switch if  // expected-warning {{keyword is hidden by macro definition}}
 #define final 1
-#define __HAVE_X 0
-#define _HAVE_X 0
+#define __clusplus // expected-warning {{macro name is a reserved identifier}}
+#define __HAVE_X 0 // expected-warning {{macro name is a reserved identifier}}
+#define _HAVE_X 0  // expected-warning {{macro name is a reserved identifier}}
 #define X__Y
 
-#undef __cplusplus
-#undef _HAVE_X
+#undef switch
+#undef final
+#undef __cplusplus // expected-warning {{macro name is a reserved identifier}}
+#undef _HAVE_X     // expected-warning {{macro name is a reserved identifier}}
 #undef X__Y
 
 int x;

Modified: cfe/trunk/test/Preprocessor/macro-reserved.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/macro-reserved.cpp?rev=224512&r1=224511&r2=224512&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/macro-reserved.cpp (original)
+++ cfe/trunk/test/Preprocessor/macro-reserved.cpp Thu Dec 18 05:14:21 2014
@@ -1,25 +1,63 @@
-// RUN: %clang_cc1 -fsyntax-only %s -verify
-
-#pragma clang diagnostic warning "-Wkeyword-macro"
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
 
 #define for 0    // expected-warning {{keyword is hidden by macro definition}}
-#define final 1  // expected-warning {{keyword is hidden by macro definition}}
+#define final 1
 #define __HAVE_X 0
 #define _HAVE_X 0
 #define X__Y
 
-#undef __cplusplus
+#undef for
+#undef final
+#undef __HAVE_X
 #undef _HAVE_X
 #undef X__Y
 
-#define switch if  // expected-warning {{keyword is hidden by macro definition}}
-#define final 1    // expected-warning {{keyword is hidden by macro definition}}
-#define __HAVE_X 0
-#define _HAVE_X 0
-#define X__Y
-
 #undef __cplusplus
-#undef _HAVE_X
-#undef X__Y
+#define __cplusplus
+
+// whitelisted definitions
+#define while while
+#define const
+#define static
+#define extern
+#define inline
+
+#undef while
+#undef const
+#undef static
+#undef extern
+#undef inline
+
+#define inline __inline
+#undef  inline
+#define inline __inline__
+#undef  inline
+
+#define inline inline__  // expected-warning {{keyword is hidden by macro definition}}
+#undef  inline
+#define extern __inline  // expected-warning {{keyword is hidden by macro definition}}
+#undef  extern
+#define extern __extern	 // expected-warning {{keyword is hidden by macro definition}}
+#undef  extern
+#define extern __extern__ // expected-warning {{keyword is hidden by macro definition}}
+#undef  extern
+
+#define inline _inline   // expected-warning {{keyword is hidden by macro definition}}
+#undef  inline
+#define volatile   // expected-warning {{keyword is hidden by macro definition}}
+#undef  volatile
+
+
+#pragma clang diagnostic warning "-Wreserved-id-macro"
+
+#define switch if  // expected-warning {{keyword is hidden by macro definition}}
+#define final 1
+#define __HAVE_X 0 // expected-warning {{macro name is a reserved identifier}}
+#define _HAVE_X 0  // expected-warning {{macro name is a reserved identifier}}
+#define X__Y       // expected-warning {{macro name is a reserved identifier}}
+
+#undef __cplusplus // expected-warning {{macro name is a reserved identifier}}
+#undef _HAVE_X     // expected-warning {{macro name is a reserved identifier}}
+#undef X__Y        // expected-warning {{macro name is a reserved identifier}}
 
 int x;





More information about the cfe-commits mailing list