diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/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 diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -198,6 +198,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 ------------------ diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h --- a/clang/include/clang/AST/Expr.h +++ b/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: diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def --- a/clang/include/clang/Basic/TokenKinds.def +++ b/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) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -6006,8 +6006,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); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/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: { diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp --- a/clang/lib/Parse/ParseExpr.cpp +++ b/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' '(' ')' @@ -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: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/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()); diff --git a/clang/test/Preprocessor/feature_tests.c b/clang/test/Preprocessor/feature_tests.c --- a/clang/test/Preprocessor/feature_tests.c +++ b/clang/test/Preprocessor/feature_tests.c @@ -1,5 +1,7 @@ // 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 -DMS -verify -DVERIFY +// RUN: %clang_cc1 %s -E -triple=i686-apple-darwin9 -target-cpu pentium4 -fms-extensions -DMS #ifndef __has_feature #error Should have __has_feature #endif @@ -31,6 +33,14 @@ #error Clang should have these #endif +#ifdef MS +#if !__has_builtin(__builtin_FUNCSIG) +#error Clang should have this +#endif +#elif __has_builtin(__builtin_FUNCSIG) +#error Clang should not have this without '-fms-extensions' +#endif + // These are C++-only builtins. #if __has_builtin(__array_rank) || \ __has_builtin(__underlying_type) || \ diff --git a/clang/test/Preprocessor/feature_tests.cpp b/clang/test/Preprocessor/feature_tests.cpp --- a/clang/test/Preprocessor/feature_tests.cpp +++ b/clang/test/Preprocessor/feature_tests.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -triple=i686-apple-darwin9 -verify -DVERIFY +// RUN: %clang_cc1 %s -triple=i686-apple-darwin9 -fms-extensions -DMS -verify -DVERIFY #ifndef __has_feature #error Should have __has_feature @@ -34,6 +35,14 @@ #error Clang should have these #endif +#ifdef MS +#if !__has_builtin(__builtin_FUNCSIG) +#error Clang should have this +#endif +#elif __has_builtin(__builtin_FUNCSIG) +#error Clang should not have this without '-fms-extensions' +#endif + // This is a C-only builtin. #if __has_builtin(__builtin_types_compatible_p) #error Clang should not have this in C++ mode diff --git a/clang/test/Sema/source_location.c b/clang/test/Sema/source_location.c --- a/clang/test/Sema/source_location.c +++ b/clang/test/Sema/source_location.c @@ -1,5 +1,7 @@ // 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 -DMS -fconst-strings -DCONST_STRINGS -verify %s +// RUN: %clang_cc1 -std=c90 -fms-extensions -DMS -verify %s // expected-no-diagnostics @@ -13,6 +15,9 @@ #ifndef CONST_STRINGS char *const NCFILE = __builtin_FILE(); char *const NCFUNC = __builtin_FUNCTION(); +#ifdef MS +char *const NCFNSG = __builtin_FUNCSIG(); +#endif #endif #ifdef CONST_STRINGS @@ -20,6 +25,9 @@ _Static_assert(IsEqual(__builtin_FILE_NAME(), __FILE_NAME__), ""); _Static_assert(__builtin_LINE() == __LINE__, ""); _Static_assert(IsEqual("", __builtin_FUNCTION()), ""); +#ifdef MS +_Static_assert(IsEqual("", __builtin_FUNCSIG()), ""); +#endif #line 42 "my_file.c" _Static_assert(__builtin_LINE() == 42, ""); @@ -30,5 +38,8 @@ void foo(void) { _Static_assert(IsEqual(__builtin_FUNCTION(), "foo"), ""); +#ifdef MS + _Static_assert(IsEqual(__builtin_FUNCSIG(), "void __cdecl foo(void)"), ""); +#endif } #endif // CONST_STRINGS diff --git a/clang/test/SemaCXX/source_location.cpp b/clang/test/SemaCXX/source_location.cpp --- a/clang/test/SemaCXX/source_location.cpp +++ b/clang/test/SemaCXX/source_location.cpp @@ -1,5 +1,7 @@ // 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 -DMS -fexceptions -verify %s +// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS -DUSE_CONSTEVAL -fexceptions -verify %s // expected-no-diagnostics #define assert(...) ((__VA_ARGS__) ? ((void)0) : throw 42) @@ -86,6 +88,9 @@ static_assert(is_same); static_assert(is_same); static_assert(is_same); +#ifdef MS +static_assert(is_same); +#endif static_assert(is_same); // test noexcept @@ -94,6 +99,9 @@ static_assert(noexcept(__builtin_FILE())); static_assert(noexcept(__builtin_FILE_NAME())); static_assert(noexcept(__builtin_FUNCTION())); +#ifdef MS +static_assert(noexcept(__builtin_FUNCSIG())); +#endif static_assert(noexcept(__builtin_source_location())); //===----------------------------------------------------------------------===// @@ -450,6 +458,57 @@ } // namespace test_func +//===----------------------------------------------------------------------===// +// __builtin_FUNCSIG() +//===----------------------------------------------------------------------===// + +#ifdef MS +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 +#endif + //===----------------------------------------------------------------------===// // __builtin_COLUMN() //===----------------------------------------------------------------------===//