r203987 - Implement the MS extension __identifier properly: take a token and strip it of

Richard Smith richard-llvm at metafoo.co.uk
Fri Mar 14 17:06:09 PDT 2014


Author: rsmith
Date: Fri Mar 14 19:06:08 2014
New Revision: 203987

URL: http://llvm.org/viewvc/llvm-project?rev=203987&view=rev
Log:
Implement the MS extension __identifier properly: take a token and strip it of
its keywordliness.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/lib/Frontend/InitPreprocessor.cpp
    cfe/trunk/lib/Lex/PPMacroExpansion.cpp
    cfe/trunk/test/Parser/MicrosoftExtensions.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=203987&r1=203986&r2=203987&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Fri Mar 14 19:06:08 2014
@@ -403,6 +403,9 @@ def warn_has_warning_invalid_option :
    ExtWarn<"__has_warning expected option name (e.g. \"-Wundef\")">,
    InGroup<MalformedWarningCheck>;
 
+def err_pp_identifier_arg_not_identifier : Error<
+  "cannot convert %0 token to an identifier">;
+
 def warn_pragma_include_alias_mismatch_angle :
    ExtWarn<"angle-bracketed include <%0> cannot be aliased to double-quoted "
    "include \"%1\"">, InGroup<UnknownPragmas>;

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=203987&r1=203986&r2=203987&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Fri Mar 14 19:06:08 2014
@@ -116,6 +116,7 @@ class Preprocessor : public RefCountedBa
   IdentifierInfo *Ident__TIMESTAMP__;              // __TIMESTAMP__
   IdentifierInfo *Ident__COUNTER__;                // __COUNTER__
   IdentifierInfo *Ident_Pragma, *Ident__pragma;    // _Pragma, __pragma
+  IdentifierInfo *Ident__identifier;               // __identifier
   IdentifierInfo *Ident__VA_ARGS__;                // __VA_ARGS__
   IdentifierInfo *Ident__has_feature;              // __has_feature
   IdentifierInfo *Ident__has_extension;            // __has_extension

Modified: cfe/trunk/lib/Frontend/InitPreprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/InitPreprocessor.cpp?rev=203987&r1=203986&r2=203987&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/InitPreprocessor.cpp (original)
+++ cfe/trunk/lib/Frontend/InitPreprocessor.cpp Fri Mar 14 19:06:08 2014
@@ -517,10 +517,6 @@ static void InitializePredefinedMacros(c
       Builder.defineMacro("_WCHAR_T_DEFINED");
       Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED");
     }
-    if (LangOpts.CPlusPlus) {
-      // FIXME: Support Microsoft's __identifier extension in the lexer.
-      Builder.append("#define __identifier(x) x");
-    }
   }
 
   if (LangOpts.Optimize)

Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=203987&r1=203986&r2=203987&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Fri Mar 14 19:06:08 2014
@@ -97,6 +97,15 @@ void Preprocessor::RegisterBuiltinMacros
   Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro(*this, "__INCLUDE_LEVEL__");
   Ident__TIMESTAMP__     = RegisterBuiltinMacro(*this, "__TIMESTAMP__");
 
+  // Microsoft Extensions.
+  if (LangOpts.MicrosoftExt) {
+    Ident__identifier = RegisterBuiltinMacro(*this, "__identifier");
+    Ident__pragma = RegisterBuiltinMacro(*this, "__pragma");
+  } else {
+    Ident__identifier = 0;
+    Ident__pragma = 0;
+  }
+
   // Clang Extensions.
   Ident__has_feature      = RegisterBuiltinMacro(*this, "__has_feature");
   Ident__has_extension    = RegisterBuiltinMacro(*this, "__has_extension");
@@ -119,12 +128,6 @@ void Preprocessor::RegisterBuiltinMacros
     Ident__building_module = 0;
     Ident__MODULE__ = 0;
   }
-  
-  // Microsoft Extensions.
-  if (LangOpts.MicrosoftExt) 
-    Ident__pragma = RegisterBuiltinMacro(*this, "__pragma");
-  else
-    Ident__pragma = 0;
 }
 
 /// isTrivialSingleTokenExpansion - Return true if MI, which has a single token
