Skip to content

Commit ca74580

Browse files
zahiraamchencha3
authored andcommitted
[clang-cl] Fix value of __FUNCTION__ in MSVC mode. (llvm#84014)
Predefined macro FUNCTION in clang is not returning the same string than MS for templated functions. See https://godbolt.org/z/q3EKn5zq4 For the same test case MSVC is returning: function: TestClass::TestClass function: TestStruct::TestStruct function: TestEnum::TestEnum The initial work for this was in the reverted patch (llvm#66120). This patch solves the issues raised in the reverted patch.
1 parent cf03d3e commit ca74580

File tree

10 files changed

+222
-26
lines changed

10 files changed

+222
-26
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,9 @@ Bug Fixes in This Version
284284
for variables created through copy initialization having side-effects in C++17 and later.
285285
Fixes (#GH64356) (#GH79518).
286286

287+
- Fix value of predefined macro ``__FUNCTION__`` in MSVC compatibility mode.
288+
Fixes (#GH66114).
289+
287290
- Clang now emits errors for explicit specializations/instatiations of lambda call
288291
operator.
289292
Fixes (#GH83267).

clang/include/clang/AST/Expr.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2045,7 +2045,8 @@ class PredefinedExpr final
20452045
}
20462046

20472047
static std::string ComputeName(PredefinedIdentKind IK,
2048-
const Decl *CurrentDecl);
2048+
const Decl *CurrentDecl,
2049+
bool ForceElaboratedPrinting = false);
20492050

20502051
SourceLocation getBeginLoc() const { return getLocation(); }
20512052
SourceLocation getEndLoc() const { return getLocation(); }

clang/lib/AST/DeclPrinter.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,16 @@ static void printExplicitSpecifier(ExplicitSpecifier ES, llvm::raw_ostream &Out,
679679
Out << Proto;
680680
}
681681

682+
static void MaybePrintTagKeywordIfSupressingScopes(PrintingPolicy &Policy,
683+
QualType T,
684+
llvm::raw_ostream &Out) {
685+
StringRef prefix = T->isClassType() ? "class "
686+
: T->isStructureType() ? "struct "
687+
: T->isUnionType() ? "union "
688+
: "";
689+
Out << prefix;
690+
}
691+
682692
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
683693
if (!D->getDescribedFunctionTemplate() &&
684694
!D->isFunctionTemplateSpecialization())
@@ -855,6 +865,10 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
855865
Out << Proto << " -> ";
856866
Proto.clear();
857867
}
868+
if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
869+
!Policy.SuppressUnwrittenScope)
870+
MaybePrintTagKeywordIfSupressingScopes(Policy, AFT->getReturnType(),
871+
Out);
858872
AFT->getReturnType().print(Out, Policy, Proto);
859873
Proto.clear();
860874
}
@@ -1022,7 +1036,13 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
10221036
? D->getIdentifier()->deuglifiedName()
10231037
: D->getName();
10241038

1025-
printDeclType(T, Name);
1039+
if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
1040+
!Policy.SuppressUnwrittenScope) {
1041+
MaybePrintTagKeywordIfSupressingScopes(Policy, T, Out);
1042+
printDeclType(T, Name);
1043+
} else {
1044+
printDeclType(T, Name);
1045+
}
10261046

10271047
// Print the attributes that should be placed right before the end of the
10281048
// decl.

