Add support for MSVC's __FUNCSIG__

It is very similar to GCC's __PRETTY_FUNCTION__, except it prints the
calling convention.

Reviewers: majnemer

Differential Revision: http://reviews.llvm.org/D3311

llvm-svn: 205780
This commit is contained in:
Reid Kleckner 2014-04-08 18:13:24 +00:00
parent d88fec3d3a
commit 52edddaea5
10 changed files with 65 additions and 23 deletions

View File

@ -1164,6 +1164,7 @@ public:
Function,
LFunction, // Same as Function, but as wide string.
FuncDName,
FuncSig,
PrettyFunction,
/// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
/// 'virtual' keyword is omitted for virtual member functions.

View File

@ -365,6 +365,7 @@ KEYWORD(typeof , KEYGNU)
// MS Extensions
KEYWORD(__FUNCDNAME__ , KEYMS)
KEYWORD(__FUNCSIG__ , KEYMS)
KEYWORD(L__FUNCTION__ , KEYMS)
TYPE_TRAIT_1(__is_interface_class, IsInterfaceClass, KEYMS)
TYPE_TRAIT_1(__is_sealed, IsSealed, KEYMS)

View File

@ -1684,6 +1684,7 @@ void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
case PredefinedExpr::FuncDName: OS << " __FUNCDNAME__"; break;
case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
case PredefinedExpr::FuncSig: OS << " __FUNCSIG__"; break;
}
}

View File

@ -478,7 +478,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
return "";
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual)
if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual && IT != FuncSig)
return FD->getNameAsString();
SmallString<256> Name;
@ -494,7 +494,6 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
PrintingPolicy Policy(Context.getLangOpts());
std::string Proto;
llvm::raw_string_ostream POut(Proto);
FD->printQualifiedName(POut, Policy);
const FunctionDecl *Decl = FD;
if (const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern())
@ -504,6 +503,19 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
if (FD->hasWrittenPrototype())
FT = dyn_cast<FunctionProtoType>(AFT);
if (IT == FuncSig) {
switch (FT->getCallConv()) {
case CC_C: POut << "__cdecl "; break;
case CC_X86StdCall: POut << "__stdcall "; break;
case CC_X86FastCall: POut << "__fastcall "; break;
case CC_X86ThisCall: POut << "__thiscall "; break;
// Only bother printing the conventions that MSVC knows about.
default: break;
}
}
FD->printQualifiedName(POut, Policy);
POut << "(";
if (FT) {
for (unsigned i = 0, e = Decl->getNumParams(); i != e; ++i) {

View File

@ -789,6 +789,9 @@ void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
case PredefinedExpr::FuncDName:
OS << "__FUNCDNAME__";
break;
case PredefinedExpr::FuncSig:
OS << "__FUNCSIG__";
break;
case PredefinedExpr::LFunction:
OS << "L__FUNCTION__";
break;

View File

@ -1953,33 +1953,27 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
case PredefinedExpr::Function:
case PredefinedExpr::LFunction:
case PredefinedExpr::FuncDName:
case PredefinedExpr::FuncSig:
case PredefinedExpr::PrettyFunction: {
PredefinedExpr::IdentType IdentType = E->getIdentType();
std::string GlobalVarName;
std::string GVName;
// FIXME: We should use the string literal mangling for the Microsoft C++
// ABI so that strings get merged.
switch (IdentType) {
default: llvm_unreachable("Invalid type");
case PredefinedExpr::Func:
GlobalVarName = "__func__.";
break;
case PredefinedExpr::Function:
GlobalVarName = "__FUNCTION__.";
break;
case PredefinedExpr::FuncDName:
GlobalVarName = "__FUNCDNAME__.";
break;
case PredefinedExpr::LFunction:
GlobalVarName = "L__FUNCTION__.";
break;
case PredefinedExpr::PrettyFunction:
GlobalVarName = "__PRETTY_FUNCTION__.";
break;
case PredefinedExpr::Func: GVName = "__func__."; break;
case PredefinedExpr::Function: GVName = "__FUNCTION__."; break;
case PredefinedExpr::FuncDName: GVName = "__FUNCDNAME__."; break;
case PredefinedExpr::FuncSig: GVName = "__FUNCSIG__."; break;
case PredefinedExpr::LFunction: GVName = "L__FUNCTION__."; break;
case PredefinedExpr::PrettyFunction: GVName = "__PRETTY_FUNCTION__."; break;
}
StringRef FnName = CurFn->getName();
if (FnName.startswith("\01"))
FnName = FnName.substr(1);
GlobalVarName += FnName;
GVName += FnName;
// If this is outside of a function use the top level decl.
const Decl *CurDecl = CurCodeDecl;
@ -2010,15 +2004,13 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
getContext().getTypeSizeInChars(ElemType).getQuantity(),
FunctionName, RawChars);
C = GetAddrOfConstantWideString(RawChars,
GlobalVarName.c_str(),
GVName.c_str(),
getContext(),
E->getType(),
E->getLocation(),
CGM);
} else {
C = CGM.GetAddrOfConstantCString(FunctionName,
GlobalVarName.c_str(),
1);
C = CGM.GetAddrOfConstantCString(FunctionName, GVName.c_str(), 1);
}
return MakeAddrLValue(C, E->getType());
}

View File

@ -835,6 +835,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU]
case tok::kw___FUNCDNAME__: // primary-expression: __FUNCDNAME__ [MS]
case tok::kw___FUNCSIG__: // primary-expression: __FUNCSIG__ [MS]
case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS]
case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU]
Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind);

View File

@ -936,6 +936,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___real:
case tok::kw___FUNCTION__:
case tok::kw___FUNCDNAME__:
case tok::kw___FUNCSIG__:
case tok::kw_L__FUNCTION__:
case tok::kw___PRETTY_FUNCTION__:
case tok::kw___uuidof:

View File

@ -2872,6 +2872,7 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
case tok::kw___func__: IT = PredefinedExpr::Func; break; // [C99 6.4.2.2]
case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break;
case tok::kw___FUNCDNAME__: IT = PredefinedExpr::FuncDName; break; // [MS]
case tok::kw___FUNCSIG__: IT = PredefinedExpr::FuncSig; break; // [MS]
case tok::kw_L__FUNCTION__: IT = PredefinedExpr::LFunction; break;
case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break;
}

View File

@ -0,0 +1,29 @@
// RUN: %clang_cc1 -std=c++11 %s -fms-extensions -fno-rtti -emit-llvm -o - | FileCheck %s
// Similar to predefined-expr.cpp, but not as exhaustive, since it's basically
// equivalent to __PRETTY_FUNCTION__.
extern "C" int printf(const char *, ...);
void freeFunc(int *, char) {
printf("__FUNCSIG__ %s\n\n", __FUNCSIG__);
}
// CHECK: private unnamed_addr constant [{{.*}} x i8] c"void __cdecl freeFunc(int *, char)\00"
struct TopLevelClass {
void topLevelMethod(int *, char);
};
void TopLevelClass::topLevelMethod(int *, char) {
printf("__FUNCSIG__ %s\n\n", __FUNCSIG__);
}
// CHECK: private unnamed_addr constant [{{.*}} x i8] c"void __thiscall TopLevelClass::topLevelMethod(int *, char)\00"
namespace NS {
struct NamespacedClass {
void namespacedMethod(int *, char);
};
void NamespacedClass::namespacedMethod(int *, char) {
printf("__FUNCSIG__ %s\n\n", __FUNCSIG__);
}
// CHECK: private unnamed_addr constant [{{.*}} x i8] c"void __thiscall NS::NamespacedClass::namespacedMethod(int *, char)\00"
}