[cfe-commits] Requesting review of MS compatibility patch (fixes bug 11789)

Aaron Wishnick aaron.s.wishnick at gmail.com
Mon Jun 11 18:07:31 PDT 2012


Sorry to spam, but I sent this out a few days ago and there was no response, and I'm wondering if it got filtered out due to the attachment.

This is my first contribution to this project, so please let me know if there's anything I can do to get this patch in better shape before committing. The aim of this patch is to fix an obstacle for clang working as a drop-in replacement for Microsoft's C++ compiler. A summary of this behavior is below, but it can also be seen in bug 11789: http://llvm.org/bugs/show_bug.cgi?id=11789

This patch adds a feature that is enabled only when "-fms-extensions" is set, to fix some errors trying to parse Microsoft's standard library implementation. In Microsoft's <locale> header, there is some debugging code that attempts to take the __FUNCTION__ predefined expression, and turn it into a wide char literal. It does something like this:

#define _STR2WSTR(s) L##s
#define STR2WSTR(s) _STR2WSTR(s)
#define __FUNCTIONW__ STR2WSTR(__FUNCTION__)

This wouldn't work in clang, because __FUNCTION__ isn't a macro, it's a predefined expression, so the token-paste operator just turns it into L__FUNCTION__, as the standard says it should. Microsoft's compiler has an undocumented extension that allows this to work, making it appear as if __FUNCTION__ were a macro, though it's not: 
1. The preprocessor special-cases pasting the token 'L' with __FUNCTION__, if __FUNCTION__ came from a macro expansion, pasting it to __LPREFIX( __FUNCTION__). This can be seen by using VC's preprocessor. When I say, "if __FUNCTION__ came from a macro expansion", I mean that _STR2WSTR(__FUNCTION__) does not have any special rules applied to it, in other words, the preprocessor pretends that __FUNCTION__ is a macro being expanded to a string, even though it's not.
2. The frontend is extended to parse __LPREFIX in a special way: The argument to __LPREFIX must be a compile-time constant string literal, or a predefined expression, and it must be formatted in UTF8. The result of the __LPREFIX expression is the same string, but formatted as a wide char literal.

This patch implements both of these phases, and allows Microsoft's <locale> header to be successfully parsed. Please let me know if there's anything I can do to better package it. I developed it against the 3.1 release tag, but it applies cleanly to top of tree clang as well.

Best regards,
Aaron

Index: test/Sema/ms_wide_predefined_expr.cpp
===================================================================
--- test/Sema/ms_wide_predefined_expr.cpp	(revision 0)
+++ test/Sema/ms_wide_predefined_expr.cpp	(revision 0)
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-extensions
+
+// Wide character predefined identifiers
+#define _STR2WSTR(str) L##str
+#define STR2WSTR(str) _STR2WSTR(str)
+void abcdefghi12(void) {
+ const wchar_t (*ss)[12] = &STR2WSTR(__FUNCTION__);
+ static int arr[sizeof(STR2WSTR(__FUNCTION__))==12*sizeof(wchar_t) ? 1 : -1];
+}
+
Index: test/Sema/ms_lprefix.cpp
===================================================================
--- test/Sema/ms_lprefix.cpp	(revision 0)
+++ test/Sema/ms_lprefix.cpp	(revision 0)
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-extensions
+
+void a(void) {
+ const wchar_t (*ss)[6] = &__LPREFIX("hello");
+ static int arr[sizeof(__LPREFIX("hello"))==6*sizeof(wchar_t) ? 1 : -1];
+}
+
Index: test/Preprocessor/macro_paste_msextensions.cpp
===================================================================
--- test/Preprocessor/macro_paste_msextensions.cpp	(revision 0)
+++ test/Preprocessor/macro_paste_msextensions.cpp	(revision 0)
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -P -E -fms-extensions %s | FileCheck -strict-whitespace %s
+
+#define _STR2WSTR(str) L##str
+#define STR2WSTR(str) _STR2WSTR(str)
+
+#define _ENDTEST(str1, str2) L##str1##str2
+#define ENDTEST(str1, str2) _ENDTEST(str1, str2)
+
+void fun() {
+// Special token pasting for __FUNCTION__ to make it seem like it's a macro
+// rather than a predefined expr
+STR2WSTR(__FUNCTION__)
+// CHECK: __LPREFIX( __FUNCTION__)
+
+// However, this rule is only applied if __FUNCTION__ would have been expanded
+// if it were a true macro.
+_STR2WSTR(__FUNCTION__)
+// CHECK: L__FUNCTION__
+
+// Make sure it's not applied for regular token pasting
+#define NOTFUNCTION NOREALLY
+STR2WSTR(NOTFUNCTION)
+// CHECK: LNOREALLY
+
+// Make sure token pasting with three arguments works with the special
+// __FUNCTION__ token pasting rule.
+ENDTEST(__FUNCTION__, JUNCTION)
+// CHECK: __LPREFIX( __FUNCTION__) JUNCTION
+}
Index: test/CodeGenCXX/ms_wide_predefined_expr.cpp
===================================================================
--- test/CodeGenCXX/ms_wide_predefined_expr.cpp	(revision 0)
+++ test/CodeGenCXX/ms_wide_predefined_expr.cpp	(revision 0)
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 %s -fms-extensions -emit-llvm -o - | FileCheck %s
+
+// CHECK: @__FUNCTION__._Z4funcv.WChar = private constant [5 x i32] [i32 102, i32 117, i32 110, i32 99, i32 0], align 4
+
+void wprint(const wchar_t*);
+
+#define __STR2WSTR(str) L##str
+#define _STR2WSTR(str) __STR2WSTR(str)
+#define STR2WSTR(str) _STR2WSTR(str)
+
+void func() {
+  wprint(STR2WSTR(__FUNCTION__));
+}
+
+int main() {
+  func();
+
+  return 0;
+}
+
Index: include/clang/Basic/TokenKinds.def
===================================================================
--- include/clang/Basic/TokenKinds.def	(revision 157363)
+++ include/clang/Basic/TokenKinds.def	(working copy)
@@ -421,6 +421,7 @@
 KEYWORD(__thiscall                  , KEYALL)
 KEYWORD(__forceinline               , KEYALL)
 KEYWORD(__unaligned                 , KEYMS)
