]> granicus.if.org Git - clang/commitdiff
Add support for MSVC's __FUNCSIG__
authorReid Kleckner <reid@kleckner.net>
Tue, 8 Apr 2014 18:13:24 +0000 (18:13 +0000)
committerReid Kleckner <reid@kleckner.net>
Tue, 8 Apr 2014 18:13:24 +0000 (18:13 +0000)
It is very similar to GCC's __PRETTY_FUNCTION__, except it prints the
calling convention.

Reviewers: majnemer

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205780 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Expr.h
include/clang/Basic/TokenKinds.def
lib/AST/ASTDumper.cpp
lib/AST/Expr.cpp
lib/AST/StmtPrinter.cpp
lib/CodeGen/CGExpr.cpp
lib/Parse/ParseExpr.cpp
lib/Parse/ParseTentative.cpp
lib/Sema/SemaExpr.cpp
test/CodeGenCXX/funcsig.cpp [new file with mode: 0644]

index adc8308f535f1e4f2d8a814c2f20032538c1183e..f0226758f4064610c6425a3ceee4434ef5ddb4aa 100644 (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.
index 42ebcf8e9e11c3da826ef4cdbf5253426dc8809e..47e23ff04998d3021decc09bf22aaf6e7a060b6f 100644 (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)
index dcfba3e339ff3bf83b2c470b103fc79b74d43864..39019792ee5e483de1c69e9be8234a3a38004706 100644 (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;
   }
 }
 
index f29e9fe4c0729a99a762356025c64cc07a782c6f..f023fe804b6b2fc9550d81e545cabf4318d0258a 100644 (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) {
index 7ad549100565cc502e5f26ff192106909fb55ad2..5cfaab26e53350db790b79a17231d32b45d318d6 100644 (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;
index 1bdd094873a3dcb6e31450d94c4eae37fa2e2156..badde1b7c9eac7198401731a3b19de87800826fa 100644 (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());
   }
index ed9d72d33866122a84de003fdcda0cafe68a348f..15b327d1efbed74958240b566c0c40027be3354e 100644 (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);
index 330e5416594f1b779315c8267aeb17a0e65d998b..71d19613a7efcbe79034362d6231210af0be3673 100644 (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:
index c6e3e23fdd6b820203fc0dbfb9b99c4ec2881c6f..db31ad0cd0780f1b7d369f30143d6dbc49f939f6 100644 (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;
   }
diff --git a/test/CodeGenCXX/funcsig.cpp b/test/CodeGenCXX/funcsig.cpp
new file mode 100644 (file)
index 0000000..76f4385
--- /dev/null
@@ -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"
+}