r209276 - Preprocessor: support defined() with operator names for MS compatibility

Alp Toker alp at nuanti.com
Tue May 20 23:13:51 PDT 2014


Author: alp
Date: Wed May 21 01:13:51 2014
New Revision: 209276

URL: http://llvm.org/viewvc/llvm-project?rev=209276&view=rev
Log:
Preprocessor: support defined() with operator names for MS compatibility

Also flesh out missing tests, improve diagnostic QOI and fix a couple of corner
cases found in the process.

Fixes PR10606.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/lib/Lex/PPDirectives.cpp
    cfe/trunk/lib/Lex/PPExpressions.cpp
    cfe/trunk/test/Parser/cxx11-user-defined-literals.cpp
    cfe/trunk/test/Preprocessor/cxx_oper_keyword.cpp
    cfe/trunk/test/Preprocessor/cxx_oper_keyword_ms_compat.cpp
    cfe/trunk/test/Preprocessor/ifdef-recover.c
    cfe/trunk/test/Preprocessor/ucn-pp-identifier.c

Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=209276&r1=209275&r2=209276&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Wed May 21 01:13:51 2014
@@ -353,7 +353,7 @@ def err_pp_error_opening_file : Error<
 def err_pp_empty_filename : Error<"empty filename">;
 def err_pp_include_too_deep : Error<"#include nested too deeply">;
 def err_pp_expects_filename : Error<"expected \"FILENAME\" or <FILENAME>">;
-def err_pp_macro_not_identifier : Error<"macro names must be identifiers">;
+def err_pp_macro_not_identifier : Error<"macro name must be an identifier">;
 def err_pp_missing_macro_name : Error<"macro name missing">;
 def err_pp_missing_rparen_in_macro_def : Error<
   "missing ')' in macro parameter list">;
@@ -379,8 +379,6 @@ def err_pp_expected_value_in_expr : Erro
 def err_pp_expected_rparen : Error<"expected ')' in preprocessor expression">;
 def err_pp_expected_eol : Error<
   "expected end of line in preprocessor expression">;
-def err_pp_defined_requires_identifier : Error<
-  "operator 'defined' requires an identifier">;
 def err_pp_expected_after : Error<"missing %1 after %0">;
 def err_pp_colon_without_question : Error<"':' without preceding '?'">;
 def err_pp_division_by_zero : Error<

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=209276&r1=209275&r2=209276&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Wed May 21 01:13:51 2014
@@ -1343,6 +1343,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, char isDefineUndef);
+
 private:
 
   void PushIncludeMacroStack() {

Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=209276&r1=209275&r2=209276&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
+++ cfe/trunk/lib/Lex/PPDirectives.cpp Wed May 21 01:13:51 2014
@@ -129,70 +129,78 @@ void Preprocessor::DiscardUntilEndOfDire
   } while (Tmp.isNot(tok::eod));
 }
 