+KEYWORD(__LPREFIX                   , KEYMS)
 
 // OpenCL-specific keywords
 KEYWORD(__kernel                    , KEYOPENCL)
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td	(revision 157363)
+++ include/clang/Basic/DiagnosticParseKinds.td	(working copy)
@@ -705,6 +705,12 @@
 
 def err_seh___finally_block : Error<
   "%0 only allowed in __finally block">;
+
+def err_ms_extensions_expected_for_lprefix : Error<
+  "Expected MS extensions to be enabled for '__LPREFIX'">;
+
+def err_lprefix_expected_string_literal : Error<
+  "Expected string literal as argument to '__LPREFIX'">;
   
 } // end of Parse Issue category.
 
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h	(revision 157363)
+++ include/clang/Sema/Sema.h	(working copy)
@@ -2620,7 +2620,8 @@
                                       SourceLocation LitEndLoc,
                             TemplateArgumentListInfo *ExplicitTemplateArgs = 0);
 
-  ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
+  ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind,
+                                 CanQualType *ForceTy = 0);
   ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
   ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = 0);
   ExprResult ActOnCharacterConstant(const Token &Tok, Scope *UDLScope = 0);
Index: include/clang/Lex/TokenLexer.h
===================================================================
--- include/clang/Lex/TokenLexer.h	(revision 157363)
+++ include/clang/Lex/TokenLexer.h	(working copy)
@@ -91,6 +91,12 @@
   /// should not be subject to further macro expansion.
   bool DisableMacroExpansion : 1;
 
+  /// MSLPrefix - This is true when we are outputing __LPREFIX( __FUNCTION__)
+  /// for Microsoft comptibility mode
+  bool MSLPrefix : 1;
+  unsigned MSLPrefixState;
+  SourceRange MSLPrefixRange;
+
   TokenLexer(const TokenLexer&);  // DO NOT IMPLEMENT
   void operator=(const TokenLexer&); // DO NOT IMPLEMENT
 public:
@@ -168,6 +174,12 @@
   /// first token on the next line.
   void HandleMicrosoftCommentPaste(Token &Tok);
 
+  /// HandleMicrosoftLPrefix - In Microsoft compatibility mode, L##__FUNCTION__
+  /// pastes to __LPREFIX( __FUNCTION__). This means it turns into multiple
+  /// tokens. When MSLPrefix is true, we output this stream of tokens. If
+  /// this returns true, the caller should immediately return the token.
+  bool HandleMicrosoftLPrefix(Token &Tok);
+
   /// \brief If \arg loc is a FileID and points inside the current macro
   /// definition, returns the appropriate source location pointing at the
   /// macro expansion source location entry.