@@ -1481,6 +1484,44 @@ void Preprocessor::ExpandBuiltinMacro(To
     IdentifierInfo *ModuleII = getIdentifierInfo(getLangOpts().CurrentModule);
     Tok.setIdentifierInfo(ModuleII);
     Tok.setKind(ModuleII->getTokenID());
+  } else if (II == Ident__identifier) {
+    SourceLocation Loc = Tok.getLocation();
+
+    // We're expecting '__identifier' '(' identifier ')'. Try to recover
+    // if the parens are missing.
+    LexNonComment(Tok);
+    if (Tok.isNot(tok::l_paren)) {
+      // No '(', use end of last token.
+      Diag(getLocForEndOfToken(Loc), diag::err_pp_expected_after)
+        << II << tok::l_paren;
+      // If the next token isn't valid as our argument, we can't recover.
+      if (!Tok.isAnnotation() && Tok.getIdentifierInfo())
+        Tok.setKind(tok::identifier);
+      return;
+    }
+
+    SourceLocation LParenLoc = Tok.getLocation();
+    LexNonComment(Tok);
+
+    if (!Tok.isAnnotation() && Tok.getIdentifierInfo())
+      Tok.setKind(tok::identifier);
+    else {
+      Diag(Tok.getLocation(), diag::err_pp_identifier_arg_not_identifier)
+        << Tok.getKind();
+      // Don't walk past anything that's not a real token.
+      if (Tok.is(tok::eof) || Tok.is(tok::eod) || Tok.isAnnotation())
+        return;
+    }
+
+    // Discard the ')', preserving 'Tok' as our result.
+    Token RParen;
+    LexNonComment(RParen);
+    if (RParen.isNot(tok::r_paren)) {
+      Diag(getLocForEndOfToken(Tok.getLocation()), diag::err_pp_expected_after)
+        << Tok.getKind() << tok::r_paren;
+      Diag(LParenLoc, diag::note_matching) << tok::l_paren;
+    }
+    return;
   } else {
     llvm_unreachable("Unknown identifier!");
   }

Modified: cfe/trunk/test/Parser/MicrosoftExtensions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/MicrosoftExtensions.cpp?rev=203987&r1=203986&r2=203987&view=diff
==============================================================================
--- cfe/trunk/test/Parser/MicrosoftExtensions.cpp (original)
+++ cfe/trunk/test/Parser/MicrosoftExtensions.cpp Fri Mar 14 19:06:08 2014
@@ -325,6 +325,29 @@ class IF_EXISTS_CLASS_TEST {
 
 
 int __identifier(generic) = 3;
+int __identifier(int) = 4;
+struct __identifier(class) { __identifier(class) *__identifier(for); };
+__identifier(class) __identifier(struct) = { &__identifier(struct) };
+
+int __identifier for; // expected-error {{missing '(' after '__identifier'}}
+int __identifier(else} = __identifier(for); // expected-error {{missing ')' after identifier}} expected-note {{to match this '('}}
+#define identifier_weird(x) __identifier(x
+int k = identifier_weird(if)); // expected-error {{use of undeclared identifier 'if'}}
+
+// This is a bit weird, but the alternative tokens aren't keywords, and this
+// behavior matches MSVC. FIXME: Consider supporting this anyway.
+extern int __identifier(and) r; // expected-error {{cannot convert '&&' token to an identifier}}
+
+void f() {
+  __identifier(() // expected-error {{cannot convert '(' token to an identifier}}
+  __identifier(void) // expected-error {{use of undeclared identifier 'void'}}
+  __identifier()) // expected-error {{cannot convert ')' token to an identifier}}
+  // FIXME: We should pick a friendlier display name for this token kind.
+  __identifier(1) // expected-error {{cannot convert <numeric_constant> token to an identifier}}
+  __identifier(+) // expected-error {{cannot convert '+' token to an identifier}}
+  __identifier("foo") // expected-error {{cannot convert <string_literal> token to an identifier}}
+  __identifier(;) // expected-error {{cannot convert ';' token to an identifier}}
+}
 
 class inline_definition_pure_spec {
    virtual int f() = 0 { return 0; }// expected-warning {{function definition with pure-specifier is a Microsoft extension}}





More information about the cfe-commits mailing list