-/// \brief Lex and validate a macro name, which occurs after a
-/// \#define or \#undef.
-///
-/// This sets the token kind to eod and discards the rest
-/// of the macro line if the macro name is invalid.  \p isDefineUndef is 1 if
-/// this is due to a a \#define, 2 if \#undef directive, 0 if it is something
-/// else (e.g. \#ifdef).
-void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
-  // Read the token, don't allow macro expansion on it.
-  LexUnexpandedToken(MacroNameTok);
-
-  if (MacroNameTok.is(tok::code_completion)) {
-    if (CodeComplete)
-      CodeComplete->CodeCompleteMacroName(isDefineUndef == 1);
-    setCodeCompletionReached();
-    LexUnexpandedToken(MacroNameTok);
-  }
-  
+bool Preprocessor::CheckMacroName(Token &MacroNameTok, char isDefineUndef) {
   // Missing macro name?
-  if (MacroNameTok.is(tok::eod)) {
-    Diag(MacroNameTok, diag::err_pp_missing_macro_name);
-    return;
-  }
+  if (MacroNameTok.is(tok::eod))
+    return Diag(MacroNameTok, diag::err_pp_missing_macro_name);
 
   IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
   if (!II) {
     bool Invalid = false;
     std::string Spelling = getSpelling(MacroNameTok, &Invalid);
     if (Invalid)
-      return;
+      return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
 
     const IdentifierInfo &Info = Identifiers.get(Spelling);
 
     // Allow #defining |and| and friends in microsoft mode.
     if (Info.isCPlusPlusOperatorKeyword() && getLangOpts().MSVCCompat) {
       MacroNameTok.setIdentifierInfo(getIdentifierInfo(Spelling));
-      return;
+      return false;
     }
 
     if (Info.isCPlusPlusOperatorKeyword())
       // C++ 2.5p2: Alternative tokens behave the same as its primary token
       // except for their spellings.
-      Diag(MacroNameTok, diag::err_pp_operator_used_as_macro_name) << Spelling;
-    else
-      Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
-    // Fall through on error.
-  } else if (isDefineUndef && II->getPPKeywordID() == tok::pp_defined) {
+      return Diag(MacroNameTok, diag::err_pp_operator_used_as_macro_name)
+             << Spelling;
+
+    return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
+  }
+
+  if (isDefineUndef && II->getPPKeywordID() == tok::pp_defined) {
     // Error if defining "defined": C99 6.10.8/4, C++ [cpp.predefined]p4.
-    Diag(MacroNameTok, diag::err_defined_macro_name);
-  } else if (isDefineUndef == 2 && II->hasMacroDefinition() &&
-             getMacroInfo(II)->isBuiltinMacro()) {
+    return Diag(MacroNameTok, diag::err_defined_macro_name);
+  }
+
+  if (isDefineUndef == 2 && II->hasMacroDefinition() &&
+      getMacroInfo(II)->isBuiltinMacro()) {
     // Warn if undefining "__LINE__" and other builtins, per C99 6.10.8/4
     // and C++ [cpp.predefined]p4], but allow it as an extension.
     Diag(MacroNameTok, diag::ext_pp_undef_builtin_macro);
-    return;
-  } else {
-    // Okay, we got a good identifier node.  Return it.
-    return;
   }
 
-  // Invalid macro name, read and discard the rest of the line.  Then set the
-  // token kind to tok::eod.
-  MacroNameTok.setKind(tok::eod);
-  return DiscardUntilEndOfDirective();
+  // Okay, we got a good identifier.
+  return false;
+}
+
+/// \brief Lex and validate a macro name, which occurs after a
+/// \#define or \#undef.
+///
+/// This sets the token kind to eod and discards the rest
+/// of the macro line if the macro name is invalid.  \p isDefineUndef is 1 if
+/// this is due to a a \#define, 2 if \#undef directive, 0 if it is something
+/// else (e.g. \#ifdef).
+void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
+  // Read the token, don't allow macro expansion on it.
+  LexUnexpandedToken(MacroNameTok);
+
+  if (MacroNameTok.is(tok::code_completion)) {
+    if (CodeComplete)
+      CodeComplete->CodeCompleteMacroName(isDefineUndef == 1);
+    setCodeCompletionReached();
+    LexUnexpandedToken(MacroNameTok);
+  }
+
+  if (!CheckMacroName(MacroNameTok, isDefineUndef))
+    return;
+
+  // Invalid macro name, read and discard the rest of the line and set the
+  // token kind to tok::eod if necessary.
+  if (MacroNameTok.isNot(tok::eod)) {
+    MacroNameTok.setKind(tok::eod);
+    DiscardUntilEndOfDirective();
+  }
 }
 
 /// \brief Ensure that the next token is a tok::eod token.

Modified: cfe/trunk/lib/Lex/PPExpressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPExpressions.cpp?rev=209276&r1=209275&r2=209276&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPExpressions.cpp (original)
+++ cfe/trunk/lib/Lex/PPExpressions.cpp Wed May 21 01:13:51 2014
@@ -81,7 +81,6 @@ struct DefinedTracker {
 /// EvaluateDefined - Process a 'defined(sym)' expression.
 static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
                             bool ValueLive, Preprocessor &PP) {
-  IdentifierInfo *II;
   SourceLocation beginLoc(PeekTok.getLocation());
   Result.setBegin(beginLoc);
 
@@ -102,14 +101,13 @@ static bool EvaluateDefined(PPValue &Res
     PP.setCodeCompletionReached();
     PP.LexUnexpandedNonComment(PeekTok);
   }
-  
+
   // If we don't have a pp-identifier now, this is an error.
-  if ((II = PeekTok.getIdentifierInfo()) == nullptr) {
-    PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier);
+  if (PP.CheckMacroName(PeekTok, 0))
     return true;
-  }
 
   // Otherwise, we got an identifier, is it defined to something?
+  IdentifierInfo *II = PeekTok.getIdentifierInfo();
   Result.Val = II->hasMacroDefinition();
   Result.Val.setIsUnsigned(false);  // Result is signed intmax_t.
 

