From 52edddaea5d99dd8227231da1a47d9ce3600cb38 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 8 Apr 2014 18:13:24 +0000 Subject: [PATCH] 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 --- clang/include/clang/AST/Expr.h | 1 + clang/include/clang/Basic/TokenKinds.def | 1 + clang/lib/AST/ASTDumper.cpp | 1 + clang/lib/AST/Expr.cpp | 16 +++++++++-- clang/lib/AST/StmtPrinter.cpp | 3 +++ clang/lib/CodeGen/CGExpr.cpp | 34 +++++++++--------------- clang/lib/Parse/ParseExpr.cpp | 1 + clang/lib/Parse/ParseTentative.cpp | 1 + clang/lib/Sema/SemaExpr.cpp | 1 + clang/test/CodeGenCXX/funcsig.cpp | 29 ++++++++++++++++++++ 10 files changed, 65 insertions(+), 23 deletions(-) create mode 100644 clang/test/CodeGenCXX/funcsig.cpp diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index adc8308f535f..f0226758f406 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -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. diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 42ebcf8e9e11..47e23ff04998 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -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) diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index dcfba3e339ff..39019792ee5e 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -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; } } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index f29e9fe4c072..f023fe804b6b 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -478,7 +478,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { return ""; } if (const FunctionDecl *FD = dyn_cast(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(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) { diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 7ad549100565..5cfaab26e533 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -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; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 1bdd094873a3..badde1b7c9ea 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -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()); } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index ed9d72d33866..15b327d1efbe 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -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); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 330e5416594f..71d19613a7ef 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -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: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c6e3e23fdd6b..db31ad0cd078 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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; } diff --git a/clang/test/CodeGenCXX/funcsig.cpp b/clang/test/CodeGenCXX/funcsig.cpp new file mode 100644 index 000000000000..76f43858c094 --- /dev/null +++ b/clang/test/CodeGenCXX/funcsig.cpp @@ -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" +}