diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index cee3cce7729c3..17d4e1a326d31 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -76,8 +76,8 @@ struct PrintingPolicy { SuppressImplicitBase(false), FullyQualifiedName(false), PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true), UsePreferredNames(true), AlwaysIncludeTypeForTemplateArgument(false), - CleanUglifiedParameters(false), EntireContentsOfLargeArray(true), - UseEnumerators(true) {} + UseClassForTemplateArgument(false), CleanUglifiedParameters(false), + EntireContentsOfLargeArray(true), UseEnumerators(true) {} /// Adjust this printing policy for cases where it's known that we're /// printing C++ code (for instance, if AST dumping reaches a C++-only @@ -291,6 +291,10 @@ struct PrintingPolicy { /// parameters. unsigned AlwaysIncludeTypeForTemplateArgument : 1; + // Prints "class" keyword before type template arguments. This is used when + // printing a function via the _FUNCTION__ or __func__ macro in MSVC mode. + unsigned UseClassForTemplateArgument : 1; + /// Whether to strip underscores when printing reserved parameter names. /// e.g. std::vector becomes std::vector. /// This only affects parameter names, and so describes a compatible API. diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 4f3837371b3fc..af82ca0784af4 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -772,18 +772,21 @@ std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) { return std::string(Out.str()); } if (const FunctionDecl *FD = dyn_cast(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(FD)) { - if (MD->isVirtual() && IK != PrettyFunctionNoVirtual) - Out << "virtual "; - if (MD->isStatic()) - Out << "static "; + if (IK != Function) { + if (const CXXMethodDecl *MD = dyn_cast(FD)) { + if (MD->isVirtual() && IK != PrettyFunctionNoVirtual) + Out << "virtual "; + if (MD->isStatic()) + Out << "static "; + } } class PrettyCallbacks final : public PrintingCallbacks { @@ -798,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.UseClassForTemplateArgument = LO.MicrosoftExt; std::string Proto; llvm::raw_string_ostream POut(Proto); @@ -827,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 eb69d0bb8755b..3771a29f26b17 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -2218,6 +2218,10 @@ printTo(raw_ostream &OS, ArrayRef Args, const PrintingPolicy &Policy, } else { if (!FirstArg) OS << Comma; + if (Policy.UseClassForTemplateArgument && + Argument.getKind() == TemplateArgument::Type) + OS << "class "; + // Tries to print the argument with location info if exists. printArgument(Arg, Policy, ArgOS, TemplateParameterList::shouldIncludeTypeForArgument( diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index ceda59405ea91..aabc909b3328e 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 1eec4476a065f..7be441eb5bad9 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::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::~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/CodeGenCXX/predefined-expr.cpp b/clang/test/CodeGenCXX/predefined-expr.cpp index 815bcbb3bd899..af76e0538a9ec 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::memberFunctionTemplate(T, U) const [T = char, U = double]\00" +// CHECK-DAG: private unnamed_addr constant [43 x i8] c"TestClass::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::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::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 } }; + +template +class TestClass { +public: + TestClass() { + const char* expected = "TestClass::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 sct2; sct2.memberFunctionTemplate('0', 0.0); + TestClass t; return 0; } diff --git a/clang/test/SemaCXX/source_location.cpp b/clang/test/SemaCXX/source_location.cpp index e92fb35b653a8..d4d4c8fa650e1 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 {