Modified: cfe/trunk/test/Parser/cxx11-user-defined-literals.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx11-user-defined-literals.cpp?rev=209276&r1=209275&r2=209276&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx11-user-defined-literals.cpp (original)
+++ cfe/trunk/test/Parser/cxx11-user-defined-literals.cpp Wed May 21 01:13:51 2014
@@ -139,7 +139,7 @@ void operator""_\u212e""_\u212f(unsigned
 void operator""_℮""_℮(unsigned long long) {} // expected-note {{previous}}
 void operator""_\u212e""_\u212e(unsigned long long) {} // expected-error {{redefinition}}
 
-#define ¢ *0.01 // expected-error {{macro names must be identifiers}}
+#define ¢ *0.01 // expected-error {{macro name must be an identifier}}
 constexpr int operator""_¢(long double d) { return d * 100; } // expected-error {{non-ASCII}}
 constexpr int operator""_¢(unsigned long long n) { return n; } // expected-error {{non-ASCII}}
 static_assert(0.02_¢ == 2_¢, ""); // expected-error 2{{non-ASCII}}

Modified: cfe/trunk/test/Preprocessor/cxx_oper_keyword.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/cxx_oper_keyword.cpp?rev=209276&r1=209275&r2=209276&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/cxx_oper_keyword.cpp (original)
+++ cfe/trunk/test/Preprocessor/cxx_oper_keyword.cpp Wed May 21 01:13:51 2014
@@ -1,7 +1,22 @@
-// RUN: not %clang_cc1 %s -E
-// RUN: %clang_cc1 %s -E -fno-operator-names
+// RUN: %clang_cc1 %s -E -verify -DOPERATOR_NAMES
+// RUN: %clang_cc1 %s -E -verify -fno-operator-names
 
-// Not valid in C++ unless -fno-operator-names is passed.
-#define and foo
+#ifndef OPERATOR_NAMES
+//expected-error at +3 {{token is not a valid binary operator in a preprocessor subexpression}}
+#endif
+// Valid because 'and' is a spelling of '&&'
+#if defined foo and bar
+#endif
+
+// Not valid in C++ unless -fno-operator-names is passed:
 
+#ifdef OPERATOR_NAMES
+//expected-error at +2 {{C++ operator 'and' cannot be used as a macro name}}
+#endif
+#define and foo
 
+#ifdef OPERATOR_NAMES
+//expected-error at +2 {{C++ operator 'and' cannot be used as a macro name}}
+#endif
+#if defined and
+#endif

Modified: cfe/trunk/test/Preprocessor/cxx_oper_keyword_ms_compat.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/cxx_oper_keyword_ms_compat.cpp?rev=209276&r1=209275&r2=209276&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/cxx_oper_keyword_ms_compat.cpp (original)
+++ cfe/trunk/test/Preprocessor/cxx_oper_keyword_ms_compat.cpp Wed May 21 01:13:51 2014
@@ -7,6 +7,13 @@ bool f() {
 #endif
 }
 
+#ifdef and
+#endif
+
+// The second 'and' is a valid C++ operator name for '&&'.
+#if defined and and defined(and)
+#endif
+
 // All c++ keywords should be #define-able in ms mode.
 // (operators like "and" aren't normally, the rest always is.)
 #define and

Modified: cfe/trunk/test/Preprocessor/ifdef-recover.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/ifdef-recover.c?rev=209276&r1=209275&r2=209276&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/ifdef-recover.c (original)
+++ cfe/trunk/test/Preprocessor/ifdef-recover.c Wed May 21 01:13:51 2014
@@ -1,15 +1,22 @@
-/* RUN: not %clang_cc1 -E %s 2>&1 >/dev/null | grep error: | count 3
+/* RUN: %clang_cc1 -E -verify %s
  */
 
+/* expected-error at +1 {{macro name missing}} */
 #ifdef
+#endif
+
+/* expected-error at +1 {{macro name must be an identifier}} */
+#ifdef !
+#endif
 
+/* expected-error at +1 {{macro name missing}} */
+#if defined
 #endif
 
-/* End of function-like macro invocation in #ifdef */
 /* PR1936 */
+/* expected-error at +2 {{unterminated function-like macro invocation}} expected-error at +2 {{expected value in expression}} expected-note at +1 {{macro 'f' defined here}} */
 #define f(x) x
 #if f(2
 #endif
 
 int x;
-

Modified: cfe/trunk/test/Preprocessor/ucn-pp-identifier.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/ucn-pp-identifier.c?rev=209276&r1=209275&r2=209276&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/ucn-pp-identifier.c (original)
+++ cfe/trunk/test/Preprocessor/ucn-pp-identifier.c Wed May 21 01:13:51 2014
@@ -24,9 +24,9 @@
 #endif
 
 // Make sure we reject disallowed UCNs
-#define \ufffe // expected-error {{macro names must be identifiers}}
-#define \U10000000  // expected-error {{macro names must be identifiers}}
-#define \u0061  // expected-error {{character 'a' cannot be specified by a universal character name}} expected-error {{macro names must be identifiers}}
+#define \ufffe // expected-error {{macro name must be an identifier}}
+#define \U10000000  // expected-error {{macro name must be an identifier}}
+#define \u0061  // expected-error {{character 'a' cannot be specified by a universal character name}} expected-error {{macro name must be an identifier}}
 
 // FIXME: Not clear what our behavior should be here; \u0024 is "$".
 #define a\u0024  // expected-warning {{whitespace}}





More information about the cfe-commits mailing list