clang/lib/AST/Expr.cpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,8 @@ StringRef PredefinedExpr::getIdentKindName(PredefinedIdentKind IK) {
676676
// FIXME: Maybe this should use DeclPrinter with a special "print predefined
677677
// expr" policy instead.
678678
std::string PredefinedExpr::ComputeName(PredefinedIdentKind IK,
679-
const Decl *CurrentDecl) {
679+
const Decl *CurrentDecl,
680+
bool ForceElaboratedPrinting) {
680681
ASTContext &Context = CurrentDecl->getASTContext();
681682

682683
if (IK == PredefinedIdentKind::FuncDName) {
@@ -724,10 +725,21 @@ std::string PredefinedExpr::ComputeName(PredefinedIdentKind IK,
724725
return std::string(Out.str());
725726
}
726727
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
727-
if (IK != PredefinedIdentKind::PrettyFunction &&
728+
const auto &LO = Context.getLangOpts();
729+
bool IsFuncOrFunctionInNonMSVCCompatEnv =
730+
((IK == PredefinedIdentKind::Func ||
731+
IK == PredefinedIdentKind ::Function) &&
732+
!LO.MSVCCompat);
733+
bool IsLFunctionInMSVCCommpatEnv =
734+
IK == PredefinedIdentKind::LFunction && LO.MSVCCompat;
735+
bool IsFuncOrFunctionOrLFunctionOrFuncDName =
736+
IK != PredefinedIdentKind::PrettyFunction &&
728737
IK != PredefinedIdentKind::PrettyFunctionNoVirtual &&
729738
IK != PredefinedIdentKind::FuncSig &&
730-
IK != PredefinedIdentKind::LFuncSig)
739+
IK != PredefinedIdentKind::LFuncSig;
740+
if ((ForceElaboratedPrinting &&
741+
(IsFuncOrFunctionInNonMSVCCompatEnv || IsLFunctionInMSVCCommpatEnv)) ||
742+
(!ForceElaboratedPrinting && IsFuncOrFunctionOrLFunctionOrFuncDName))
731743
return FD->getNameAsString();
732744

733745
SmallString<256> Name;
@@ -755,6 +767,8 @@ std::string PredefinedExpr::ComputeName(PredefinedIdentKind IK,
755767
PrintingPolicy Policy(Context.getLangOpts());
756768
PrettyCallbacks PrettyCB(Context.getLangOpts());
757769
Policy.Callbacks = &PrettyCB;
770+
if (IK == PredefinedIdentKind::Function && ForceElaboratedPrinting)
771+
Policy.SuppressTagKeyword = !LO.MSVCCompat;
758772
std::string Proto;
759773
llvm::raw_string_ostream POut(Proto);
760774

@@ -782,6 +796,12 @@ std::string PredefinedExpr::ComputeName(PredefinedIdentKind IK,
782796

783797
FD->printQualifiedName(POut, Policy);
784798

799+
if (IK == PredefinedIdentKind::Function) {
800+
POut.flush();
801+
Out << Proto;
802+
return std::string(Name);
803+
}
804+
785805
POut << "(";
786806
if (FT) {
787807
for (unsigned i = 0, e = Decl->getNumParams(); i != e; ++i) {

clang/lib/AST/TypePrinter.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1635,6 +1635,17 @@ void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
16351635
if (T->getKeyword() != ElaboratedTypeKeyword::None)
16361636
OS << " ";
16371637
NestedNameSpecifier *Qualifier = T->getQualifier();
1638+
if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
1639+
!Policy.SuppressUnwrittenScope) {
1640+
bool OldTagKeyword = Policy.SuppressTagKeyword;
1641+
bool OldSupressScope = Policy.SuppressScope;
1642+
Policy.SuppressTagKeyword = true;
1643+
Policy.SuppressScope = false;
1644+
printBefore(T->getNamedType(), OS);
1645+
Policy.SuppressTagKeyword = OldTagKeyword;
1646+
Policy.SuppressScope = OldSupressScope;
1647+
return;
1648+
}
16381649
if (Qualifier)
16391650
Qualifier->print(OS, Policy);
16401651
}
@@ -2260,10 +2271,15 @@ printTo(raw_ostream &OS, ArrayRef<TA> Args, const PrintingPolicy &Policy,
22602271
} else {
22612272
if (!FirstArg)
22622273
OS << Comma;
2263-
// Tries to print the argument with location info if exists.
2264-
printArgument(Arg, Policy, ArgOS,
2265-
TemplateParameterList::shouldIncludeTypeForArgument(
2266-
Policy, TPL, ParmIndex));
2274+
if (!Policy.SuppressTagKeyword &&
2275+
Argument.getKind() == TemplateArgument::Type &&
2276+
isa<TagType>(Argument.getAsType()))
2277+
OS << Argument.getAsType().getAsString();
2278+
else
2279+
// Tries to print the argument with location info if exists.
2280+
printArgument(Arg, Policy, ArgOS,
2281+
TemplateParameterList::shouldIncludeTypeForArgument(
2282+
Policy, TPL, ParmIndex));
22672283
}
22682284
StringRef ArgString = ArgOS.str();
22692285

clang/lib/Sema/SemaExpr.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3740,7 +3740,10 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
37403740
else {
37413741
// Pre-defined identifiers are of type char[x], where x is the length of
37423742
// the string.
3743-
auto Str = PredefinedExpr::ComputeName(IK, currentDecl);
3743+
bool ForceElaboratedPrinting =
3744+
IK == PredefinedIdentKind::Function && getLangOpts().MSVCCompat;
3745+
auto Str =
3746+
PredefinedExpr::ComputeName(IK, currentDecl, ForceElaboratedPrinting);
37443747
unsigned Length = Str.length();
37453748

37463749
llvm::APInt LengthI(32, Length + 1);

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

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,13 @@ void foo() {
5252

5353
struct A {
5454
A() {
55-
clang_analyzer_dump(__func__);
56-
clang_analyzer_dump(__FUNCTION__);
57-
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}}}
55+
clang_analyzer_dump(__func__); // expected-warning {{&Element{"A",0 S64b,char}}}
56+
#ifdef ANALYZER_MS
57+
clang_analyzer_dump(__FUNCTION__); // expected-warning {{&Element{"A::A",0 S64b,char}}}
58+
#else
59+
clang_analyzer_dump(__FUNCTION__); // expected-warning {{&Element{"A",0 S64b,char}}}
60+
#endif
61+
clang_analyzer_dump(__PRETTY_FUNCTION__); // expected-warning {{&Element{"A::A()",0 S64b,char}}}
6162

6263
#ifdef ANALYZER_MS
6364
clang_analyzer_dump(__FUNCDNAME__);
@@ -71,12 +72,13 @@ struct A {
7172
#endif
7273
}
7374
~A() {
74-
clang_analyzer_dump(__func__);
75-
clang_analyzer_dump(__FUNCTION__);
76-
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}}}
75+
clang_analyzer_dump(__func__); // expected-warning {{&Element{"~A",0 S64b,char}}}
76+
#ifdef ANALYZER_MS
77+
clang_analyzer_dump(__FUNCTION__); // expected-warning {{&Element{"A::~A",0 S64b,char}}}
78+
#else
79+
clang_analyzer_dump(__FUNCTION__); // expected-warning {{&Element{"~A",0 S64b,char}}}
80+
#endif
81+
clang_analyzer_dump(__PRETTY_FUNCTION__); // expected-warning {{&Element{"A::~A()",0 S64b,char}}}
8082

8183
#ifdef ANALYZER_MS
8284
clang_analyzer_dump(__FUNCDNAME__);

clang/test/SemaCXX/source_location.cpp

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -verify %s
22
// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -DUSE_CONSTEVAL -fexceptions -verify %s
33
// RUN: %clang_cc1 -std=c++2b -fcxx-exceptions -DUSE_CONSTEVAL -DPAREN_INIT -fexceptions -verify %s
4-
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fms-extensions -DMS -fexceptions -verify %s
5-
// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS -DUSE_CONSTEVAL -fexceptions -verify %s
4+
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fms-extensions -DMS -fexceptions -fms-compatibility -verify %s
5+
// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS -DUSE_CONSTEVAL -fexceptions -fms-compatibility -verify %s
66
//
77
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
88
// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -DUSE_CONSTEVAL -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
99
// RUN: %clang_cc1 -std=c++2b -fcxx-exceptions -DUSE_CONSTEVAL -DPAREN_INIT -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
10-
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fms-extensions -DMS -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
11-
// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS -DUSE_CONSTEVAL -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
10+
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fms-extensions -DMS -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -fms-compatibility -verify %s
11+
// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS -DUSE_CONSTEVAL -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify -fms-compatibility %s
1212
// expected-no-diagnostics
1313

1414
#define assert(...) ((__VA_ARGS__) ? ((void)0) : throw 42)
@@ -463,8 +463,70 @@ void ctor_tests() {
463463
constexpr SL global_sl = SL::current();
464464
static_assert(is_equal(global_sl.function(), ""));
465465

466+
template <class T>
467+
class TestBI {
468+
public:
469+
TestBI() {
470+
#ifdef MS
471+
static_assert(is_equal(__FUNCTION__, "test_func::TestBI<int>::TestBI"));
472+
#else
473+
static_assert(is_equal(__FUNCTION__, "TestBI"));
474+
#endif
475+
static_assert(is_equal(__func__, "TestBI"));
476+
}
477+
};
478+
479+
template <class T>
480+
class TestClass {
481+
public:
482+
TestClass() {
483+
#ifdef MS
484+
static_assert(is_equal(__FUNCTION__, "test_func::TestClass<class test_func::C>::TestClass"));
485+
#else
486+
static_assert(is_equal(__FUNCTION__, "TestClass"));
487+
#endif
488+
static_assert(is_equal(__func__, "TestClass"));
489+
}
490+
};
491+
492+
template <class T>
493+
class TestStruct {
494+
public:
495+
TestStruct() {
496+
#ifdef MS
497+
static_assert(is_equal(__FUNCTION__, "test_func::TestStruct<struct test_func::S>::TestStruct"));
498+
#else
499+
static_assert(is_equal(__FUNCTION__, "TestStruct"));
500+
#endif
501+
static_assert(is_equal(__func__, "TestStruct"));
502+
}
503+
};
504+
505+
template <class T>
506+
class TestEnum {
507+
public:
508+
TestEnum() {
509+
#ifdef MS
510+
static_assert(is_equal(__FUNCTION__, "test_func::TestEnum<enum test_func::E>::TestEnum"));
511+
#else
512+
static_assert(is_equal(__FUNCTION__, "TestEnum"));
513+
#endif
514+
static_assert(is_equal(__func__, "TestEnum"));
515+
}
516+
};
517+
518+
class C {};
519+
struct S {};
520+
enum E {};
521+
522+
TestBI<int> t1;
523+
TestClass<test_func::C> t2;
524+
TestStruct<test_func::S> t3;
525+
TestEnum<test_func::E> t4;
526+
466527
} // namespace test_func
467528

529+
468530
//===----------------------------------------------------------------------===//
469531
// __builtin_FUNCSIG()
470532
//===----------------------------------------------------------------------===//

clang/unittests/AST/DeclPrinterTest.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,59 @@ TEST(DeclPrinter, TestCXXRecordDecl11) {
358358
"class A : virtual public Z, private Y {}"));
359359
}
360360

361+
TEST(DeclPrinter, TestCXXRecordDecl12) {
362+
ASSERT_TRUE(
363+
PrintedDeclCXX98Matches("struct S { int x; };"
364+
"namespace NS { class C {};}"
365+
"void foo() {using namespace NS; C c;}",
366+
"foo",
367+
"void foo() {\nusing namespace NS;\nclass "
368+
"NS::C c;\n}\n",
369+
[](PrintingPolicy &Policy) {
370+
Policy.SuppressTagKeyword = false;
371+
Policy.SuppressScope = true;
372+
Policy.TerseOutput = false;
373+
}));
374+
}
375+
376+
TEST(DeclPrinter, TestCXXRecordDecl13) {
377+
ASSERT_TRUE(PrintedDeclCXX98Matches(
378+
"struct S { int x; };"
379+
"S s1;"
380+
"S foo() {return s1;}",
381+
"foo", "struct S foo() {\nreturn s1;\n}\n", [](PrintingPolicy &Policy) {
382+
Policy.SuppressTagKeyword = false;
383+
Policy.SuppressScope = true;
384+
Policy.TerseOutput = false;
385+
}));
386+
}
387+
388+
TEST(DeclPrinter, TestCXXRecordDecl14) {
389+
ASSERT_TRUE(PrintedDeclCXX98Matches(
390+
"struct S { int x; };"
391+
"S foo(S s1) {return s1;}",
392+
"foo", "struct S foo(struct S s1) {\nreturn s1;\n}\n",
393+
[](PrintingPolicy &Policy) {
394+
Policy.SuppressTagKeyword = false;
395+
Policy.SuppressScope = true;
396+
Policy.TerseOutput = false;
397+
}));
398+
}
399+
TEST(DeclPrinter, TestCXXRecordDecl15) {
400+
ASSERT_TRUE(PrintedDeclCXX98Matches(
401+
"struct S { int x; };"
402+
"namespace NS { class C {};}"
403+
"S foo(S s1, NS::C c1) {using namespace NS; C c; return s1;}",
404+
"foo",
405+
"struct S foo(struct S s1, class NS::C c1) {\nusing namespace NS;\nclass "
406+
"NS::C c;\nreturn s1;\n}\n",
407+
[](PrintingPolicy &Policy) {
408+
Policy.SuppressTagKeyword = false;
409+
Policy.SuppressScope = true;
410+
Policy.TerseOutput = false;
411+
}));
412+
}
413+
361414
TEST(DeclPrinter, TestFunctionDecl1) {
362415
ASSERT_TRUE(PrintedDeclCXX98Matches(
363416
"void A();",

clang/unittests/AST/TypePrinterTest.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,22 @@ TEST(TypePrinter, TemplateIdWithNTTP) {
155155
}));
156156
}
157157

158+
TEST(TypePrinter, TemplateArgumentsSubstitution) {
159+
constexpr char Code[] = R"cpp(
160+
template <typename Y> class X {};
161+
typedef X<int> A;
162+
int foo() {
163+
return sizeof(A);
164+
}
165+
)cpp";
166+
auto Matcher = typedefNameDecl(hasName("A"), hasType(qualType().bind("id")));
167+
ASSERT_TRUE(PrintedTypeMatches(Code, {}, Matcher, "X<int>",
168+
[](PrintingPolicy &Policy) {
169+
Policy.SuppressTagKeyword = false;
170+
Policy.SuppressScope = true;
171+
}));
172+
}
173+
158174
TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) {
159175
/// Tests clang::isSubstitutedDefaultArgument on TemplateArguments
160176
/// that are of kind TemplateArgument::Expression

0 commit comments

Comments
 (0)