[clang] 78d8312 - [Clang][clang-cl] Implement `__builtin_FUNCSIG`

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Fri May 19 09:02:54 PDT 2023


Author: Jakub Mazurkiewicz
Date: 2023-05-19T12:02:44-04:00
New Revision: 78d8312acea96f58f13a876f98d241590c16d530

URL: https://github.com/llvm/llvm-project/commit/78d8312acea96f58f13a876f98d241590c16d530
DIFF: https://github.com/llvm/llvm-project/commit/78d8312acea96f58f13a876f98d241590c16d530.diff

LOG: [Clang][clang-cl] Implement `__builtin_FUNCSIG`

This patch implements __builtin_FUNCSIG intrinsic which returns the same string as __FUNCSIG__.

Fixes https://github.com/llvm/llvm-project/issues/58951
Differential Revision: https://reviews.llvm.org/D150183

Added: 
    

Modified: 
    clang/docs/LanguageExtensions.rst
    clang/docs/ReleaseNotes.rst
    clang/include/clang/AST/Expr.h
    clang/include/clang/Basic/TokenKinds.def
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/Expr.cpp
    clang/lib/Parse/ParseExpr.cpp
    clang/lib/Sema/SemaExpr.cpp
    clang/test/Preprocessor/feature_tests.c
    clang/test/Preprocessor/feature_tests.cpp
    clang/test/Sema/source_location.c
    clang/test/SemaCXX/source_location.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 632a5cf1a7d02..5b186c4f81774 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3711,7 +3711,7 @@ Source location builtins
 
 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 @@ these builtins are also implemented by GCC.
   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 @@ these builtins are also implemented by GCC.
 
 **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
index 1dd3d8a0ed80c..9bcc17b0c5ff8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -198,6 +198,9 @@ Non-comprehensive list of changes in this release
   ``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 <https://github.com/llvm/llvm-project/issues/58951>`_).
 
 New Compiler Flags
 ------------------

diff  --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index db4316d8faf1f..22cbf23ac2a4c 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -4691,14 +4691,22 @@ class VAArgExpr : public Expr {
 };
 
 /// 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 @@ class SourceLocExpr final : public Expr {
     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
index ae67209d9b9e2..7c3a55cb76348 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -438,6 +438,7 @@ KEYWORD(__builtin_offsetof          , KEYALL)
 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
index aae1d9ce3208e..6e2734da2bea6 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6006,8 +6006,8 @@ class Sema final {
   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
index 588a7ad322b9a..958f4e9042319 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -2247,6 +2247,8 @@ StringRef SourceLocExpr::getBuiltinStr() const {
     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 @@ APValue SourceLocExpr::EvaluateInContext(const ASTContext &Ctx,
                                                  Ctx.getTargetInfo());
     return MakeStringLiteral(Path);
   }
-  case SourceLocExpr::Function: {
+  case SourceLocExpr::Function:
+  case SourceLocExpr::FuncSig: {
     const auto *CurDecl = dyn_cast<Decl>(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
index b99baf476592f..57bb8f609592f 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -792,6 +792,7 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback {
 /// [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 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
   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 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
 /// [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 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
   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 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
         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
index e7a555b991bf0..ac0b2ad6eb7ee 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -17181,7 +17181,8 @@ ExprResult Sema::ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind,
   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
index 07ca02279b911..e8aecfb82cb3b 100644
--- 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
index 810cfe88cae5f..00421d74e6282 100644
--- 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
index e4faf042d4876..e0030c634dd88 100644
--- 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 @@ const unsigned COL = __builtin_COLUMN();
 #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(), __FILE__), "");
 _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 @@ _Static_assert(__builtin_COLUMN() == __builtin_strlen("_Static_assert(_"), "");
 
 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
index 06f90f9251643..6ff58d4ee8ca1 100644
--- 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<decltype(__builtin_COLUMN()), unsigned>);
 static_assert(is_same<decltype(__builtin_FILE()), const char *>);
 static_assert(is_same<decltype(__builtin_FILE_NAME()), const char *>);
 static_assert(is_same<decltype(__builtin_FUNCTION()), const char *>);
+#ifdef MS
+static_assert(is_same<decltype(__builtin_FUNCSIG()), const char *>);
+#endif
 static_assert(is_same<decltype(__builtin_source_location()), const std::source_location::public_impl_alias *>);
 
 // test noexcept
@@ -94,6 +99,9 @@ static_assert(noexcept(__builtin_COLUMN()));
 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 @@ static_assert(is_equal(global_sl.function(), ""));
 
 } // 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 <class T>
+constexpr Pair<const char*, const char*> test_funcsig_template(T, const char* f = __builtin_FUNCSIG()) {
+  return {f, __builtin_FUNCSIG()};
+}
+template <class T>
+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<int>();
+
+template <class = int, class T = const char*>
+struct TestCtor {
+  T funcsig = __builtin_FUNCSIG();
+  T ctor_funcsig;
+  TestCtor() = default;
+  template <class F = const char*>
+  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()
 //===----------------------------------------------------------------------===//


        


More information about the cfe-commits mailing list