Index: include/clang/Lex/Token.h
===================================================================
--- include/clang/Lex/Token.h	(revision 157363)
+++ include/clang/Lex/Token.h	(working copy)
@@ -76,7 +76,8 @@
     DisableExpand = 0x04,  // This identifier may never be macro expanded.
     NeedsCleaning = 0x08,   // Contained an escaped newline or trigraph.
     LeadingEmptyMacro = 0x10, // Empty macro exists before this token.
-    HasUDSuffix = 0x20     // This string or character literal has a ud-suffix.
+    HasUDSuffix = 0x20,     // This string or character literal has a ud-suffix.
+    ExpandedFakeMacro = 0x40 // This is a fake macro that has been expanded
   };
 
   tok::TokenKind getKind() const { return (tok::TokenKind)Kind; }
@@ -267,6 +268,13 @@
   /// \brief Return true if this token is a string or character literal which
   /// has a ud-suffix.
   bool hasUDSuffix() const { return (Flags & HasUDSuffix) ? true : false; }
+
+  /// \brief Returns true if this token is an identifier representing
+  /// a fake macro like __FUNCTION__, that would have been expanded if
+  /// it were a real macro like __FILE__
+  bool isExpandedFakeMacro() const {
+    return (Flags & ExpandedFakeMacro) ? true : false;
+  }
 };
 
 /// PPConditionalInfo - Information about the conditional stack (#if directives)
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h	(revision 157363)
+++ include/clang/Parse/Parser.h	(working copy)
@@ -1376,6 +1376,8 @@
   
   ExprResult ParseObjCBoolLiteral();
 
+  ExprResult ParseLPrefixExpression();
+
   //===--------------------------------------------------------------------===//
   // C++ Expressions
   ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp	(revision 157363)
+++ lib/Sema/SemaExpr.cpp	(working copy)
@@ -2374,7 +2374,8 @@
   }
 }
 
-ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
+ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind,
+                                     CanQualType *ForceTy) {
   PredefinedExpr::IdentType IT;
 
   switch (Kind) {
@@ -2402,7 +2403,8 @@
     unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
 
     llvm::APInt LengthI(32, Length + 1);
-    ResTy = Context.CharTy.withConst();
+    if (ForceTy) ResTy = ForceTy->withConst();
+    else ResTy = Context.CharTy.withConst();
     ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
   }
   return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT));
Index: lib/Lex/TokenLexer.cpp
===================================================================
--- lib/Lex/TokenLexer.cpp	(revision 157363)
+++ lib/Lex/TokenLexer.cpp	(working copy)
@@ -32,6 +32,9 @@
   ActualArgs = Actuals;
   CurToken = 0;
 
+  MSLPrefix = false;
+  MSLPrefixState = 0;
+
   ExpandLocStart = Tok.getLocation();
   ExpandLocEnd = ELEnd;
   AtStartOfLine = Tok.isAtStartOfLine();
@@ -91,6 +94,8 @@
   DisableMacroExpansion = disableMacroExpansion;
   NumTokens = NumToks;
   CurToken = 0;
+  MSLPrefix = false;
+  MSLPrefixState = 0;
   ExpandLocStart = ExpandLocEnd = SourceLocation();
   AtStartOfLine = false;
   HasLeadingSpace = false;
@@ -354,9 +359,32 @@
   }
 }
 
