Index: clang/docs/LanguageExtensions.rst =================================================================== --- clang/docs/LanguageExtensions.rst +++ clang/docs/LanguageExtensions.rst @@ -3711,7 +3711,7 @@ Clang provides builtins to support C++ standard library implementation of ``std::source_location`` as specified in C++20. With the exception -of ``__builtin_COLUMN`` and ``__builtin_FILE_NAME``, +of ``__builtin_COLUMN``, ``__builtin_FILE_NAME`` and ``__builtin_FUNCSIG``, these builtins are also implemented by GCC. **Syntax**: @@ -3721,6 +3721,7 @@ const char *__builtin_FILE(); const char *__builtin_FILE_NAME(); // Clang only const char *__builtin_FUNCTION(); + const char *__builtin_FUNCSIG(); // Microsoft unsigned __builtin_LINE(); unsigned __builtin_COLUMN(); // Clang only const std::source_location::__impl *__builtin_source_location(); @@ -3750,11 +3751,12 @@ **Description**: -The builtins ``__builtin_LINE``, ``__builtin_FUNCTION``, ``__builtin_FILE`` and -``__builtin_FILE_NAME`` return the values, at the "invocation point", for -``__LINE__``, ``__FUNCTION__``, ``__FILE__`` and ``__FILE_NAME__`` respectively. -``__builtin_COLUMN`` similarly returns the column, -though there is no corresponding macro. These builtins are constant expressions. +The builtins ``__builtin_LINE``, ``__builtin_FUNCTION``, ``__builtin_FUNCSIG``, +``__builtin_FILE`` and ``__builtin_FILE_NAME`` return the values, at the +"invocation point", for ``__LINE__``, ``__FUNCTION__``, ``__FUNCSIG__``, +``__FILE__`` and ``__FILE_NAME__`` respectively. ``__builtin_COLUMN`` similarly +returns the column, though there is no corresponding macro. These builtins are +constant expressions. When the builtins appear as part of a default function argument the invocation point is the location of the caller. When the builtins appear as part of a Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -192,6 +192,9 @@ ``memcmp(&lhs, &rhs, sizeof(T)) == 0``. - Clang now ignores null directives outside of the include guard when deciding whether a file can be enabled for the multiple-include optimization. +- Clang now support ``__builtin_FUNCSIG()`` which retruns the same information + as the ``__FUNCSIG__`` macro (available only with ``-fms-extensions`` flag). + This fixes (`#58951 `_). New Compiler Flags ------------------ Index: clang/include/clang/AST/Expr.h =================================================================== --- clang/include/clang/AST/Expr.h +++ clang/include/clang/AST/Expr.h @@ -4691,14 +4691,22 @@ }; /// Represents a function call to one of __builtin_LINE(), __builtin_COLUMN(), -/// __builtin_FUNCTION(), __builtin_FILE(), __builtin_FILE_NAME(), -/// or __builtin_source_location(). +/// __builtin_FUNCTION(), __builtin_FUNCSIG(), __builtin_FILE(), +/// __builtin_FILE_NAME() or __builtin_source_location(). class SourceLocExpr final : public Expr { SourceLocation BuiltinLoc, RParenLoc; DeclContext *ParentContext; public: - enum IdentKind { Function, File, FileName, Line, Column, SourceLocStruct }; + enum IdentKind { + Function, + FuncSig, + File, + FileName, + Line, + Column, + SourceLocStruct + }; SourceLocExpr(const ASTContext &Ctx, IdentKind Type, QualType ResultTy, SourceLocation BLoc, SourceLocation RParenLoc, @@ -4724,6 +4732,7 @@ case File: case FileName: case Function: + case FuncSig: case SourceLocStruct: return false; case Line: Index: clang/include/clang/Basic/TokenKinds.def =================================================================== --- clang/include/clang/Basic/TokenKinds.def +++ clang/include/clang/Basic/TokenKinds.def @@ -438,6 +438,7 @@ KEYWORD(__builtin_FILE , KEYALL) KEYWORD(__builtin_FILE_NAME , KEYALL) KEYWORD(__builtin_FUNCTION , KEYALL) +KEYWORD(__builtin_FUNCSIG , KEYMS) KEYWORD(__builtin_LINE , KEYALL) KEYWORD(__builtin_COLUMN , KEYALL) KEYWORD(__builtin_source_location , KEYCXX) Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -6000,8 +6000,8 @@ ExprResult BuildVAArgExpr(SourceLocation BuiltinLoc, Expr *E, TypeSourceInfo *TInfo, SourceLocation RPLoc); - // __builtin_LINE(), __builtin_FUNCTION(), __builtin_FILE(), - // __builtin_COLUMN(), __builtin_source_location() + // __builtin_LINE(), __builtin_FUNCTION(), __builtin_FUNCSIG(), + // __builtin_FILE(), __builtin_COLUMN(), __builtin_source_location() ExprResult ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind, SourceLocation BuiltinLoc, SourceLocation RPLoc); Index: clang/lib/AST/Expr.cpp =================================================================== --- clang/lib/AST/Expr.cpp +++ clang/lib/AST/Expr.cpp @@ -2247,6 +2247,8 @@ return "__builtin_FILE_NAME"; case Function: return "__builtin_FUNCTION"; + case FuncSig: + return "__builtin_FUNCSIG"; case Line: return "__builtin_LINE"; case Column: @@ -2297,11 +2299,14 @@ Ctx.getTargetInfo()); return MakeStringLiteral(Path); } - case SourceLocExpr::Function: { + case SourceLocExpr::Function: + case SourceLocExpr::FuncSig: { const auto *CurDecl = dyn_cast(Context); + const auto Kind = getIdentKind() == SourceLocExpr::Function + ? PredefinedExpr::Function + : PredefinedExpr::FuncSig; return MakeStringLiteral( - CurDecl ? PredefinedExpr::ComputeName(PredefinedExpr::Function, CurDecl) - : std::string("")); + CurDecl ? PredefinedExpr::ComputeName(Kind, CurDecl) : std::string("")); } case SourceLocExpr::Line: case SourceLocExpr::Column: { Index: clang/lib/Parse/ParseExpr.cpp =================================================================== --- clang/lib/Parse/ParseExpr.cpp +++ clang/lib/Parse/ParseExpr.cpp @@ -792,6 +792,7 @@ /// [GNU] '__builtin_FILE' '(' ')' /// [CLANG] '__builtin_FILE_NAME' '(' ')' /// [GNU] '__builtin_FUNCTION' '(' ')' +/// [MS] '__builtin_FUNCSIG' '(' ')' /// [GNU] '__builtin_LINE' '(' ')' /// [CLANG] '__builtin_COLUMN' '(' ')' /// [GNU] '__builtin_source_location' '(' ')' @@ -803,9 +804,9 @@ /// [OBJC] '\@encode' '(' type-name ')' /// [OBJC] objc-string-literal /// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] -/// [C++11] simple-type-specifier braced-init-list [C++11 5.2.3] +/// [C++11] simple-type-specifier braced-init-list [C++11 5.2.3] /// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3] -/// [C++11] typename-specifier braced-init-list [C++11 5.2.3] +/// [C++11] typename-specifier braced-init-list [C++11 5.2.3] /// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] @@ -1321,6 +1322,7 @@ case tok::kw___builtin_FILE: case tok::kw___builtin_FILE_NAME: case tok::kw___builtin_FUNCTION: + case tok::kw___builtin_FUNCSIG: case tok::kw___builtin_LINE: case tok::kw___builtin_source_location: if (NotPrimaryExpression) @@ -2547,6 +2549,7 @@ /// [GNU] '__builtin_FILE' '(' ')' /// [CLANG] '__builtin_FILE_NAME' '(' ')' /// [GNU] '__builtin_FUNCTION' '(' ')' +/// [MS] '__builtin_FUNCSIG' '(' ')' /// [GNU] '__builtin_LINE' '(' ')' /// [CLANG] '__builtin_COLUMN' '(' ')' /// [GNU] '__builtin_source_location' '(' ')' @@ -2783,6 +2786,7 @@ case tok::kw___builtin_FILE: case tok::kw___builtin_FILE_NAME: case tok::kw___builtin_FUNCTION: + case tok::kw___builtin_FUNCSIG: case tok::kw___builtin_LINE: case tok::kw___builtin_source_location: { // Attempt to consume the r-paren. @@ -2799,6 +2803,8 @@ return SourceLocExpr::FileName; case tok::kw___builtin_FUNCTION: return SourceLocExpr::Function; + case tok::kw___builtin_FUNCSIG: + return SourceLocExpr::FuncSig; case tok::kw___builtin_LINE: return SourceLocExpr::Line; case tok::kw___builtin_COLUMN: Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -17181,7 +17181,8 @@ switch (Kind) { case SourceLocExpr::File: case SourceLocExpr::FileName: - case SourceLocExpr::Function: { + case SourceLocExpr::Function: + case SourceLocExpr::FuncSig: { QualType ArrTy = Context.getStringLiteralArrayType(Context.CharTy, 0); ResultTy = Context.getPointerType(ArrTy->getAsArrayTypeUnsafe()->getElementType()); Index: clang/test/Preprocessor/feature_tests.c =================================================================== --- clang/test/Preprocessor/feature_tests.c +++ clang/test/Preprocessor/feature_tests.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 %s -triple=i686-apple-darwin9 -target-cpu pentium4 -verify -DVERIFY -// RUN: %clang_cc1 %s -E -triple=i686-apple-darwin9 -target-cpu pentium4 +// RUN: %clang_cc1 %s -triple=i686-apple-darwin9 -target-cpu pentium4 -fms-extensions -verify -DVERIFY +// RUN: %clang_cc1 %s -E -triple=i686-apple-darwin9 -target-cpu pentium4 -fms-extensions #ifndef __has_feature #error Should have __has_feature #endif @@ -26,6 +26,7 @@ !__has_builtin(__builtin_FILE) || \ !__has_builtin(__builtin_FILE_NAME) || \ !__has_builtin(__builtin_FUNCTION) || \ + !__has_builtin(__builtin_FUNCSIG) || \ !__has_builtin(__builtin_COLUMN) || \ !__has_builtin(__builtin_types_compatible_p) #error Clang should have these Index: clang/test/Sema/source_location.c =================================================================== --- clang/test/Sema/source_location.c +++ clang/test/Sema/source_location.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -std=c90 -fconst-strings -DCONST_STRINGS -verify %s -// RUN: %clang_cc1 -std=c90 -verify %s +// RUN: %clang_cc1 -std=c90 -fms-extensions -fconst-strings -DCONST_STRINGS -verify %s +// RUN: %clang_cc1 -std=c90 -fms-extensions -verify %s // expected-no-diagnostics @@ -13,6 +13,7 @@ #ifndef CONST_STRINGS char *const NCFILE = __builtin_FILE(); char *const NCFUNC = __builtin_FUNCTION(); +char *const NCFNSG = __builtin_FUNCSIG(); #endif #ifdef CONST_STRINGS @@ -20,6 +21,7 @@ _Static_assert(IsEqual(__builtin_FILE_NAME(), __FILE_NAME__), ""); _Static_assert(__builtin_LINE() == __LINE__, ""); _Static_assert(IsEqual("", __builtin_FUNCTION()), ""); +_Static_assert(IsEqual("", __builtin_FUNCSIG()), ""); #line 42 "my_file.c" _Static_assert(__builtin_LINE() == 42, ""); @@ -30,5 +32,6 @@ void foo(void) { _Static_assert(IsEqual(__builtin_FUNCTION(), "foo"), ""); + _Static_assert(IsEqual(__builtin_FUNCSIG(), "void __cdecl foo(void)"), ""); } #endif // CONST_STRINGS Index: clang/test/SemaCXX/source_location.cpp =================================================================== --- clang/test/SemaCXX/source_location.cpp +++ clang/test/SemaCXX/source_location.cpp @@ -1,5 +1,5 @@ -// 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++1z -fcxx-exceptions -fms-extensions -fexceptions -verify %s +// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DUSE_CONSTEVAL -fexceptions -verify %s // expected-no-diagnostics #define assert(...) ((__VA_ARGS__) ? ((void)0) : throw 42) @@ -86,6 +86,7 @@ static_assert(is_same); static_assert(is_same); static_assert(is_same); +static_assert(is_same); static_assert(is_same); // test noexcept @@ -94,6 +95,7 @@ static_assert(noexcept(__builtin_FILE())); static_assert(noexcept(__builtin_FILE_NAME())); static_assert(noexcept(__builtin_FUNCTION())); +static_assert(noexcept(__builtin_FUNCSIG())); static_assert(noexcept(__builtin_source_location())); //===----------------------------------------------------------------------===// @@ -450,6 +452,55 @@ } // namespace test_func +//===----------------------------------------------------------------------===// +// __builtin_FUNCSIG() +//===----------------------------------------------------------------------===// + +namespace test_funcsig { + +constexpr const char *test_funcsig_simple(const char *f = __builtin_FUNCSIG()) { + return f; +} +constexpr const char *get_funcsig() { + return __FUNCSIG__; +} +constexpr bool test_funcsig() { + return is_equal(__FUNCSIG__, test_funcsig_simple()) && + !is_equal(get_funcsig(), test_funcsig_simple()); +} +static_assert(test_funcsig()); + +template +constexpr Pair test_funcsig_template(T, const char* f = __builtin_FUNCSIG()) { + return {f, __builtin_FUNCSIG()}; +} +template +void func_template_tests() { + constexpr auto P = test_funcsig_template(42); + static_assert(is_equal(P.first, __FUNCSIG__), ""); + static_assert(!is_equal(P.second, __FUNCSIG__), ""); +} +template void func_template_tests(); + +template +struct TestCtor { + T funcsig = __builtin_FUNCSIG(); + T ctor_funcsig; + TestCtor() = default; + template + constexpr TestCtor(int, F f = __builtin_FUNCSIG()) : ctor_funcsig(f) {} +}; +void ctor_tests() { + constexpr TestCtor<> Template{42}; + static_assert(is_equal(Template.funcsig, "__cdecl test_funcsig::TestCtor<>::TestCtor(int, F) [T = const char *, F = const char *]")); + static_assert(is_equal(Template.ctor_funcsig, __FUNCSIG__)); +} + +constexpr const char* global_funcsig = __builtin_FUNCSIG(); +static_assert(is_equal(global_funcsig, "")); + +} // namespace test_funcsig + //===----------------------------------------------------------------------===// // __builtin_COLUMN() //===----------------------------------------------------------------------===//