[clang] [clang-cl] Fix value of __FUNCTION__ in MSVC mode. (PR #84014)

Zahira Ammarguellat via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 14 06:15:59 PDT 2024


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

>From bdefe754c14c5e050ebf2b9c82eca458041564a4 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Tue, 5 Mar 2024 05:35:16 -0800
Subject: [PATCH 1/6] [clang-cl] Fix value of __FUNCTION__ in MSVC mode.

---
 clang/docs/ReleaseNotes.rst                   |  3 +
 clang/include/clang/AST/Expr.h                |  3 +-
 clang/lib/AST/Expr.cpp                        | 26 ++++++--
 clang/lib/AST/TypePrinter.cpp                 | 24 +++++--
 clang/lib/Sema/SemaExpr.cpp                   |  5 +-
 clang/test/AST/Interp/literals.cpp            |  8 +--
 clang/test/Analysis/eval-predefined-exprs.cpp | 22 +++++--
 clang/test/SemaCXX/source_location.cpp        | 64 +++++++++++++++++++
 clang/unittests/AST/DeclPrinterTest.cpp       | 15 +++++
 9 files changed, 149 insertions(+), 21 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 612b4329727455..20c14fae1dd31b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -224,6 +224,9 @@ Bug Fixes in This Version
   for variables created through copy initialization having side-effects in C++17 and later.
   Fixes (#GH64356) (#GH79518).
 
+- Fix value of predefined macro ``__FUNCTION__`` to match MSVC's value. Fixes
+  (`#66114 <https://github.com/llvm/llvm-project/issues/66114>`_).
+
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index bf0622bdeca30e..ce8e64a4bed04b 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -2034,7 +2034,8 @@ class PredefinedExpr final
   }
 
   static std::string ComputeName(PredefinedIdentKind IK,
-                                 const Decl *CurrentDecl);
+                                 const Decl *CurrentDecl,
+                                 bool ForceElaboratedPrinting = false);
 
   SourceLocation getBeginLoc() const { return getLocation(); }
   SourceLocation getEndLoc() const { return getLocation(); }
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index b4de2155adcebd..796e50817ee319 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -673,7 +673,8 @@ StringRef PredefinedExpr::getIdentKindName(PredefinedIdentKind IK) {
 // FIXME: Maybe this should use DeclPrinter with a special "print predefined
 // expr" policy instead.
 std::string PredefinedExpr::ComputeName(PredefinedIdentKind IK,
-                                        const Decl *CurrentDecl) {
+                                        const Decl *CurrentDecl,
+                                        bool ForceElaboratedPrinting) {
   ASTContext &Context = CurrentDecl->getASTContext();
 
   if (IK == PredefinedIdentKind::FuncDName) {
@@ -721,10 +722,17 @@ std::string PredefinedExpr::ComputeName(PredefinedIdentKind IK,
     return std::string(Out.str());
   }
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
-    if (IK != PredefinedIdentKind::PrettyFunction &&
-        IK != PredefinedIdentKind::PrettyFunctionNoVirtual &&
-        IK != PredefinedIdentKind::FuncSig &&
-        IK != PredefinedIdentKind::LFuncSig)
+    const auto &LO = Context.getLangOpts();
+    if ((ForceElaboratedPrinting &&
+         (((IK == PredefinedIdentKind::Func ||
+            IK == PredefinedIdentKind ::Function) &&
+           !LO.MicrosoftExt) ||
+          (IK == PredefinedIdentKind::LFunction && LO.MicrosoftExt))) ||
+        (!ForceElaboratedPrinting &&
+         (IK != PredefinedIdentKind::PrettyFunction &&
+          IK != PredefinedIdentKind::PrettyFunctionNoVirtual &&
+          IK != PredefinedIdentKind::FuncSig &&
+          IK != PredefinedIdentKind::LFuncSig)))
       return FD->getNameAsString();
 
     SmallString<256> Name;
@@ -752,6 +760,8 @@ std::string PredefinedExpr::ComputeName(PredefinedIdentKind IK,
     PrintingPolicy Policy(Context.getLangOpts());
     PrettyCallbacks PrettyCB(Context.getLangOpts());
     Policy.Callbacks = &PrettyCB;
+    if (IK == PredefinedIdentKind::Function && ForceElaboratedPrinting)
+      Policy.SuppressTagKeyword = !LO.MicrosoftExt;
     std::string Proto;
     llvm::raw_string_ostream POut(Proto);
 
@@ -779,6 +789,12 @@ std::string PredefinedExpr::ComputeName(PredefinedIdentKind IK,
 
     FD->printQualifiedName(POut, Policy);
 
+    if (IK == PredefinedIdentKind::Function) {
+      POut.flush();
+      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 7dcc4348f8e036..21605e1f53e3d9 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1635,6 +1635,17 @@ void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
     if (T->getKeyword() != ElaboratedTypeKeyword::None)
       OS << " ";
     NestedNameSpecifier *Qualifier = T->getQualifier();
+    if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
+        !Policy.SuppressUnwrittenScope) {
+      std::string prefix = T->isClassType()       ? "class "
+                           : T->isStructureType() ? "struct "
+                           : T->isUnionType()     ? "union "
+                                                  : "";
+      OS << prefix;
+      Policy.SuppressTagKeyword = true;
+      Policy.SuppressScope = false;
+      return printBefore(T->getNamedType(), OS);
+    }
     if (Qualifier)
       Qualifier->print(OS, Policy);
   }
@@ -2260,10 +2271,15 @@ printTo(raw_ostream &OS, ArrayRef<TA> Args, const PrintingPolicy &Policy,
     } else {
       if (!FirstArg)
         OS << Comma;
-      // Tries to print the argument with location info if exists.
-      printArgument(Arg, Policy, ArgOS,
-                    TemplateParameterList::shouldIncludeTypeForArgument(
-                        Policy, TPL, ParmIndex));
+      if (!Policy.SuppressTagKeyword &&
+          Argument.getKind() == TemplateArgument::Type &&
+          isa<TagType>(Argument.getAsType()))
+        OS << Argument.getAsType().getAsString().data();
+      else
+        // Tries to print the argument with location info if exists.
+        printArgument(Arg, Policy, ArgOS,
+                      TemplateParameterList::shouldIncludeTypeForArgument(
+                          Policy, TPL, ParmIndex));
     }
     StringRef ArgString = ArgOS.str();
 
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 0a449fc1082bd4..fa0daa8ab0491b 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3741,7 +3741,10 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
   else {
     // Pre-defined identifiers are of type char[x], where x is the length of
     // the string.
-    auto Str = PredefinedExpr::ComputeName(IK, currentDecl);
+    bool ForceElaboratedPrinting =
+        IK == PredefinedIdentKind::Function && getLangOpts().MicrosoftExt;
+    auto Str =
+        PredefinedExpr::ComputeName(IK, currentDecl, ForceElaboratedPrinting);
     unsigned Length = Str.length();
 
     llvm::APInt LengthI(32, Length + 1);
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index d86609108ca446..b2f3f2cf7e336f 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -1039,7 +1039,7 @@ 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(__FUNCTION__, "PredefinedExprs::foo"), "");
     static_assert(strings_match(__func__, "foo"), "");
     static_assert(strings_match(__PRETTY_FUNCTION__, "void PredefinedExprs::foo()"), "");
   }
@@ -1049,9 +1049,9 @@ namespace PredefinedExprs {
     __extension__ __FUNCTION__; // both-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 1eec4476a065f3..a6bac5ee9d486d 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",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",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__);
diff --git a/clang/test/SemaCXX/source_location.cpp b/clang/test/SemaCXX/source_location.cpp
index 7414fbce7828d1..203925cf49e936 100644
--- a/clang/test/SemaCXX/source_location.cpp
+++ b/clang/test/SemaCXX/source_location.cpp
@@ -463,8 +463,72 @@ void ctor_tests() {
 constexpr SL global_sl = SL::current();
 static_assert(is_equal(global_sl.function(), ""));
 
+template <class T>
+class TestBI {
+public:
+   TestBI() {
+#ifdef MS
+     static_assert(is_equal(__FUNCTION__, "test_func::TestBI<int>::TestBI"));
+     static_assert(is_equal(__func__, "TestBI"));
+#else
+     static_assert(is_equal(__FUNCTION__, "TestBI"));
+     static_assert(is_equal(__func__, "TestBI"));
+#endif
+   }
+};
+
+template <class T>
+class TestClass {
+public:
+   TestClass() {
+#ifdef MS
+      static_assert(is_equal(__FUNCTION__, "test_func::TestClass<class test_func::C>::TestClass"));
+      static_assert(is_equal(__func__, "TestClass"));
+#else
+      static_assert(is_equal(__FUNCTION__, "TestClass"));
+      static_assert(is_equal(__func__, "TestClass"));
+#endif
+   }
+};
+
+template <class T>
+class TestStruct {
+public:
+   TestStruct() {
+#ifdef MS
+      static_assert(is_equal(__FUNCTION__, "test_func::TestStruct<struct test_func::S>::TestStruct"));
+      static_assert(is_equal(__func__, "TestStruct"));
+#else
+      static_assert(is_equal(__FUNCTION__, "TestStruct"));
+      static_assert(is_equal(__func__, "TestStruct"));
+#endif
+   }
+};
+
+template <class T>
+class TestEnum {
+public:
+   TestEnum() {
+#ifdef MS
+      static_assert(is_equal(__FUNCTION__, "test_func::TestEnum<enum test_func::E>::TestEnum"));
+      static_assert(is_equal(__func__, "TestEnum"));
+#else
+      static_assert(is_equal(__FUNCTION__, "TestEnum"));
+      static_assert(is_equal(__func__, "TestEnum"));
+#endif
+   }
+};
+
+class C {};
+struct S {};
+enum E {};
 } // namespace test_func
 
+test_func::TestBI<int> t1;
+test_func::TestClass<test_func::C> t2;
+test_func::TestStruct<test_func::S> t3;
+test_func::TestEnum<test_func::E> t4;
+
 //===----------------------------------------------------------------------===//
 //                            __builtin_FUNCSIG()
 //===----------------------------------------------------------------------===//
diff --git a/clang/unittests/AST/DeclPrinterTest.cpp b/clang/unittests/AST/DeclPrinterTest.cpp
index 0e09ab2a7bba88..8fcfaa7c2f0379 100644
--- a/clang/unittests/AST/DeclPrinterTest.cpp
+++ b/clang/unittests/AST/DeclPrinterTest.cpp
@@ -358,6 +358,21 @@ TEST(DeclPrinter, TestCXXRecordDecl11) {
     "class A : virtual public Z, private Y {}"));
 }
 
+TEST(DeclPrinter, TestCXXRecordDecl12) {
+  ASSERT_TRUE(PrintedDeclCXX98Matches(
+      "struct S { int x; };"
+      "namespace NS { class C {};}"
+      "S foo(S s1, NS::C c1) {using namespace NS; C c; return s1;}",
+      "foo",
+      "struct S foo(struct S s1, class NS::C c1) {\nusing namespace NS;\nclass "
+      "NS::C c;\nreturn s1;\n}\n",
+      [](PrintingPolicy &Policy) {
+        Policy.SuppressTagKeyword = false;
+        Policy.SuppressScope = true;
+        Policy.TerseOutput = false;
+      }));
+}
+
 TEST(DeclPrinter, TestFunctionDecl1) {
   ASSERT_TRUE(PrintedDeclCXX98Matches(
     "void A();",

>From 13f46938be7deaf0ae0409e374694b61e2ffe86d Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Tue, 5 Mar 2024 14:18:39 -0800
Subject: [PATCH 2/6] Addressed review comments.

---
 clang/lib/AST/Expr.cpp                        | 24 ++++++++------
 clang/lib/AST/TypePrinter.cpp                 | 10 +++---
 clang/lib/Sema/SemaExpr.cpp                   |  2 +-
 clang/test/AST/Interp/literals.cpp            |  8 ++---
 clang/test/Analysis/eval-predefined-exprs.cpp | 32 +++++++++----------
 clang/test/SemaCXX/source_location.cpp        | 30 ++++++++---------
 6 files changed, 54 insertions(+), 52 deletions(-)

diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 796e50817ee319..c2524b2df0fe2a 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -723,16 +723,20 @@ std::string PredefinedExpr::ComputeName(PredefinedIdentKind IK,
   }
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
     const auto &LO = Context.getLangOpts();
+    bool isFuncOrFunctionInNonMSVCCompatEnv =
+        ((IK == PredefinedIdentKind::Func ||
+          IK == PredefinedIdentKind ::Function) &&
+         !LO.MSVCCompat);
+    bool isLFunctionInMSVCCommpatEnv =
+        IK == PredefinedIdentKind::LFunction && LO.MSVCCompat;
+    bool isFuncOrFunctionOrLFunctionOrFuncDName =
+        IK != PredefinedIdentKind::PrettyFunction &&
+        IK != PredefinedIdentKind::PrettyFunctionNoVirtual &&
+        IK != PredefinedIdentKind::FuncSig &&
+        IK != PredefinedIdentKind::LFuncSig;
     if ((ForceElaboratedPrinting &&
-         (((IK == PredefinedIdentKind::Func ||
-            IK == PredefinedIdentKind ::Function) &&
-           !LO.MicrosoftExt) ||
-          (IK == PredefinedIdentKind::LFunction && LO.MicrosoftExt))) ||
-        (!ForceElaboratedPrinting &&
-         (IK != PredefinedIdentKind::PrettyFunction &&
-          IK != PredefinedIdentKind::PrettyFunctionNoVirtual &&
-          IK != PredefinedIdentKind::FuncSig &&
-          IK != PredefinedIdentKind::LFuncSig)))
+         (isFuncOrFunctionInNonMSVCCompatEnv || isLFunctionInMSVCCommpatEnv)) ||
+        !ForceElaboratedPrinting && isFuncOrFunctionOrLFunctionOrFuncDName)
       return FD->getNameAsString();
 
     SmallString<256> Name;
@@ -761,7 +765,7 @@ std::string PredefinedExpr::ComputeName(PredefinedIdentKind IK,
     PrettyCallbacks PrettyCB(Context.getLangOpts());
     Policy.Callbacks = &PrettyCB;
     if (IK == PredefinedIdentKind::Function && ForceElaboratedPrinting)
-      Policy.SuppressTagKeyword = !LO.MicrosoftExt;
+      Policy.SuppressTagKeyword = !LO.MSVCCompat;
     std::string Proto;
     llvm::raw_string_ostream POut(Proto);
 
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 21605e1f53e3d9..6de90638d916cf 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1637,10 +1637,10 @@ void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
     NestedNameSpecifier *Qualifier = T->getQualifier();
     if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
         !Policy.SuppressUnwrittenScope) {
-      std::string prefix = T->isClassType()       ? "class "
-                           : T->isStructureType() ? "struct "
-                           : T->isUnionType()     ? "union "
-                                                  : "";
+      StringRef prefix = T->isClassType()       ? "class "
+                         : T->isStructureType() ? "struct "
+                         : T->isUnionType()     ? "union "
+                                                : "";
       OS << prefix;
       Policy.SuppressTagKeyword = true;
       Policy.SuppressScope = false;
@@ -2274,7 +2274,7 @@ printTo(raw_ostream &OS, ArrayRef<TA> Args, const PrintingPolicy &Policy,
       if (!Policy.SuppressTagKeyword &&
           Argument.getKind() == TemplateArgument::Type &&
           isa<TagType>(Argument.getAsType()))
-        OS << Argument.getAsType().getAsString().data();
+        OS << Argument.getAsType().getAsString();
       else
         // Tries to print the argument with location info if exists.
         printArgument(Arg, Policy, ArgOS,
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index fa0daa8ab0491b..c80f1dd810e732 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3742,7 +3742,7 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
     // Pre-defined identifiers are of type char[x], where x is the length of
     // the string.
     bool ForceElaboratedPrinting =
-        IK == PredefinedIdentKind::Function && getLangOpts().MicrosoftExt;
+        IK == PredefinedIdentKind::Function && getLangOpts().MSVCCompat;
     auto Str =
         PredefinedExpr::ComputeName(IK, currentDecl, ForceElaboratedPrinting);
     unsigned Length = Str.length();
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index b2f3f2cf7e336f..d86609108ca446 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -1039,7 +1039,7 @@ 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__, "PredefinedExprs::foo"), "");
+    static_assert(strings_match(__FUNCTION__, "foo"), "");
     static_assert(strings_match(__func__, "foo"), "");
     static_assert(strings_match(__PRETTY_FUNCTION__, "void PredefinedExprs::foo()"), "");
   }
@@ -1049,9 +1049,9 @@ namespace PredefinedExprs {
     __extension__ __FUNCTION__; // both-warning {{result unused}}
     return __FUNCTION__[index];
   }
-  static_assert(heh(0) == 'P', "");
-  static_assert(heh(1) == 'r', "");
-  static_assert(heh(2) == 'e', "");
+  static_assert(heh(0) == 'h', "");
+  static_assert(heh(1) == 'e', "");
+  static_assert(heh(2) == 'h', "");
 #endif
 }
 
diff --git a/clang/test/Analysis/eval-predefined-exprs.cpp b/clang/test/Analysis/eval-predefined-exprs.cpp
index a6bac5ee9d486d..1a407597eb96b7 100644
--- a/clang/test/Analysis/eval-predefined-exprs.cpp
+++ b/clang/test/Analysis/eval-predefined-exprs.cpp
@@ -52,17 +52,17 @@ void foo() {
 
 struct A {
   A() {
-    clang_analyzer_dump(__func__);
-    clang_analyzer_dump(__FUNCTION__);
-    clang_analyzer_dump(__PRETTY_FUNCTION__);
 #ifdef ANALYZER_MS
-    // expected-warning at -4 {{&Element{"A",0 S64b,char}}}
-    // expected-warning at -4 {{&Element{"A::A",0 S64b,char}}}
+    clang_analyzer_dump(__func__);     // expected-warning {{&Element{"A",0 S64b,char}}}
 #else
-    // expected-warning at -7 {{&Element{"A",0 S64b,char}}}
-    // expected-warning at -7 {{&Element{"A",0 S64b,char}}}
+        clang_analyzer_dump(__func__); // expected-warning {{&Element{"A",0 S64b,char}}}
 #endif
-    // expected-warning at -8 {{&Element{"A::A()",0 S64b,char}}}
+#ifdef ANALYZER_MS
+    clang_analyzer_dump(__FUNCTION__); // expected-warning {{&Element{"A::A",0 S64b,char}}}
+#else
+    clang_analyzer_dump(__FUNCTION__); // expected-warning {{&Element{"A",0 S64b,char}}}
+#endif
+    clang_analyzer_dump(__PRETTY_FUNCTION__);  // expected-warning {{&Element{"A::A()",0 S64b,char}}}
 
 #ifdef ANALYZER_MS
     clang_analyzer_dump(__FUNCDNAME__);
@@ -76,17 +76,17 @@ struct A {
 #endif
   }
   ~A() {
-    clang_analyzer_dump(__func__);
-    clang_analyzer_dump(__FUNCTION__);
-    clang_analyzer_dump(__PRETTY_FUNCTION__);
 #ifdef ANALYZER_MS
-    // expected-warning at -4 {{&Element{"~A",0 S64b,char}}}
-    // expected-warning at -4 {{&Element{"A::~A",0 S64b,char}}}
+    clang_analyzer_dump(__func__);          // expected-warning {{&Element{"~A",0 S64b,char}}}
+#else
+    clang_analyzer_dump(__func__);          // expected-warning {{&Element{"~A",0 S64b,char}}}
+#endif
+#ifdef ANALYZER_MS
+    clang_analyzer_dump(__FUNCTION__);      // expected-warning {{&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}}}
+    clang_analyzer_dump(__FUNCTION__);      // expected-warning {{&Element{"~A",0 S64b,char}}}
 #endif
-    // expected-warning at -8 {{&Element{"A::~A()",0 S64b,char}}}
+    clang_analyzer_dump(__PRETTY_FUNCTION__); // expected-warning {{&Element{"A::~A()",0 S64b,char}}}
 
 #ifdef ANALYZER_MS
     clang_analyzer_dump(__FUNCDNAME__);
diff --git a/clang/test/SemaCXX/source_location.cpp b/clang/test/SemaCXX/source_location.cpp
index 203925cf49e936..d6c377bcd4d31f 100644
--- a/clang/test/SemaCXX/source_location.cpp
+++ b/clang/test/SemaCXX/source_location.cpp
@@ -1,14 +1,14 @@
 // RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -verify %s
 // RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -DUSE_CONSTEVAL -fexceptions -verify %s
 // RUN: %clang_cc1 -std=c++2b -fcxx-exceptions -DUSE_CONSTEVAL -DPAREN_INIT -fexceptions -verify %s
-// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fms-extensions -DMS -fexceptions -verify %s
-// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS -DUSE_CONSTEVAL -fexceptions -verify %s
+// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fms-extensions -DMS -fexceptions -fms-compatibility -verify %s
+// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS -DUSE_CONSTEVAL -fexceptions -fms-compatibility -verify %s
 //
 // RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
 // RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -DUSE_CONSTEVAL -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
 // RUN: %clang_cc1 -std=c++2b -fcxx-exceptions -DUSE_CONSTEVAL -DPAREN_INIT -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
-// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fms-extensions -DMS -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
-// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS -DUSE_CONSTEVAL -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
+// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fms-extensions -DMS -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -fms-compatibility -verify %s
+// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS -DUSE_CONSTEVAL -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify -fms-compatibility %s
 // expected-no-diagnostics
 
 #define assert(...) ((__VA_ARGS__) ? ((void)0) : throw 42)
@@ -469,11 +469,10 @@ class TestBI {
    TestBI() {
 #ifdef MS
      static_assert(is_equal(__FUNCTION__, "test_func::TestBI<int>::TestBI"));
-     static_assert(is_equal(__func__, "TestBI"));
 #else
      static_assert(is_equal(__FUNCTION__, "TestBI"));
-     static_assert(is_equal(__func__, "TestBI"));
 #endif
+     static_assert(is_equal(__func__, "TestBI"));
    }
 };
 
@@ -483,11 +482,10 @@ class TestClass {
    TestClass() {
 #ifdef MS
       static_assert(is_equal(__FUNCTION__, "test_func::TestClass<class test_func::C>::TestClass"));
-      static_assert(is_equal(__func__, "TestClass"));
 #else
       static_assert(is_equal(__FUNCTION__, "TestClass"));
-      static_assert(is_equal(__func__, "TestClass"));
 #endif
+      static_assert(is_equal(__func__, "TestClass"));
    }
 };
 
@@ -497,11 +495,10 @@ class TestStruct {
    TestStruct() {
 #ifdef MS
       static_assert(is_equal(__FUNCTION__, "test_func::TestStruct<struct test_func::S>::TestStruct"));
-      static_assert(is_equal(__func__, "TestStruct"));
 #else
       static_assert(is_equal(__FUNCTION__, "TestStruct"));
-      static_assert(is_equal(__func__, "TestStruct"));
 #endif
+      static_assert(is_equal(__func__, "TestStruct"));
    }
 };
 
@@ -511,23 +508,24 @@ class TestEnum {
    TestEnum() {
 #ifdef MS
       static_assert(is_equal(__FUNCTION__, "test_func::TestEnum<enum test_func::E>::TestEnum"));
-      static_assert(is_equal(__func__, "TestEnum"));
 #else
       static_assert(is_equal(__FUNCTION__, "TestEnum"));
-      static_assert(is_equal(__func__, "TestEnum"));
 #endif
+      static_assert(is_equal(__func__, "TestEnum"));
    }
 };
 
 class C {};
 struct S {};
 enum E {};
+
+TestBI<int> t1;
+TestClass<test_func::C> t2;
+TestStruct<test_func::S> t3;
+TestEnum<test_func::E> t4;
+
 } // namespace test_func
 
-test_func::TestBI<int> t1;
-test_func::TestClass<test_func::C> t2;
-test_func::TestStruct<test_func::S> t3;
-test_func::TestEnum<test_func::E> t4;
 
 //===----------------------------------------------------------------------===//
 //                            __builtin_FUNCSIG()

>From 5eeffd1762e2cba336753ee2fedfce1620356bf2 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 6 Mar 2024 04:41:05 -0800
Subject: [PATCH 3/6] Addressed review comments.

---
 clang/docs/ReleaseNotes.rst                   | 4 ++--
 clang/test/Analysis/eval-predefined-exprs.cpp | 8 --------
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 20c14fae1dd31b..db5f7aa39388e7 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -224,8 +224,8 @@ Bug Fixes in This Version
   for variables created through copy initialization having side-effects in C++17 and later.
   Fixes (#GH64356) (#GH79518).
 
-- Fix value of predefined macro ``__FUNCTION__`` to match MSVC's value. Fixes
-  (`#66114 <https://github.com/llvm/llvm-project/issues/66114>`_).
+- Fix value of predefined macro ``__FUNCTION__`` in MSVC compatibility mode.
+  Fixes (GH#66114).
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/test/Analysis/eval-predefined-exprs.cpp b/clang/test/Analysis/eval-predefined-exprs.cpp
index 1a407597eb96b7..b26091869cd03f 100644
--- a/clang/test/Analysis/eval-predefined-exprs.cpp
+++ b/clang/test/Analysis/eval-predefined-exprs.cpp
@@ -52,11 +52,7 @@ void foo() {
 
 struct A {
   A() {
-#ifdef ANALYZER_MS
     clang_analyzer_dump(__func__);     // expected-warning {{&Element{"A",0 S64b,char}}}
-#else
-        clang_analyzer_dump(__func__); // expected-warning {{&Element{"A",0 S64b,char}}}
-#endif
 #ifdef ANALYZER_MS
     clang_analyzer_dump(__FUNCTION__); // expected-warning {{&Element{"A::A",0 S64b,char}}}
 #else
@@ -76,11 +72,7 @@ struct A {
 #endif
   }
   ~A() {
-#ifdef ANALYZER_MS
     clang_analyzer_dump(__func__);          // expected-warning {{&Element{"~A",0 S64b,char}}}
-#else
-    clang_analyzer_dump(__func__);          // expected-warning {{&Element{"~A",0 S64b,char}}}
-#endif
 #ifdef ANALYZER_MS
     clang_analyzer_dump(__FUNCTION__);      // expected-warning {{&Element{"A::~A",0 S64b,char}}}
 #else

>From 16d3c751336a9d4127793cd02a5de838baa3859c Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 6 Mar 2024 05:13:32 -0800
Subject: [PATCH 4/6] Fixed typo.

---
 clang/docs/ReleaseNotes.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index db5f7aa39388e7..0399d5ab6b16a4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -225,7 +225,7 @@ Bug Fixes in This Version
   Fixes (#GH64356) (#GH79518).
 
 - Fix value of predefined macro ``__FUNCTION__`` in MSVC compatibility mode.
-  Fixes (GH#66114).
+  Fixes (#GH66114).
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

>From 463cbc9d24c3ec5e020802603c97d32d5b1246cc Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 6 Mar 2024 06:32:33 -0800
Subject: [PATCH 5/6] Addressed review comment.

---
 clang/lib/AST/Expr.cpp        | 10 +++++-----
 clang/lib/AST/TypePrinter.cpp |  6 ++++++
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index c2524b2df0fe2a..39fcad88a9a6a7 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -723,20 +723,20 @@ std::string PredefinedExpr::ComputeName(PredefinedIdentKind IK,
   }
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
     const auto &LO = Context.getLangOpts();
-    bool isFuncOrFunctionInNonMSVCCompatEnv =
+    bool IsFuncOrFunctionInNonMSVCCompatEnv =
         ((IK == PredefinedIdentKind::Func ||
           IK == PredefinedIdentKind ::Function) &&
          !LO.MSVCCompat);
-    bool isLFunctionInMSVCCommpatEnv =
+    bool IsLFunctionInMSVCCommpatEnv =
         IK == PredefinedIdentKind::LFunction && LO.MSVCCompat;
-    bool isFuncOrFunctionOrLFunctionOrFuncDName =
+    bool IsFuncOrFunctionOrLFunctionOrFuncDName =
         IK != PredefinedIdentKind::PrettyFunction &&
         IK != PredefinedIdentKind::PrettyFunctionNoVirtual &&
         IK != PredefinedIdentKind::FuncSig &&
         IK != PredefinedIdentKind::LFuncSig;
     if ((ForceElaboratedPrinting &&
-         (isFuncOrFunctionInNonMSVCCompatEnv || isLFunctionInMSVCCommpatEnv)) ||
-        !ForceElaboratedPrinting && isFuncOrFunctionOrLFunctionOrFuncDName)
+         (IsFuncOrFunctionInNonMSVCCompatEnv || IsLFunctionInMSVCCommpatEnv)) ||
+        (!ForceElaboratedPrinting && IsFuncOrFunctionOrLFunctionOrFuncDName))
       return FD->getNameAsString();
 
     SmallString<256> Name;
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 6de90638d916cf..833bd964995780 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1628,6 +1628,7 @@ void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
     return;
   }
 
+  bool ResetPolicy = false;
   // The tag definition will take care of these.
   if (!Policy.IncludeTagDefinition)
   {
@@ -1637,6 +1638,7 @@ void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
     NestedNameSpecifier *Qualifier = T->getQualifier();
     if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
         !Policy.SuppressUnwrittenScope) {
+      ResetPolicy = true;
       StringRef prefix = T->isClassType()       ? "class "
                          : T->isStructureType() ? "struct "
                          : T->isUnionType()     ? "union "
@@ -1652,6 +1654,10 @@ void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
 
   ElaboratedTypePolicyRAII PolicyRAII(Policy);
   printBefore(T->getNamedType(), OS);
+  if (ResetPolicy) {
+    Policy.SuppressTagKeyword = false;
+    Policy.SuppressScope = true;
+  }
 }
 
 void TypePrinter::printElaboratedAfter(const ElaboratedType *T,

>From 4b42f76d5c1e5439311cc8153ef9530be2625840 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Thu, 14 Mar 2024 06:15:14 -0700
Subject: [PATCH 6/6] Refactor the code and added entry to TypePrinterTest.cpp.

---
 clang/lib/AST/DeclPrinter.cpp           | 37 ++++++++++++++++++++--
 clang/lib/AST/TypePrinter.cpp           | 14 ++-------
 clang/unittests/AST/DeclPrinterTest.cpp | 41 +++++++++++++++++++++++++
 clang/unittests/AST/TypePrinterTest.cpp | 18 +++++++++++
 4 files changed, 96 insertions(+), 14 deletions(-)

diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 43d221968ea3fb..af736fa46a165a 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -679,6 +679,19 @@ static void printExplicitSpecifier(ExplicitSpecifier ES, llvm::raw_ostream &Out,
   Out << Proto;
 }
 
+static void AddPrefix(PrintingPolicy &Policy, QualType T,
+                      llvm::raw_ostream &Out) {
+  if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
+      !Policy.SuppressUnwrittenScope) {
+    StringRef prefix;
+    prefix = T->isClassType()       ? "class "
+             : T->isStructureType() ? "struct "
+             : T->isUnionType()     ? "union "
+                                    : "";
+    Out << prefix;
+  }
+}
+
 void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
   if (!D->getDescribedFunctionTemplate() &&
       !D->isFunctionTemplateSpecialization())
@@ -855,7 +868,17 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
         Out << Proto << " -> ";
         Proto.clear();
       }
-      AFT->getReturnType().print(Out, Policy, Proto);
+      if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
+          !Policy.SuppressUnwrittenScope) {
+        AddPrefix(Policy, AFT->getReturnType(), Out);
+        bool OldTagKeyword = Policy.SuppressTagKeyword;
+        bool OldSupressScope = Policy.SuppressScope;
+        AFT->getReturnType().print(Out, Policy, Proto);
+        Policy.SuppressTagKeyword = OldTagKeyword;
+        Policy.SuppressScope = OldSupressScope;
+      } else {
+        AFT->getReturnType().print(Out, Policy, Proto);
+      }
       Proto.clear();
     }
     Out << Proto;
@@ -1022,7 +1045,17 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
              ? D->getIdentifier()->deuglifiedName()
              : D->getName();
 
-  printDeclType(T, Name);
+  if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
+      !Policy.SuppressUnwrittenScope) {
+    AddPrefix(Policy, T, Out);
+    bool OldTagKeyword = Policy.SuppressTagKeyword;
+    bool OldSupressScope = Policy.SuppressScope;
+    printDeclType(T, Name);
+    Policy.SuppressTagKeyword = OldTagKeyword;
+    Policy.SuppressScope = OldSupressScope;
+  } else {
+    printDeclType(T, Name);
+  }
 
   // Print the attributes that should be placed right before the end of the
   // decl.
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 833bd964995780..e43acc44118892 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1628,7 +1628,6 @@ void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
     return;
   }
 
-  bool ResetPolicy = false;
   // The tag definition will take care of these.
   if (!Policy.IncludeTagDefinition)
   {
@@ -1638,15 +1637,10 @@ void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
     NestedNameSpecifier *Qualifier = T->getQualifier();
     if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
         !Policy.SuppressUnwrittenScope) {
-      ResetPolicy = true;
-      StringRef prefix = T->isClassType()       ? "class "
-                         : T->isStructureType() ? "struct "
-                         : T->isUnionType()     ? "union "
-                                                : "";
-      OS << prefix;
       Policy.SuppressTagKeyword = true;
       Policy.SuppressScope = false;
-      return printBefore(T->getNamedType(), OS);
+      printBefore(T->getNamedType(), OS);
+      return;
     }
     if (Qualifier)
       Qualifier->print(OS, Policy);
@@ -1654,10 +1648,6 @@ void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
 
   ElaboratedTypePolicyRAII PolicyRAII(Policy);
   printBefore(T->getNamedType(), OS);
-  if (ResetPolicy) {
-    Policy.SuppressTagKeyword = false;
-    Policy.SuppressScope = true;
-  }
 }
 
 void TypePrinter::printElaboratedAfter(const ElaboratedType *T,
diff --git a/clang/unittests/AST/DeclPrinterTest.cpp b/clang/unittests/AST/DeclPrinterTest.cpp
index 8fcfaa7c2f0379..06829313b57ad9 100644
--- a/clang/unittests/AST/DeclPrinterTest.cpp
+++ b/clang/unittests/AST/DeclPrinterTest.cpp
@@ -359,6 +359,47 @@ TEST(DeclPrinter, TestCXXRecordDecl11) {
 }
 
 TEST(DeclPrinter, TestCXXRecordDecl12) {
+  ASSERT_TRUE(PrintedDeclCXX98Matches(
+      "struct S { int x; };"
+      "namespace NS { class C {};}"
+      "void foo() {using namespace NS; C c;}",
+      "foo",
+      "void foo() {\nusing namespace NS;\nclass "
+      "NS::C c;\n}\n",
+      [](PrintingPolicy &Policy) {
+        Policy.SuppressTagKeyword = false;
+        Policy.SuppressScope = true;
+        Policy.TerseOutput = false;
+      }));
+}
+
+TEST(DeclPrinter, TestCXXRecordDecl13) {
+  ASSERT_TRUE(PrintedDeclCXX98Matches(
+      "struct S { int x; };"
+      "S s1;"
+      "S foo() {return s1;}",
+      "foo",
+      "struct S foo() {\nreturn s1;\n}\n",
+      [](PrintingPolicy &Policy) {
+        Policy.SuppressTagKeyword = false;
+        Policy.SuppressScope = true;
+        Policy.TerseOutput = false;
+      }));
+}
+
+TEST(DeclPrinter, TestCXXRecordDecl14) {
+  ASSERT_TRUE(PrintedDeclCXX98Matches(
+      "struct S { int x; };"
+      "S foo(S s1) {return s1;}",
+      "foo",
+      "struct S foo(struct S s1) {\nreturn s1;\n}\n",
+      [](PrintingPolicy &Policy) {
+        Policy.SuppressTagKeyword = false;
+        Policy.SuppressScope = true;
+        Policy.TerseOutput = false;
+      }));
+}
+TEST(DeclPrinter, TestCXXRecordDecl15) {
   ASSERT_TRUE(PrintedDeclCXX98Matches(
       "struct S { int x; };"
       "namespace NS { class C {};}"
diff --git a/clang/unittests/AST/TypePrinterTest.cpp b/clang/unittests/AST/TypePrinterTest.cpp
index f0a6eb7e9fd8c9..2cdab5d1d36ab3 100644
--- a/clang/unittests/AST/TypePrinterTest.cpp
+++ b/clang/unittests/AST/TypePrinterTest.cpp
@@ -155,6 +155,24 @@ TEST(TypePrinter, TemplateIdWithNTTP) {
       }));
 }
 
+TEST(TypePrinter, TemplateArgumentsSubstitution) {
+     constexpr char Code[] = R"cpp(
+       template <typename Y> class X {};
+       typedef X<int> A;
+       int foo() {
+          return sizeof(A);
+       }
+  )cpp";
+  auto Matcher = typedefNameDecl(hasName("A"),
+                                 hasType(qualType().bind("id")));
+  ASSERT_TRUE(PrintedTypeMatches(
+      Code, {}, Matcher, "X<int>",
+     [](PrintingPolicy &Policy) {
+       Policy.SuppressTagKeyword = false;
+       Policy.SuppressScope = true;
+     }));
+}
+
 TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) {
   /// Tests clang::isSubstitutedDefaultArgument on TemplateArguments
   /// that are of kind TemplateArgument::Expression



More information about the cfe-commits mailing list