Skip to content

Commit 265568c

Browse files
zahiraamrnk
andauthored
[clang-cl] Fix value of __FUNCTION__ and __FUNC__ in MSVC mode for c++. (#66120)
Predefined macro FUNCTION (and __FUNC__) in clang is not returning the same string than MS for templated functions. See https://godbolt.org/z/88n1rGs3b For this test case MSVC is returning: function: TestClass<class UnitTestNative>::TestClass func: TestClass --------- Co-authored-by: Reid Kleckner <[email protected]>
1 parent e7651e6 commit 265568c

File tree

7 files changed

+80
-22
lines changed

7 files changed

+80
-22
lines changed

clang/include/clang/AST/PrettyPrinter.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ struct PrintingPolicy {
7676
SuppressImplicitBase(false), FullyQualifiedName(false),
7777
PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true),
7878
UsePreferredNames(true), AlwaysIncludeTypeForTemplateArgument(false),
79-
CleanUglifiedParameters(false), EntireContentsOfLargeArray(true),
80-
UseEnumerators(true) {}
79+
UseClassForTemplateArgument(false), CleanUglifiedParameters(false),
80+
EntireContentsOfLargeArray(true), UseEnumerators(true) {}
8181

8282
/// Adjust this printing policy for cases where it's known that we're
8383
/// printing C++ code (for instance, if AST dumping reaches a C++-only
@@ -291,6 +291,10 @@ struct PrintingPolicy {
291291
/// parameters.
292292
unsigned AlwaysIncludeTypeForTemplateArgument : 1;
293293

294+
// Prints "class" keyword before type template arguments. This is used when
295+
// printing a function via the _FUNCTION__ or __func__ macro in MSVC mode.
296+
unsigned UseClassForTemplateArgument : 1;
297+
294298
/// Whether to strip underscores when printing reserved parameter names.
295299
/// e.g. std::vector<class _Tp> becomes std::vector<class Tp>.
296300
/// This only affects parameter names, and so describes a compatible API.

clang/lib/AST/Expr.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -772,18 +772,21 @@ std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) {
772772
return std::string(Out.str());
773773
}
774774
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
775-
if (IK != PrettyFunction && IK != PrettyFunctionNoVirtual &&
776-
IK != FuncSig && IK != LFuncSig)
775+
const auto &LO = Context.getLangOpts();
776+
if (((IK == Func || IK == Function) && !LO.MicrosoftExt) ||
777+
(IK == LFunction && LO.MicrosoftExt))
777778
return FD->getNameAsString();
778779

779780
SmallString<256> Name;
780781
llvm::raw_svector_ostream Out(Name);
781782

782-
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
783-
if (MD->isVirtual() && IK != PrettyFunctionNoVirtual)
784-
Out << "virtual ";
785-
if (MD->isStatic())
786-
Out << "static ";
783+
if (IK != Function) {
784+
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
785+
if (MD->isVirtual() && IK != PrettyFunctionNoVirtual)
786+
Out << "virtual ";
787+
if (MD->isStatic())
788+
Out << "static ";
789+
}
787790
}
788791

789792
class PrettyCallbacks final : public PrintingCallbacks {
@@ -798,9 +801,10 @@ std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) {
798801
private:
799802
const LangOptions &LO;
800803
};
801-
PrintingPolicy Policy(Context.getLangOpts());
802-
PrettyCallbacks PrettyCB(Context.getLangOpts());
804+
PrintingPolicy Policy(LO);
805+
PrettyCallbacks PrettyCB(LO);
803806
Policy.Callbacks = &PrettyCB;
807+
Policy.UseClassForTemplateArgument = LO.MicrosoftExt;
804808
std::string Proto;
805809
llvm::raw_string_ostream POut(Proto);
806810

