};
// Function classes
-enum FuncClass : uint8_t {
+enum FuncClass : uint16_t {
Public = 1 << 0,
Protected = 1 << 1,
Private = 1 << 2,
Static = 1 << 4,
Virtual = 1 << 5,
Far = 1 << 6,
+ ExternC = 1 << 7,
+ NoPrototype = 1 << 8,
};
enum NameBackrefBehavior : uint8_t {
if (FunctionClass & Static)
OS << "static ";
}
+ if (FunctionClass & ExternC) {
+ OS << "extern \"C\" ";
+ }
if (ReturnType) {
Type::outputPre(OS, *ReturnType, Resolver);
}
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 << ")";
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 {
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;
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;
?s6@PR13182@@3PBQBDB
; CHECK: char const *const *PR13182::s6
-; FIXME: We don't properly support extern "C" functions yet.
-; ?local@?1??extern_c_func@@9@4HA
-; FIXME: int `extern_c_func'::`2'::local
+?local@?1??extern_c_func@@9@4HA
+; CHECK: int `extern "C" extern_c_func'::`2'::local
-; ?local@?1??extern_c_func@@9@4HA
-; FIXME: int `extern_c_func'::`2'::local
+?local@?1??extern_c_func@@9@4HA
+; CHECK: int `extern "C" extern_c_func'::`2'::local
?v@?1??f@@YAHXZ@4U<unnamed-type-v>@?1??1@YAHXZ@A
; CHECK: struct `int __cdecl f(void)'::`2'::<unnamed-type-v> `int __cdecl f(void)'::`2'::v
?vector_func@@YQXXZ
; CHECK: void __vectorcall vector_func(void)
-; FIXME: We don't support extern C funcs currently.
-; ??$fn_tmpl@$1?extern_c_func@@YAXXZ@@YAXXZ
-; FIXME: void __cdecl fn_tmpl<&void __cdecl extern_c_func(void)>(void)
+??$fn_tmpl@$1?extern_c_func@@YAXXZ@@YAXXZ
+; CHECK: void __cdecl fn_tmpl<&void __cdecl extern_c_func(void)>(void)
-; ?overloaded_fn@@$$J0YAXXZ
-; FIXME-EXTERNC: extern \"C\" void __cdecl overloaded_fn(void)
+?overloaded_fn@@$$J0YAXXZ
+; CHECK: extern "C" void __cdecl overloaded_fn(void)
?f@UnnamedType@@YAXQAPAU<unnamed-type-T1>@S@1@@Z
; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::<unnamed-type-T1> **const)