+namespace {
+  /// Is the given token one that is treated as a "fake" macro, like
+  /// __FUNCTION__. A fake macro isn't really a macro; it's an identifier
+  /// that is expanded into a string literal during compilation, where
+  /// special rules are obeyed in the preprocessor to make it act a little
+  /// more like a macro. This is used to implement Microsoft's __LPREFIX
+  /// extension for __FUNCTION__.
+  bool IsTokenFakeMacro(const Token &Tok, bool MicrosoftExt) {
+    if (!MicrosoftExt) return false;
+    switch (Tok.getKind()) {
+      case tok::kw___FUNCTION__:
+        return true;
+      default:
+        return false;
+    }
+  }
+}
+
 /// Lex - Lex and return a token from this macro stream.
 ///
 void TokenLexer::Lex(Token &Tok) {
+  // Handle outputting the Microsoft __LPREFIX extension, if the
+  // MSLPrefix flag is set.
+  if (MSLPrefix && HandleMicrosoftLPrefix(Tok))
+    return;
+
   // Lexing off the end of the macro, pop this macro off the expansion stack.
   if (isAtEnd()) {
     // If this is a macro (not a token stream), mark the macro enabled now
@@ -383,6 +411,11 @@
   // Get the next token to return.
   Tok = Tokens[CurToken++];
 
+  // Check for fake macros. If this is a fake macro, mark it expanded.
+  if (IsTokenFakeMacro(Tok, PP.getLangOpts().MicrosoftExt)) {
+    Tok.setFlagValue(Token::ExpandedFakeMacro, true);
+  }
+
   bool TokenIsFromPaste = false;
 
   // If this token is followed by a token paste (##) operator, paste the tokens!
@@ -483,6 +516,34 @@
     if (BufPtr != &Buffer[LHSLen])   // Really, we want the chars in Buffer!
       memcpy(&Buffer[LHSLen], BufPtr, RHSLen);
 
+    // If Microsoft extensions are enabled, special-case token pasting
+    // __FUNCTION__. L##__FUNCTION__ turns into __LPREFIX( __FUNCTION__)
+    if (PP.getLangOpts().MicrosoftExt) {
+      const bool isRHSFunction = RHS.isExpandedFakeMacro()
+        && RHS.getKind() == tok::kw___FUNCTION__;
+      if (isRHSFunction && LHSLen == 1 && Buffer[0] == 'L') {
+        // __LPREFIX( __FUNCTION__)
+        // For this expansion, we don't return a single token; it actually
+        // turns into four tokens. Paste the __LPREFIX token here,
+        // and set MSLPrefix to true. In Lex(), when this flag is set, we'll
+        // continue outputting this series of tokens rather than
+        // continuing to lex.
+        MSLPrefix = true;
+        MSLPrefixState = 0;
+        MSLPrefixRange.setBegin(Tok.getLocation());
+        MSLPrefixRange.setEnd(RHS.getLocation());
+
+        Tok.startToken();
+        Tok.setKind(tok::kw___LPREFIX);
+        Tok.setLength(9);
+        PP.CreateString("__LPREFIX", 9, Tok,
+                        MSLPrefixRange.getBegin(),
+                        MSLPrefixRange.getEnd());
+        ++CurToken;
+        return false;
+      }
+    }
+
     // Trim excess space.
     Buffer.resize(LHSLen+RHSLen);
 
@@ -646,6 +707,52 @@
   PP.HandleMicrosoftCommentPaste(Tok);
 }
 
+/// HandleMicrosoftLPrefix - In Microsoft compatibility mode, L##__FUNCTION__
+/// pastes to __LPREFIX( __FUNCTION__). This means it turns into multiple
+/// tokens. When MSLPrefix is true, we output this stream of tokens. If
+/// this returns true, the caller should immediately return the token.
+bool TokenLexer::HandleMicrosoftLPrefix(Token &Tok) {
+  assert(MSLPrefix && "Expected MSLPrefix to be set");
+
+  SourceLocation StartLoc = MSLPrefixRange.getBegin(),
+                 EndLoc = MSLPrefixRange.getEnd();
+  switch (MSLPrefixState++) {
+  case 0:
+    Tok.startToken();
+    Tok.setKind(tok::l_paren);
+    Tok.setLength(1);
+    PP.CreateString("(", 1, Tok, StartLoc, EndLoc);
+    return true;
+  case 1:
+    // We put a space before __FUNCTION__ to get __LPREFIX( __FUNCTION__)
+    // as Microsoft's compiler does
+    Tok.startToken();
+    Tok.setKind(tok::kw___FUNCTION__);
+    Tok.setLength(13);
+    PP.CreateString(" __FUNCTION__", 13, Tok, StartLoc, EndLoc);
+    return true;
+  case 2:
+    Tok.startToken();
+    Tok.setKind(tok::r_paren);
+    Tok.setLength(1);
+    PP.CreateString(")", 1, Tok, StartLoc, EndLoc);
+    return true;
+  case 3:
+    // Once we've pasted __LPREFIX( __FUNCTION__), look for a token
+    // paste (##) operator. If we find one, skip it. This for example:
+    // #define __ENDTEST(str1, str2) L##str1##str2
+    // #define _ENDTEST(str1, str2) __ENDTEST(str1, str2)
+    // #define ENDTEST _ENDTEST(__FUNCTION__, JUNCTION)
+    // ENDTEST should expand to __LPREFIX( __FUNCTION__)JUNCTION
+    if (Tokens[CurToken].is(tok::hashhash)) ++CurToken;
+    MSLPrefix = false;
+    return false;
+  default:
+    assert(false);
+    return false;
+  }
+}
+
 /// \brief If \arg loc is a file ID and points inside the current macro
 /// definition, returns the appropriate source location pointing at the
 /// macro expansion source location entry, otherwise it returns an invalid
Index: lib/Lex/LiteralSupport.cpp
===================================================================
--- lib/Lex/LiteralSupport.cpp	(revision 157363)
+++ lib/Lex/LiteralSupport.cpp	(working copy)
@@ -1090,6 +1090,15 @@
 
   // TODO: K&R warning: "traditional C rejects string constant concatenation"
 
+  // If the first token is __LPREFIX, parse the string literal as if it
+  // started with 'L', and skip the token. When the parser encounters
+  // __LPREFIX("string"), it passes us __LPREFIX "string" as two tokens.
+  if (Kind == tok::kw___LPREFIX) {
+    Kind = tok::wide_string_literal;
+    ++StringToks;
+    --NumStringToks;
+  }
+
   // Get the width in bytes of char/wchar_t/char16_t/char32_t
   CharByteWidth = getCharWidth(Kind, Target);
   assert((CharByteWidth & 7) == 0 && "Assumes character size is byte multiple");
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp	(revision 157363)
+++ lib/CodeGen/CGExpr.cpp	(working copy)
@@ -21,6 +21,7 @@
 #include "TargetInfo.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
+#include "clang/Basic/ConvertUTF.h"
 #include "clang/Frontend/CodeGenOptions.h"
 #include "llvm/Intrinsics.h"
 #include "llvm/LLVMContext.h"
@@ -1683,7 +1684,76 @@
                         E->getType());
 }
 