@@ -827,6 +831,11 @@ std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) {
827831

828832
FD->printQualifiedName(POut, Policy);
829833

834+
if ((IK == Function || IK == Func) && LO.MicrosoftExt) {
835+
Out << Proto;
836+
return std::string(Name);
837+
}
838+
830839
POut << "(";
831840
if (FT) {
832841
for (unsigned i = 0, e = Decl->getNumParams(); i != e; ++i) {

clang/lib/AST/TypePrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2218,6 +2218,10 @@ printTo(raw_ostream &OS, ArrayRef<TA> Args, const PrintingPolicy &Policy,
22182218
} else {
22192219
if (!FirstArg)
22202220
OS << Comma;
2221+
if (Policy.UseClassForTemplateArgument &&
2222+
Argument.getKind() == TemplateArgument::Type)
2223+
OS << "class ";
2224+
22212225
// Tries to print the argument with location info if exists.
22222226
printArgument(Arg, Policy, ArgOS,
22232227
TemplateParameterList::shouldIncludeTypeForArgument(

clang/test/AST/Interp/literals.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,8 +1046,8 @@ namespace PredefinedExprs {
10461046
static_assert(strings_match(__FUNCSIG__, "void __cdecl PredefinedExprs::foo(void)"), "");
10471047
static_assert(strings_match(L__FUNCSIG__, L"void __cdecl PredefinedExprs::foo(void)"), "");
10481048
static_assert(strings_match(L__FUNCTION__, L"foo"), "");
1049-
static_assert(strings_match(__FUNCTION__, "foo"), "");
1050-
static_assert(strings_match(__func__, "foo"), "");
1049+
static_assert(strings_match(__FUNCTION__, "PredefinedExprs::foo"), "");
1050+
static_assert(strings_match(__func__, "PredefinedExprs::foo"), "");
10511051
static_assert(strings_match(__PRETTY_FUNCTION__, "void PredefinedExprs::foo()"), "");
10521052
}
10531053

@@ -1058,9 +1058,9 @@ namespace PredefinedExprs {
10581058
// expected-warning {{result unused}}
10591059
return __FUNCTION__[index];
10601060
}
1061-
static_assert(heh(0) == 'h', "");
1062-
static_assert(heh(1) == 'e', "");
1063-
static_assert(heh(2) == 'h', "");
1061+
static_assert(heh(0) == 'P', "");
1062+
static_assert(heh(1) == 'r', "");
1063+
static_assert(heh(2) == 'e', "");
10641064
#endif
10651065
}
10661066

clang/test/Analysis/eval-predefined-exprs.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,14 @@ struct A {
5555
clang_analyzer_dump(__func__);
5656
clang_analyzer_dump(__FUNCTION__);
5757
clang_analyzer_dump(__PRETTY_FUNCTION__);
58-
// expected-warning@-3 {{&Element{"A",0 S64b,char}}}
59-
// expected-warning@-3 {{&Element{"A",0 S64b,char}}}
60-
// expected-warning@-3 {{&Element{"A::A()",0 S64b,char}}}
58+
#ifdef ANALYZER_MS
59+
// expected-warning@-4 {{&Element{"A::A",0 S64b,char}}}
60+
// expected-warning@-4 {{&Element{"A::A",0 S64b,char}}}
61+
#else
62+
// expected-warning@-7 {{&Element{"A",0 S64b,char}}}
63+
// expected-warning@-7 {{&Element{"A",0 S64b,char}}}
64+
#endif
65+
// expected-warning@-8 {{&Element{"A::A()",0 S64b,char}}}
6166

6267
#ifdef ANALYZER_MS
6368
clang_analyzer_dump(__FUNCDNAME__);
@@ -74,9 +79,14 @@ struct A {
7479
clang_analyzer_dump(__func__);
7580
clang_analyzer_dump(__FUNCTION__);
7681
clang_analyzer_dump(__PRETTY_FUNCTION__);
77-
// expected-warning@-3 {{&Element{"~A",0 S64b,char}}}
78-
// expected-warning@-3 {{&Element{"~A",0 S64b,char}}}
79-
// expected-warning@-3 {{&Element{"A::~A()",0 S64b,char}}}
82+
#ifdef ANALYZER_MS
83+
// expected-warning@-4 {{&Element{"A::~A",0 S64b,char}}}
84+
// expected-warning@-4 {{&Element{"A::~A",0 S64b,char}}}
85+
#else
86+
// expected-warning@-7 {{&Element{"~A",0 S64b,char}}}
87+
// expected-warning@-7 {{&Element{"~A",0 S64b,char}}}
88+
#endif
89+
// expected-warning@-8 {{&Element{"A::~A()",0 S64b,char}}}
8090

8191
#ifdef ANALYZER_MS
8292
clang_analyzer_dump(__FUNCDNAME__);

clang/test/CodeGenCXX/predefined-expr.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
// CHECK-DAG: private unnamed_addr constant [49 x i8] c"void functionTemplateExplicitSpecialization(int)\00"
66

77
// CHECK-DAG: private unnamed_addr constant [95 x i8] c"void SpecializedClassTemplate<char>::memberFunctionTemplate(T, U) const [T = char, U = double]\00"
8+
// CHECK-DAG: private unnamed_addr constant [43 x i8] c"TestClass<class UnitTestNative>::TestClass\00"
9+
// CHECK-DAG: private unnamed_addr constant [10 x i8] c"TestClass\00"
810
// CHECK-DAG: private unnamed_addr constant [85 x i8] c"void SpecializedClassTemplate<int>::memberFunctionTemplate(int, U) const [U = float]\00"
911
// CHECK-DAG: private unnamed_addr constant [57 x i8] c"void NonTypeTemplateParam<42>::size() const [Count = 42]\00"
1012
// 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 @@
101103

102104

103105
int printf(const char * _Format, ...);
106+
int strcmp(const char *, const char *);
104107

105108
class ClassInTopLevelNamespace {
106109
public:
@@ -455,6 +458,21 @@ class SpecializedClassTemplate<int>
455458
}
456459
};
457460

461+
462+
template <class T>
463+
class TestClass {
464+
public:
465+
TestClass() {
466+
const char* expected = "TestClass<class UnitTestNative>::TestClass";
467+
if (strcmp(expected,__FUNCTION__)==0)
468+
printf("PASSED\n");
469+
else
470+
printf("FAILED %s\n",__FUNCTION__);
471+
}
472+
};
473+
474+
class UnitTestNative {};
475+
458476
int main() {
459477
ClassInAnonymousNamespace anonymousNamespace;
460478
anonymousNamespace.anonymousNamespaceFunction();
@@ -535,6 +553,7 @@ int main() {
535553
SpecializedClassTemplate<char> sct2;
536554
sct2.memberFunctionTemplate('0', 0.0);
537555

556+
TestClass<UnitTestNative> t;
538557
return 0;
539558
}
540559

clang/test/SemaCXX/source_location.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,8 +649,16 @@ constexpr bool test_in_func() {
649649
static_assert(is_equal(b.a.f, "test_func_passed.cpp"));
650650
static_assert(is_equal(b.a.f2, "test_func_passed.cpp"));
651651
static_assert(is_equal(b.a.info.file(), "test_func_passed.cpp"));
652+
#ifdef MS
653+
static_assert(is_equal(b.a.func, "test_out_of_line_init::test_in_func"));
654+
#else
652655
static_assert(is_equal(b.a.func, "test_in_func"));
656+
#endif
657+
#ifdef MS
658+
static_assert(is_equal(b.a.func, "test_out_of_line_init::test_in_func"));
659+
#else
653660
static_assert(is_equal(b.a.func2, "test_in_func"));
661+
#endif
654662
static_assert(is_equal(b.a.info.function(), "bool test_out_of_line_init::test_in_func()"));
655663
return true;
656664
}
@@ -677,7 +685,11 @@ constexpr InInit II;
677685

678686
static_assert(II.l == 5200, "");
679687
static_assert(is_equal(II.f, "in_init.cpp"));
688+
#ifdef MS
689+
static_assert(is_equal(II.func, "test_global_scope::InInit::InInit"));
690+
#else
680691
static_assert(is_equal(II.func, "InInit"));
692+
#endif
681693

682694
#line 5400
683695
struct AggInit {

0 commit comments

Comments
 (0)