[clang-tools-extra] [clang-cl] Fix for __FUNCTION__ in c++. (PR #66120)

Zahira Ammarguellat via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 21 08:40:44 PDT 2023


https://github.com/zahiraam updated https://github.com/llvm/llvm-project/pull/66120

>From 3fcfa303bd211f9a3382657012968cd3f7269db8 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Tue, 12 Sep 2023 11:25:19 -0700
Subject: [PATCH 1/4] [clang-cl] Fix for __FUNCTION__ in c++.

---
 clang/lib/AST/Expr.cpp        | 20 ++++++++++++++++++++
 clang/lib/AST/TypePrinter.cpp |  4 ++++
 2 files changed, 24 insertions(+)

diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 4f3837371b3fc5e..55b6e2968487b86 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -727,6 +727,26 @@ StringRef PredefinedExpr::getIdentKindName(PredefinedExpr::IdentKind IK) {
 std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) {
   ASTContext &Context = CurrentDecl->getASTContext();
 
+  if (CurrentDecl->getASTContext().getTargetInfo().getCXXABI().isMicrosoft() &&
+      IK == PredefinedExpr::Function) {
+    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
+      SmallString<256> Name;
+      llvm::raw_svector_ostream Out(Name);
+      PrintingPolicy Policy(Context.getLangOpts());
+      Policy.AlwaysIncludeTypeForTemplateArgument = true;
+      std::string Proto;
+      llvm::raw_string_ostream POut(Proto);
+      const FunctionDecl *Decl = FD;
+      if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern())
+        Decl = Pattern;
+      const FunctionType *AFT = Decl->getType()->getAs<FunctionType>();
+      const FunctionProtoType *FT = nullptr;
+      if (FD->hasWrittenPrototype())
+        FT = dyn_cast<FunctionProtoType>(AFT);
+      FD->printQualifiedName(POut, Policy);
+      return std::string(POut.str());
+    }
+  }
   if (IK == PredefinedExpr::FuncDName) {
     if (const NamedDecl *ND = dyn_cast<NamedDecl>(CurrentDecl)) {
       std::unique_ptr<MangleContext> MC;
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index eb69d0bb8755b48..676ce166312adf4 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2218,6 +2218,10 @@ printTo(raw_ostream &OS, ArrayRef<TA> Args, const PrintingPolicy &Policy,
     } else {
       if (!FirstArg)
         OS << Comma;
+      // zahira
+      //if (Argument.getKind() == TemplateArgument::Type)
+      //  OS << "class ";
+
       // Tries to print the argument with location info if exists.
       printArgument(Arg, Policy, ArgOS,
                     TemplateParameterList::shouldIncludeTypeForArgument(

>From f2c2d9ca4120d61e8cf75165693ead19890be0e0 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 13 Sep 2023 06:45:03 -0700
Subject: [PATCH 2/4] Testing.

---
 clang/lib/AST/TypePrinter.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 676ce166312adf4..e4abf4b2160682a 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2218,7 +2218,6 @@ printTo(raw_ostream &OS, ArrayRef<TA> Args, const PrintingPolicy &Policy,
     } else {
       if (!FirstArg)
         OS << Comma;
-      // zahira
       //if (Argument.getKind() == TemplateArgument::Type)
       //  OS << "class ";
 

>From 5e85929ce09c0c73b10c5557ee14f431f8a59808 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Tue, 19 Sep 2023 11:44:16 -0700
Subject: [PATCH 3/4] Addressed review comments.

---
 clang/lib/AST/Expr.cpp                    | 47 +++++++++--------------
 clang/lib/AST/TypePrinter.cpp             |  4 +-
 clang/test/CodeGenCXX/predefined-expr.cpp | 19 +++++++++
 clang/test/SemaCXX/source_location.cpp    | 12 ++++++
 4 files changed, 51 insertions(+), 31 deletions(-)

diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 55b6e2968487b86..4d258c92dda3012 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -727,26 +727,6 @@ StringRef PredefinedExpr::getIdentKindName(PredefinedExpr::IdentKind IK) {
 std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) {
   ASTContext &Context = CurrentDecl->getASTContext();
 
-  if (CurrentDecl->getASTContext().getTargetInfo().getCXXABI().isMicrosoft() &&
-      IK == PredefinedExpr::Function) {
-    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
-      SmallString<256> Name;
-      llvm::raw_svector_ostream Out(Name);
-      PrintingPolicy Policy(Context.getLangOpts());
-      Policy.AlwaysIncludeTypeForTemplateArgument = true;
-      std::string Proto;
-      llvm::raw_string_ostream POut(Proto);
-      const FunctionDecl *Decl = FD;
-      if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern())
-        Decl = Pattern;
-      const FunctionType *AFT = Decl->getType()->getAs<FunctionType>();
-      const FunctionProtoType *FT = nullptr;
-      if (FD->hasWrittenPrototype())
-        FT = dyn_cast<FunctionProtoType>(AFT);
-      FD->printQualifiedName(POut, Policy);
-      return std::string(POut.str());
-    }
-  }
   if (IK == PredefinedExpr::FuncDName) {
     if (const NamedDecl *ND = dyn_cast<NamedDecl>(CurrentDecl)) {
       std::unique_ptr<MangleContext> MC;
@@ -792,18 +772,21 @@ std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) {
     return std::string(Out.str());
   }
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
-    if (IK != PrettyFunction && IK != PrettyFunctionNoVirtual &&
-        IK != FuncSig && IK != LFuncSig)
+    const auto &LO = Context.getLangOpts();
+    if (((IK == Func || IK == Function) && !LO.MicrosoftExt) ||
+        (IK == LFunction && LO.MicrosoftExt))
       return FD->getNameAsString();
 
     SmallString<256> Name;
     llvm::raw_svector_ostream Out(Name);
 
-    if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
-      if (MD->isVirtual() && IK != PrettyFunctionNoVirtual)
-        Out << "virtual ";
-      if (MD->isStatic())
-        Out << "static ";
+    if (IK != Function) {
+      if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+        if (MD->isVirtual() && IK != PrettyFunctionNoVirtual)
+          Out << "virtual ";
+        if (MD->isStatic())
+          Out << "static ";
+      }
     }
 
     class PrettyCallbacks final : public PrintingCallbacks {
@@ -818,9 +801,10 @@ std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) {
     private:
       const LangOptions &LO;
     };
-    PrintingPolicy Policy(Context.getLangOpts());
-    PrettyCallbacks PrettyCB(Context.getLangOpts());
+    PrintingPolicy Policy(LO);
+    PrettyCallbacks PrettyCB(LO);
     Policy.Callbacks = &PrettyCB;
+    Policy.MSVCFormatting = LO.MicrosoftExt;
     std::string Proto;
     llvm::raw_string_ostream POut(Proto);
 
@@ -847,6 +831,11 @@ std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) {
 
     FD->printQualifiedName(POut, Policy);
 
+    if ((IK == Function || IK == Func) && LO.MicrosoftExt) {
+      Out << Proto;
+      return std::string(Name);
+    }
+
     POut << "(";
     if (FT) {
       for (unsigned i = 0, e = Decl->getNumParams(); i != e; ++i) {
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index e4abf4b2160682a..589c4e03e329e7e 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2218,8 +2218,8 @@ printTo(raw_ostream &OS, ArrayRef<TA> Args, const PrintingPolicy &Policy,
     } else {
       if (!FirstArg)
         OS << Comma;
-      //if (Argument.getKind() == TemplateArgument::Type)
-      //  OS << "class ";
+      if (Policy.MSVCFormatting && Argument.getKind() == TemplateArgument::Type)
+        OS << "class ";
 
       // Tries to print the argument with location info if exists.
       printArgument(Arg, Policy, ArgOS,
diff --git a/clang/test/CodeGenCXX/predefined-expr.cpp b/clang/test/CodeGenCXX/predefined-expr.cpp
index 815bcbb3bd8992f..af76e0538a9ec9f 100644
--- a/clang/test/CodeGenCXX/predefined-expr.cpp
+++ b/clang/test/CodeGenCXX/predefined-expr.cpp
@@ -5,6 +5,8 @@
 // CHECK-DAG: private unnamed_addr constant [49 x i8] c"void functionTemplateExplicitSpecialization(int)\00"
 
 // CHECK-DAG: private unnamed_addr constant [95 x i8] c"void SpecializedClassTemplate<char>::memberFunctionTemplate(T, U) const [T = char, U = double]\00"
+// CHECK-DAG: private unnamed_addr constant [43 x i8] c"TestClass<class UnitTestNative>::TestClass\00"
+// CHECK-DAG: private unnamed_addr constant [10 x i8] c"TestClass\00"
 // CHECK-DAG: private unnamed_addr constant [85 x i8] c"void SpecializedClassTemplate<int>::memberFunctionTemplate(int, U) const [U = float]\00"
 // CHECK-DAG: private unnamed_addr constant [57 x i8] c"void NonTypeTemplateParam<42>::size() const [Count = 42]\00"
 // CHECK-DAG: private unnamed_addr constant [103 x i8] c"static void ClassWithTemplateTemplateParam<char>::staticMember() [T = char, Param = NS::ClassTemplate]\00"
@@ -101,6 +103,7 @@
 
 
 int printf(const char * _Format, ...);
+int strcmp(const char *, const char *);
 
 class ClassInTopLevelNamespace {
 public:
@@ -455,6 +458,21 @@ class SpecializedClassTemplate<int>
   }
 };
 
+
+template <class T>
+class TestClass {
+public:
+   TestClass() {
+      const char* expected = "TestClass<class UnitTestNative>::TestClass";
+      if (strcmp(expected,__FUNCTION__)==0)
+        printf("PASSED\n");
+      else
+        printf("FAILED %s\n",__FUNCTION__);
+   }
+};
+
+class UnitTestNative {};
+
 int main() {
   ClassInAnonymousNamespace anonymousNamespace;
   anonymousNamespace.anonymousNamespaceFunction();
@@ -535,6 +553,7 @@ int main() {
   SpecializedClassTemplate<char> sct2;
   sct2.memberFunctionTemplate('0', 0.0);
 
+  TestClass<UnitTestNative> t;
   return 0;
 }
 
diff --git a/clang/test/SemaCXX/source_location.cpp b/clang/test/SemaCXX/source_location.cpp
index e92fb35b653a8f3..d4d4c8fa650e1af 100644
--- a/clang/test/SemaCXX/source_location.cpp
+++ b/clang/test/SemaCXX/source_location.cpp
@@ -649,8 +649,16 @@ constexpr bool test_in_func() {
   static_assert(is_equal(b.a.f, "test_func_passed.cpp"));
   static_assert(is_equal(b.a.f2, "test_func_passed.cpp"));
   static_assert(is_equal(b.a.info.file(), "test_func_passed.cpp"));
+#ifdef MS
+  static_assert(is_equal(b.a.func, "test_out_of_line_init::test_in_func"));
+#else
   static_assert(is_equal(b.a.func, "test_in_func"));
+#endif
+#ifdef MS
+  static_assert(is_equal(b.a.func, "test_out_of_line_init::test_in_func"));
+#else
   static_assert(is_equal(b.a.func2, "test_in_func"));
+#endif
   static_assert(is_equal(b.a.info.function(), "bool test_out_of_line_init::test_in_func()"));
   return true;
 }
@@ -677,7 +685,11 @@ constexpr InInit II;
 
 static_assert(II.l == 5200, "");
 static_assert(is_equal(II.f, "in_init.cpp"));
+#ifdef MS
+static_assert(is_equal(II.func, "test_global_scope::InInit::InInit"));
+#else
 static_assert(is_equal(II.func, "InInit"));
+#endif
 
 #line 5400
 struct AggInit {

>From 1364bb8058de82f125d0ca1c4ddcd8712c225162 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Thu, 21 Sep 2023 08:40:21 -0700
Subject: [PATCH 4/4] Addressed review comments and fixed some LIT tests.

---
 clang/include/clang/AST/PrettyPrinter.h       |  6 ++++-
 clang/lib/AST/Expr.cpp                        |  2 +-
 clang/lib/AST/TypePrinter.cpp                 |  2 +-
 clang/test/AST/Interp/literals.cpp            | 10 ++++-----
 clang/test/Analysis/eval-predefined-exprs.cpp | 22 ++++++++++++++-----
 5 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h
index cee3cce7729c30f..2bfe51185a38d29 100644
--- a/clang/include/clang/AST/PrettyPrinter.h
+++ b/clang/include/clang/AST/PrettyPrinter.h
@@ -72,7 +72,7 @@ struct PrintingPolicy {
         SplitTemplateClosers(!LO.CPlusPlus11), TerseOutput(false),
         PolishForDeclaration(false), Half(LO.Half),
         MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true),
-        MSVCFormatting(false), ConstantsAsWritten(false),
+        MSVCFormatting(false), IncludeKeyword(false), ConstantsAsWritten(false),
         SuppressImplicitBase(false), FullyQualifiedName(false),
         PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true),
         UsePreferredNames(true), AlwaysIncludeTypeForTemplateArgument(false),
@@ -250,6 +250,10 @@ struct PrintingPolicy {
   /// after template arguments.
   unsigned MSVCFormatting : 1;
 
+  // Prints "class" keyword. This is used when printing a function via the
+  // _FUNCTION__ or __FUNC__ macro in MSVC mode.
+  unsigned IncludeKeyword : 1;
+
   /// Whether we should print the constant expressions as written in the
   /// sources.
   ///
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 4d258c92dda3012..c25d3ba894a8878 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -804,7 +804,7 @@ std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) {
     PrintingPolicy Policy(LO);
     PrettyCallbacks PrettyCB(LO);
     Policy.Callbacks = &PrettyCB;
-    Policy.MSVCFormatting = LO.MicrosoftExt;
+    Policy.IncludeKeyword = LO.MicrosoftExt;
     std::string Proto;
     llvm::raw_string_ostream POut(Proto);
 
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 589c4e03e329e7e..acf844948c4207b 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2218,7 +2218,7 @@ printTo(raw_ostream &OS, ArrayRef<TA> Args, const PrintingPolicy &Policy,
     } else {
       if (!FirstArg)
         OS << Comma;
-      if (Policy.MSVCFormatting && Argument.getKind() == TemplateArgument::Type)
+      if (Policy.IncludeKeyword && Argument.getKind() == TemplateArgument::Type)
         OS << "class ";
 
       // Tries to print the argument with location info if exists.
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index ceda59405ea9105..aabc909b3328e48 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -1046,8 +1046,8 @@ namespace PredefinedExprs {
     static_assert(strings_match(__FUNCSIG__, "void __cdecl PredefinedExprs::foo(void)"), "");
     static_assert(strings_match(L__FUNCSIG__, L"void __cdecl PredefinedExprs::foo(void)"), "");
     static_assert(strings_match(L__FUNCTION__, L"foo"), "");
-    static_assert(strings_match(__FUNCTION__, "foo"), "");
-    static_assert(strings_match(__func__, "foo"), "");
+    static_assert(strings_match(__FUNCTION__, "PredefinedExprs::foo"), "");
+    static_assert(strings_match(__func__, "PredefinedExprs::foo"), "");
     static_assert(strings_match(__PRETTY_FUNCTION__, "void PredefinedExprs::foo()"), "");
   }
 
@@ -1058,9 +1058,9 @@ namespace PredefinedExprs {
                                 // expected-warning {{result unused}}
     return __FUNCTION__[index];
   }
-  static_assert(heh(0) == 'h', "");
-  static_assert(heh(1) == 'e', "");
-  static_assert(heh(2) == 'h', "");
+  static_assert(heh(0) == 'P', "");
+  static_assert(heh(1) == 'r', "");
+  static_assert(heh(2) == 'e', "");
 #endif
 }
 
diff --git a/clang/test/Analysis/eval-predefined-exprs.cpp b/clang/test/Analysis/eval-predefined-exprs.cpp
index 1eec4476a065f31..7be441eb5bad943 100644
--- a/clang/test/Analysis/eval-predefined-exprs.cpp
+++ b/clang/test/Analysis/eval-predefined-exprs.cpp
@@ -55,9 +55,14 @@ struct A {
     clang_analyzer_dump(__func__);
     clang_analyzer_dump(__FUNCTION__);
     clang_analyzer_dump(__PRETTY_FUNCTION__);
-    // expected-warning at -3 {{&Element{"A",0 S64b,char}}}
-    // expected-warning at -3 {{&Element{"A",0 S64b,char}}}
-    // expected-warning at -3 {{&Element{"A::A()",0 S64b,char}}}
+#ifdef ANALYZER_MS
+    // expected-warning at -4 {{&Element{"A::A",0 S64b,char}}}
+    // expected-warning at -4 {{&Element{"A::A",0 S64b,char}}}
+#else
+    // expected-warning at -7 {{&Element{"A",0 S64b,char}}}
+    // expected-warning at -7 {{&Element{"A",0 S64b,char}}}
+#endif
+    // expected-warning at -8 {{&Element{"A::A()",0 S64b,char}}}
 
 #ifdef ANALYZER_MS
     clang_analyzer_dump(__FUNCDNAME__);
@@ -74,9 +79,14 @@ struct A {
     clang_analyzer_dump(__func__);
     clang_analyzer_dump(__FUNCTION__);
     clang_analyzer_dump(__PRETTY_FUNCTION__);
-    // expected-warning at -3 {{&Element{"~A",0 S64b,char}}}
-    // expected-warning at -3 {{&Element{"~A",0 S64b,char}}}
-    // expected-warning at -3 {{&Element{"A::~A()",0 S64b,char}}}
+#ifdef ANALYZER_MS
+    // expected-warning at -4 {{&Element{"A::~A",0 S64b,char}}}
+    // expected-warning at -4 {{&Element{"A::~A",0 S64b,char}}}
+#else
+    // expected-warning at -7 {{&Element{"~A",0 S64b,char}}}
+    // expected-warning at -7 {{&Element{"~A",0 S64b,char}}}
+#endif
+    // expected-warning at -8 {{&Element{"A::~A()",0 S64b,char}}}
 
 #ifdef ANALYZER_MS
     clang_analyzer_dump(__FUNCDNAME__);



More information about the cfe-commits mailing list