+namespace {
+  llvm::Constant*
+  GetAddrOfConstantWideString(StringRef Str,
+                              const char *GlobalName,
+                              ASTContext &Context,
+                              QualType Ty, SourceLocation Loc,
+                              CodeGenModule &CGM) {
 
+    StringLiteral *SL = StringLiteral::Create(Context,
+                                              Str,
+                                              StringLiteral::Wide,
+                                              /*Pascal = */false,
+                                              Ty, Loc);
+    llvm::Constant *C = CGM.GetConstantArrayFromStringLiteral(SL);
+    llvm::GlobalVariable *GV =
+      new llvm::GlobalVariable(CGM.getModule(), C->getType(),
+                               !CGM.getLangOpts().WritableStrings,
+                               llvm::GlobalValue::PrivateLinkage,
+                               C, GlobalName);
+    const unsigned WideAlignment =
+      Context.getTypeAlignInChars(Ty).getQuantity();
+    GV->setAlignment(WideAlignment);
+    return GV;
+  }
+
+  // FIXME: Mostly copied from StringLiteralParser::CopyStringFragment
+  void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source,
+                               SmallString<32>& Target) {
+    Target.resize(CharByteWidth * (Source.size() + 1));
+    char* ResultPtr = &Target[0];
+
+    assert(CharByteWidth==1 || CharByteWidth==2 || CharByteWidth==4);
+    ConversionResult result = conversionOK;
+    // Copy the character span over.
+    if (CharByteWidth == 1) {
+      if (!isLegalUTF8String(reinterpret_cast<const UTF8*>(&*Source.begin()),
+                             reinterpret_cast<const UTF8*>(&*Source.end())))
+        result = sourceIllegal;
+      memcpy(ResultPtr, Source.data(), Source.size());
+      ResultPtr += Source.size();
+    } else if (CharByteWidth == 2) {
+      UTF8 const *sourceStart = (UTF8 const *)Source.data();
+      // FIXME: Make the type of the result buffer correct instead of
+      // using reinterpret_cast.
+      UTF16 *targetStart = reinterpret_cast<UTF16*>(ResultPtr);
+      ConversionFlags flags = strictConversion;
+      result = ConvertUTF8toUTF16(
+        &sourceStart,sourceStart + Source.size(),
+          &targetStart,targetStart + 2*Source.size(),flags);
+      if (result==conversionOK)
+        ResultPtr = reinterpret_cast<char*>(targetStart);
+    } else if (CharByteWidth == 4) {
+      UTF8 const *sourceStart = (UTF8 const *)Source.data();
+      // FIXME: Make the type of the result buffer correct instead of
+      // using reinterpret_cast.
+      UTF32 *targetStart = reinterpret_cast<UTF32*>(ResultPtr);
+      ConversionFlags flags = strictConversion;
+      result = ConvertUTF8toUTF32(
+          &sourceStart,sourceStart + Source.size(),
+          &targetStart,targetStart + 4*Source.size(),flags);
+      if (result==conversionOK)
+        ResultPtr = reinterpret_cast<char*>(targetStart);
+    }
+    assert((result != targetExhausted)
+           && "ConvertUTF8toUTFXX exhausted target buffer");
+    assert(result == conversionOK);
+    Target.resize(ResultPtr - &Target[0]);
+  }
+}
+
 LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
   switch (E->getIdentType()) {
   default:
@@ -1722,8 +1792,27 @@
          ? FnName.str()
          : PredefinedExpr::ComputeName((PredefinedExpr::IdentType)Type, CurDecl));
 
