llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Zahira Ammarguellat (zahiraam) <details> <summary>Changes</summary> 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 --- Full diff: https://github.com/llvm/llvm-project/pull/84014.diff 9 Files Affected: - (modified) clang/docs/ReleaseNotes.rst (+3) - (modified) clang/include/clang/AST/Expr.h (+2-1) - (modified) clang/lib/AST/Expr.cpp (+21-5) - (modified) clang/lib/AST/TypePrinter.cpp (+20-4) - (modified) clang/lib/Sema/SemaExpr.cpp (+4-1) - (modified) clang/test/AST/Interp/literals.cpp (+4-4) - (modified) clang/test/Analysis/eval-predefined-exprs.cpp (+16-6) - (modified) clang/test/SemaCXX/source_location.cpp (+64) - (modified) clang/unittests/AST/DeclPrinterTest.cpp (+15) ``````````diff 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@-3 {{&Element{"A",0 S64b,char}}} - // expected-warning@-3 {{&Element{"A",0 S64b,char}}} - // expected-warning@-3 {{&Element{"A::A()",0 S64b,char}}} +#ifdef ANALYZER_MS + // expected-warning@-4 {{&Element{"A",0 S64b,char}}} + // expected-warning@-4 {{&Element{"A::A",0 S64b,char}}} +#else + // expected-warning@-7 {{&Element{"A",0 S64b,char}}} + // expected-warning@-7 {{&Element{"A",0 S64b,char}}} +#endif + // expected-warning@-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@-3 {{&Element{"~A",0 S64b,char}}} - // expected-warning@-3 {{&Element{"~A",0 S64b,char}}} - // expected-warning@-3 {{&Element{"A::~A()",0 S64b,char}}} +#ifdef ANALYZER_MS + // expected-warning@-4 {{&Element{"~A",0 S64b,char}}} + // expected-warning@-4 {{&Element{"A::~A",0 S64b,char}}} +#else + // expected-warning@-7 {{&Element{"~A",0 S64b,char}}} + // expected-warning@-7 {{&Element{"~A",0 S64b,char}}} +#endif + // expected-warning@-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();", `````````` </details> https://github.com/llvm/llvm-project/pull/84014 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits