[MS Demangler] Support extern "C" functions.

There are two cases we need to support with extern "C"
functions.  The first is the case of a '9' indicating that
the function has no prototype.  This occurs when we mangle
a symbol inside of an extern "C" function, but not the
function itself.

The second case is when we have an overloaded extern "C"
functions.  In this case we emit $$J0 to indicate this.
This patch adds support for both of these cases.

llvm-svn: 339471
diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp
index d9aed64..cab662f9 100644
--- a/llvm/lib/Demangle/MicrosoftDemangle.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp
@@ -195,7 +195,7 @@
 };
 
 // Function classes
-enum FuncClass : uint8_t {
+enum FuncClass : uint16_t {
   Public = 1 << 0,
   Protected = 1 << 1,
   Private = 1 << 2,
@@ -203,6 +203,8 @@
   Static = 1 << 4,
   Virtual = 1 << 5,
   Far = 1 << 6,
+  ExternC = 1 << 7,
+  NoPrototype = 1 << 8,
 };
 
 enum NameBackrefBehavior : uint8_t {
@@ -833,6 +835,9 @@
     if (FunctionClass & Static)
       OS << "static ";
   }
+  if (FunctionClass & ExternC) {
+    OS << "extern \"C\" ";
+  }
 
   if (ReturnType) {
     Type::outputPre(OS, *ReturnType, Resolver);
@@ -847,6 +852,10 @@
 }
 
 void FunctionType::outputPost(OutputStream &OS, NameResolver &Resolver) {
+  // extern "C" functions don't have a prototype.
+  if (FunctionClass & NoPrototype)
+    return;
+
   OS << "(";
   outputParameterList(OS, Params, Resolver);
   OS << ")";
@@ -1059,7 +1068,9 @@
   if (Error)
     return nullptr;
   // Read a variable.
-  if (startsWithDigit(MangledName)) {
+  if (startsWithDigit(MangledName) && !MangledName.startsWith('9')) {
+    // 9 is a special marker for an extern "C" function with
+    // no prototype.
     S->Category = SymbolCategory::Variable;
     S->SymbolType = demangleVariableEncoding(MangledName);
   } else {
@@ -1517,47 +1528,53 @@
   SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
   RestoreOnError.shouldRestore(false);
 
+  FuncClass TempFlags = FuncClass(0);
+  if (MangledName.consumeFront("$$J0"))
+    TempFlags = ExternC;
+
   switch (MangledName.popFront()) {
+  case '9':
+    return FuncClass(TempFlags | ExternC | NoPrototype);
   case 'A':
     return Private;
   case 'B':
-    return FuncClass(Private | Far);
+    return FuncClass(TempFlags | Private | Far);
   case 'C':
-    return FuncClass(Private | Static);
+    return FuncClass(TempFlags | Private | Static);
   case 'D':
-    return FuncClass(Private | Static);
+    return FuncClass(TempFlags | Private | Static);
   case 'E':
-    return FuncClass(Private | Virtual);
+    return FuncClass(TempFlags | Private | Virtual);
   case 'F':
-    return FuncClass(Private | Virtual);
+    return FuncClass(TempFlags | Private | Virtual);
   case 'I':
-    return Protected;
+    return FuncClass(TempFlags | Protected);
   case 'J':
-    return FuncClass(Protected | Far);
+    return FuncClass(TempFlags | Protected | Far);
   case 'K':
-    return FuncClass(Protected | Static);
+    return FuncClass(TempFlags | Protected | Static);
   case 'L':
-    return FuncClass(Protected | Static | Far);
+    return FuncClass(TempFlags | Protected | Static | Far);
   case 'M':
-    return FuncClass(Protected | Virtual);
+    return FuncClass(TempFlags | Protected | Virtual);
   case 'N':
-    return FuncClass(Protected | Virtual | Far);
+    return FuncClass(TempFlags | Protected | Virtual | Far);
   case 'Q':
-    return Public;
+    return FuncClass(TempFlags | Public);
   case 'R':
-    return FuncClass(Public | Far);
+    return FuncClass(TempFlags | Public | Far);
   case 'S':
-    return FuncClass(Public | Static);
+    return FuncClass(TempFlags | Public | Static);
   case 'T':
-    return FuncClass(Public | Static | Far);
+    return FuncClass(TempFlags | Public | Static | Far);
   case 'U':
-    return FuncClass(Public | Virtual);
+    return FuncClass(TempFlags | Public | Virtual);
   case 'V':
-    return FuncClass(Public | Virtual | Far);
+    return FuncClass(TempFlags | Public | Virtual | Far);
   case 'Y':
-    return Global;
+    return FuncClass(TempFlags | Global);
   case 'Z':
-    return FuncClass(Global | Far);
+    return FuncClass(TempFlags | Global | Far);
   }
 
   Error = true;
@@ -1768,9 +1785,16 @@
 
 Type *Demangler::demangleFunctionEncoding(StringView &MangledName) {
   FuncClass FC = demangleFunctionClass(MangledName);
-
-  bool HasThisQuals = !(FC & (Global | Static));
-  FunctionType *FTy = demangleFunctionType(MangledName, HasThisQuals, false);
+  FunctionType *FTy = nullptr;
+  if (FC & NoPrototype) {
+    // This is an extern "C" function whose full signature hasn't been mangled.
+    // This happens when we need to mangle a local symbol inside of an extern
+    // "C" function.
+    FTy = Arena.alloc<FunctionType>();
+  } else {
+    bool HasThisQuals = !(FC & (Global | Static));
+    FTy = demangleFunctionType(MangledName, HasThisQuals, false);
+  }
   FTy->FunctionClass = FC;
 
   return FTy;