-    llvm::Constant *C =
-      CGM.GetAddrOfConstantCString(FunctionName, GlobalVarName.c_str());
+    const ConstantArrayType *CAT =
+      getContext().getAsConstantArrayType(E->getType());
+    QualType ElemType = CAT->getElementType();
+    llvm::Constant *C;
+    if (ElemType == getContext().WCharTy.withConst()) {
+      GlobalVarName += ".WChar";
+      SmallString<32> RawChars;
+      ConvertUTF8ToWideString(
+          getContext().getTypeSizeInChars(ElemType).getQuantity(),
+          FunctionName, RawChars);
+      C = GetAddrOfConstantWideString(RawChars,
+                                      GlobalVarName.c_str(),
+                                      getContext(),
+                                      E->getType(),
+                                      E->getLocation(),
+                                      CGM);
+    } else {
+      C = CGM.GetAddrOfConstantCString(FunctionName,
+                                       GlobalVarName.c_str(),
+                                       1);
+    }
     return MakeAddrLValue(C, E->getType());
   }
   }
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp	(revision 157363)
+++ lib/Parse/ParseExpr.cpp	(working copy)
@@ -857,6 +857,9 @@
   case tok::utf32_string_literal:
     Res = ParseStringLiteralExpression(true);
     break;
+  case tok::kw___LPREFIX:
+    Res = ParseLPrefixExpression();
+    break;
   case tok::kw__Generic:   // primary-expression: generic-selection [C11 6.5.1]
     Res = ParseGenericSelectionExpression();
     break;
@@ -2429,3 +2432,63 @@
   tok::TokenKind Kind = Tok.getKind();
   return Actions.ActOnObjCBoolLiteral(ConsumeToken(), Kind);
 }
+
+/// ParseLPrefixExpression - This is for a Microsoft expression.
+///         '__LPREFIX' '(' string-literal ')'
+///         '__LPREFIX' '(' __FUNCTION__ ')'
+ExprResult Parser::ParseLPrefixExpression() {
+  assert(Tok.getKind() == tok::kw___LPREFIX);
+
+  // MS extensions should be enabled or we should give an error.
+  // Still parse regularly, though.
+  if (!PP.getLangOpts().MicrosoftExt) {
+    Diag(Tok, diag::err_ms_extensions_expected_for_lprefix);
+  }
+
+  // Eat the __LPREFIX
+  Token LPrefixTok = Tok;
+  ConsumeToken();
+
+  // Expect a lparen
+  if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen,
+                       "", tok::r_paren))
+    return ExprError();
+
+
+  ExprResult Res;
+  switch (Tok.getKind()) {
+    case tok::kw___FUNCTION__:
+      Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), Tok.getKind(),
+                                        &Actions.Context.WCharTy);
+      ConsumeToken();
+      break;
+    case tok::string_literal: {
+      // Pass the string literal parser __LPREFIX "string" without the
+      // parentheses. The string literal parser will treat __LPREFIX
+      // like 'L'.
+      SmallVector<Token, 4> StringToks;
+      StringToks.push_back(LPrefixTok);
+
+      do {
+        StringToks.push_back(Tok);
+        ConsumeStringToken();
+      } while (isTokenStringLiteral());
+
+      // Pass the set of string tokens, ready for concatenation, to the actions.
+      Res = Actions.ActOnStringLiteral(&StringToks[0], StringToks.size(), 0);
+      break;
+    }
+    default:
+      Diag(Tok, diag::err_lprefix_expected_string_literal);
+      SkipUntil(tok::r_paren);
+      Res = ExprError();
+      break;
+  }
+  
+  // Expect a rparen
+  if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen, ""))
+    return ExprError();
+
+  return Res;
+}
+

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20120611/cf86e44e/attachment.html>


More information about the cfe-commits mailing list