PR c++/66561 - __builtin_LINE at al. should yield constant expressions
authorMartin Sebor <msebor@redhat.com>
Tue, 3 May 2016 21:15:28 +0000 (21:15 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Tue, 3 May 2016 21:15:28 +0000 (15:15 -0600)
PR c++/66561 - __builtin_LINE at al. should yield constant expressions
PR c++/66639 - declare __func__, __FUNCTION__ & __PRETTY_FUNCTION__ constexpr

gcc/testsuite/ChangeLog:
2016-05-03  Martin Sebor  <msebor@redhat.com>

PR c++/66561
* c-c++-common/builtin_location.c: New test.
* g++.dg/cpp1y/builtin_location.C: New test.

gcc/cp/ChangeLog:
2016-05-03  Martin Sebor  <msebor@redhat.com>

PR c++/66561
* tree.c (builtin_valid_in_constant_expr_p): Treat BUILT_IN_FILE,
BUILT_IN_FUNCTION, and BUILT_IN_LINE as constant expressions.

gcc/ChangeLog:
2016-05-03  Martin Sebor  <msebor@redhat.com>

PR c++/66561
* builtins.c (fold_builtin_FILE): New function.
(fold_builtin_FUNCTION, fold_builtin_LINE): New functions.
(fold_builtin_0): Call them.
* gimplify.c (gimplify_call_expr): Remove the handling of
BUILT_IN_FILE, BUILT_IN_FUNCTION, and BUILT_IN_LINE.

PR c++/66561
* doc/extend.texi (Other Builtins): Update __builtin_FILE,
__builtin_FUNCTION, and __builtin_LINE to reflect they yield
constants.

PR c++/66639
* doc/extend.texi (Function Names as Strings): Update __func__,
__FUNCTION__, __PRETTY_FUNCTION__ to reflect they evaluate to
constants.

From-SVN: r235845

gcc/ChangeLog
gcc/builtins.c
gcc/cp/ChangeLog
gcc/cp/tree.c
gcc/doc/extend.texi
gcc/gimplify.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/builtin_location.c [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/builtin_location.C [new file with mode: 0644]

index f9950c420f868796fe55922b31a15f90ad590929..36b57ac9620f19d9a7f264733cc1bb4843d82f27 100644 (file)
@@ -1,3 +1,22 @@
+2016-05-03  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/66561
+       * builtins.c (fold_builtin_FILE): New function.
+       (fold_builtin_FUNCTION, fold_builtin_LINE): New functions.
+       (fold_builtin_0): Call them.
+       * gimplify.c (gimplify_call_expr): Remove the handling of
+       BUILT_IN_FILE, BUILT_IN_FUNCTION, and BUILT_IN_LINE.
+
+       PR c++/66561
+       * doc/extend.texi (Other Builtins): Update __builtin_FILE,
+       __builtin_FUNCTION, and __builtin_LINE to reflect they yield
+       constants.
+
+       PR c++/66639
+       * doc/extend.texi (Function Names as Strings): Update __func__,
+       __FUNCTION__, __PRETTY_FUNCTION__ to reflect they evaluate to
+       constants.
+
 2016-05-03  Jakub Jelinek  <jakub@redhat.com>
            Richard Biener  <rguenther@suse.de>
 
index 7d876199bcab8cca9f2e88dbd551b8fdb556c2e2..476feb1eb164e4c5cdd22e2526bd1786f115dca6 100644 (file)
@@ -8011,6 +8011,39 @@ fold_builtin_arith_overflow (location_t loc, enum built_in_function fcode,
   return build2_loc (loc, COMPOUND_EXPR, boolean_type_node, store, ovfres);
 }
 
+/* Fold a call to __builtin_FILE to a constant string.  */
+
+static inline tree
+fold_builtin_FILE (location_t loc)
+{
+  if (const char *fname = LOCATION_FILE (loc))
+    return build_string_literal (strlen (fname) + 1, fname);
+
+  return build_string_literal (1, "");
+}
+
+/* Fold a call to __builtin_FUNCTION to a constant string.  */
+
+static inline tree
+fold_builtin_FUNCTION ()
+{
+  if (current_function_decl)
+    {
+      const char *name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
+      return build_string_literal (strlen (name) + 1, name);
+    }
+
+  return build_string_literal (1, "");
+}
+
+/* Fold a call to __builtin_LINE to an integer constant.  */
+
+static inline tree
+fold_builtin_LINE (location_t loc, tree type)
+{
+  return build_int_cst (type, LOCATION_LINE (loc));
+}
+
 /* Fold a call to built-in function FNDECL with 0 arguments.
    This function returns NULL_TREE if no simplification was possible.  */
 
@@ -8021,6 +8054,15 @@ fold_builtin_0 (location_t loc, tree fndecl)
   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
   switch (fcode)
     {
+    case BUILT_IN_FILE:
+      return fold_builtin_FILE (loc);
+
+    case BUILT_IN_FUNCTION:
+      return fold_builtin_FUNCTION ();
+
+    case BUILT_IN_LINE:
+      return fold_builtin_LINE (loc, type);
+
     CASE_FLT_FN (BUILT_IN_INF):
     case BUILT_IN_INFD32:
     case BUILT_IN_INFD64:
index 3bc37e1ba70d6923ebddc31b0be3192ec0d8af3b..b7375189214821074cf25252f2735df3ed9b877c 100644 (file)
@@ -1,3 +1,9 @@
+2016-05-03  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/66561
+       * tree.c (builtin_valid_in_constant_expr_p): Treat BUILT_IN_FILE,
+       BUILT_IN_FUNCTION, and BUILT_IN_LINE as constant expressions.
+
 2016-05-03  Marek Polacek  <polacek@redhat.com>
 
        PR c/70859
index d7e9c7b804861a4a026f7ac719fdb81ebdeeaf10..57fc5c1c54c388eee8960f2421a74d7031ade1e6 100644 (file)
@@ -346,10 +346,16 @@ builtin_valid_in_constant_expr_p (const_tree decl)
     return false;
   switch (DECL_FUNCTION_CODE (decl))
     {
-    case BUILT_IN_CONSTANT_P:
-    case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
+      /* These always have constant results like the corresponding
+        macros/symbol.  */
+    case BUILT_IN_FILE:
+    case BUILT_IN_FUNCTION:
+    case BUILT_IN_LINE:
+
       /* These have constant results even if their operands are
         non-constant.  */
+    case BUILT_IN_CONSTANT_P:
+    case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
       return true;
     default:
       return false;
index daf1297350d89d87890dde1a05ed9a17a83559d9..802845dc66f3c819186b57062be1d121900e1869 100644 (file)
@@ -8929,9 +8929,11 @@ This extension is not supported by GNU C++.
 @cindex @code{__FUNCTION__} identifier
 @cindex @code{__PRETTY_FUNCTION__} identifier
 
-GCC provides three magic variables that hold the name of the current
-function, as a string.  The first of these is @code{__func__}, which
-is part of the C99 standard:
+GCC provides three magic constants that hold the name of the current
+function as a string.  In C++11 and later modes, all three are treated
+as constant expressions and can be used in @code{constexpr} constexts.
+The first of these constants is @code{__func__}, which is part of
+the C99 standard:
 
 The identifier @code{__func__} is implicitly declared by the translator
 as if, immediately following the opening brace of each function
@@ -8943,20 +8945,21 @@ static const char __func__[] = "function-name";
 
 @noindent
 appeared, where function-name is the name of the lexically-enclosing
-function.  This name is the unadorned name of the function.
+function.  This name is the unadorned name of the function.  As an
+extension, at file (or, in C++, namespace scope), @code{__func__}
+evaluates to the empty string.
 
 @code{__FUNCTION__} is another name for @code{__func__}, provided for
 backward compatibility with old versions of GCC.
 
 In C, @code{__PRETTY_FUNCTION__} is yet another name for
-@code{__func__}.  However, in C++, @code{__PRETTY_FUNCTION__} contains
-the type signature of the function as well as its bare name.  For
-example, this program:
+@code{__func__}, except that at file (or, in C++, namespace scope),
+it evaluates to the string @code{"top level"}.  In addition, in C++,
+@code{__PRETTY_FUNCTION__} contains the signature of the function as
+well as its bare name.  For example, this program:
 
 @smallexample
-extern "C" @{
-extern int printf (char *, ...);
-@}
+extern "C" int printf (const char *, ...);
 
 class a @{
  public:
@@ -8985,7 +8988,7 @@ __PRETTY_FUNCTION__ = void a::sub(int)
 @end smallexample
 
 These identifiers are variables, not preprocessor macros, and may not
-be used to initialize @code{char} arrays or be concatenated with other string
+be used to initialize @code{char} arrays or be concatenated with string
 literals.
 
 @node Return Address
@@ -11091,22 +11094,50 @@ means that the compiler can assume for @code{x}, set to @code{arg}, that
 @end deftypefn
 
 @deftypefn {Built-in Function} int __builtin_LINE ()
-This function is the equivalent to the preprocessor @code{__LINE__}
-macro and returns the line number of the invocation of the built-in.
-In a C++ default argument for a function @var{F}, it gets the line number of
-the call to @var{F}.
+This function is the equivalent of the preprocessor @code{__LINE__}
+macro and returns a constant integer expression that evaluates to
+the line number of the invocation of the built-in.  When used as a C++
+default argument for a function @var{F}, it returns the line number
+of the call to @var{F}.
 @end deftypefn
 
 @deftypefn {Built-in Function} {const char *} __builtin_FUNCTION ()
-This function is the equivalent to the preprocessor @code{__FUNCTION__}
-macro and returns the function name the invocation of the built-in is in.
+This function is the equivalent of the @code{__FUNCTION__} symbol
+and returns an address constant pointing to the name of the function
+from which the built-in was invoked, or the empty string if
+the invocation is not at function scope.  When used as a C++ default
+argument for a function @var{F}, it returns the name of @var{F}'s
+caller or the empty string if the call was not made at function
+scope.
 @end deftypefn
 
 @deftypefn {Built-in Function} {const char *} __builtin_FILE ()
-This function is the equivalent to the preprocessor @code{__FILE__}
-macro and returns the file name the invocation of the built-in is in.
-In a C++ default argument for a function @var{F}, it gets the file name of
-the call to @var{F}.
+This function is the equivalent of the preprocessor @code{__FILE__}
+macro and returns an address constant pointing to the file name
+containing the invocation of the built-in, or the empty string if
+the invocation is not at function scope.  When used as a C++ default
+argument for a function @var{F}, it returns the file name of the call
+to @var{F} or the empty string if the call was not made at function
+scope.
+
+For example, in the following, each call to function @code{foo} will
+print a line similar to @code{"file.c:123: foo: message"} with the name
+of the file and the line number of the @code{printf} call, the name of
+the function @code{foo}, followed by the word @code{message}.
+
+@smallexample
+const char*
+function (const char *func = __builtin_FUNCTION ())
+@{
+  return func;
+@}
+
+void foo (void)
+@{
+  printf ("%s:%i: %s: message\n", file (), line (), function ());
+@}
+@end smallexample
+
 @end deftypefn
 
 @deftypefn {Built-in Function} void __builtin___clear_cache (char *@var{begin}, char *@var{end})
index 9fe9bd5ed89838eba0177f6f0742af3a73d7921f..f13980d80bed90ac1b772e9eb91ae1538b2569cb 100644 (file)
@@ -2437,25 +2437,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
            }
          break;
        }
-      case BUILT_IN_LINE:
-       {
-         *expr_p = build_int_cst (TREE_TYPE (*expr_p),
-                                  LOCATION_LINE (EXPR_LOCATION (*expr_p)));
-         return GS_OK;
-       }
-      case BUILT_IN_FILE:
-       {
-         const char *locfile = LOCATION_FILE (EXPR_LOCATION (*expr_p));
-         *expr_p = build_string_literal (strlen (locfile) + 1, locfile);
-         return GS_OK;
-       }
-      case BUILT_IN_FUNCTION:
-       {
-         const char *function;
-         function = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
-         *expr_p = build_string_literal (strlen (function) + 1, function);
-         return GS_OK;
-       }
+
       default:
         ;
       }
index 59e5be84d8c62cb2326a363b9a1f4016637fbe52..b83de7369fd58c53a4668f193e3df96eb45fe968 100644 (file)
@@ -1,3 +1,9 @@
+2016-05-03  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/66561
+       * c-c++-common/builtin_location.c: New test.
+       * g++.dg/cpp1y/builtin_location.C: New test.
+
 2016-05-03  Marek Polacek  <polacek@redhat.com>
 
        PR c/70859
diff --git a/gcc/testsuite/c-c++-common/builtin_location.c b/gcc/testsuite/c-c++-common/builtin_location.c
new file mode 100644 (file)
index 0000000..f3bcd17
--- /dev/null
@@ -0,0 +1,57 @@
+/* PR c++/66561 - __builtin_LINE at al. should yield constant expressions */
+/* { dg-do compile } */
+
+#if __cplusplus >= 201103L
+#  define Assert(expr) static_assert ((expr), #expr)
+#elif __STDC_VERSION__ >= 201112L
+#  define Assert(expr) _Static_assert ((expr), #expr)
+#else
+#  define CONCAT(a, b)  a ## b
+#  define CAT(a, b)     CONCAT (a, b)
+#  define Assert(expr)  typedef int CAT (Assert_, __LINE__) [1 - 2 * !(expr)]
+#endif
+
+/* Verify (in C) that __builtin_FILE() yields an address constant.
+   This test is ineffective in C++ where initializers of global
+   objects need not be constant expressions.  */
+const char* const file = __builtin_FILE ();
+
+/* Verify (in C) that __builtin_FUNCTION() yields an address constant.  */
+const char* const function = __builtin_FUNCTION ();
+
+/* Also verify that __builtin_constant_p() returns true for both.  */
+Assert (__builtin_constant_p (__builtin_FILE ()));
+Assert (__builtin_constant_p (__builtin_FUNCTION ()));
+       
+/* Verify (in both C and C++ 11 and later) that both __builtin_FILE ()
+   and __builtin_FUNCTION() yield an address constant by making use
+   of a GCC extension that allows operands of arithmetic constant
+   expressions to be address constants.  (Subtracting two literals
+   from one another is undefined in both C and C++ and should be
+   diagnosed.  See c/70772.)  */
+
+#pragma GCC diagnostic push  
+#pragma GCC diagnostic ignored "-Waddress"
+
+enum E0 {
+  e0 = __FILE__ - __FILE__,
+  e1 = __builtin_FILE () - __builtin_FILE (),
+
+#if !__cplusplus || __cplusplus >= 201103L
+  /* Skip this test in C++ 98 where GCC rejects __FUNCTION__ in constant
+     expressions.  */
+  e2 = __FUNCTION__ - __FUNCTION__,
+  e3 = __builtin_FUNCTION () - __builtin_FUNCTION ()
+
+#endif
+};
+
+#pragma GCC diagnostic pop
+
+/* Verify that __builtin_LINE () yields an integer constant expression.  */
+#line 13
+int a [__builtin_LINE ()][__builtin_LINE ()];
+enum F { f0 = __builtin_LINE () };
+struct S { unsigned bitfield: __builtin_LINE (); } s;
+
+Assert (__builtin_constant_p (__builtin_LINE ()));
diff --git a/gcc/testsuite/g++.dg/cpp1y/builtin_location.C b/gcc/testsuite/g++.dg/cpp1y/builtin_location.C
new file mode 100644 (file)
index 0000000..b3b9b43
--- /dev/null
@@ -0,0 +1,175 @@
+// PR c++/66561 - __builtin_LINE at al. should yield constant expressions
+// { dg-do compile { target c++11 } }
+#define A(expr) static_assert ((expr), #expr)
+
+#define FILE_1 "file_name.suffix"
+#define FILE_2 "some_other_file_name.suffix"
+
+#line 1 FILE_1
+constexpr const char*
+file1 ()
+{
+#if __cplusplus >= 201402L
+  // Do extra checking in C++ 14 and later.
+  constexpr const char *f1 = __FILE__;
+  constexpr const char *f2 = __builtin_FILE ();
+  A (0 == __builtin_strcmp (f1, f2));
+  return f1;
+#else
+  // In C++ 11, a constexpr function body must consist of a single
+  // return statement and no declaratations.
+  return __builtin_FILE ();
+#endif  
+}
+
+#line 1 FILE_2
+constexpr const char*
+file2 ()
+{
+#if __cplusplus >= 201402L
+  constexpr const char *f1 = __FILE__;
+  constexpr const char *f2 = __builtin_FILE ();
+  A (0 == __builtin_strcmp (f1, f2));
+  return f1;
+#else
+  return __builtin_FILE ();
+#endif
+}
+
+#line 1 "bogus file name"
+constexpr const char*
+this_file (const char *fname = __builtin_FILE ())
+{
+  return fname;
+}
+
+constexpr const char*
+function ()
+{
+#if __cplusplus >= 201402L
+  constexpr const char *f1 = __FUNCTION__;
+  constexpr const char *f2 = __builtin_FUNCTION ();
+  A (0 == __builtin_strcmp (f1, f2));
+  return f1;
+#else
+  return __builtin_FUNCTION ();
+#endif
+}
+
+constexpr const char*
+this_function (const char *func = __builtin_FUNCTION ())
+{
+  return func;
+}
+
+constexpr int
+line ()
+{
+#if __cplusplus >= 201402L
+#line 123
+  constexpr int n1 = __LINE__;
+  constexpr int n2 = __builtin_LINE ();
+  A (123 == n1);
+  A (n1 + 1 == n2);
+  return n2;
+#else
+#line 123
+  // Newline.
+  return __builtin_LINE ();
+#endif
+}
+
+constexpr int
+this_line (int line = __builtin_LINE ())
+{
+  return line;
+}
+
+
+// Exercise __builtin_FILE().
+#line 1 "foobar"
+constexpr const char* f1 = file1 ();
+A (0 == __builtin_strcmp (f1, FILE_1));
+
+#line 2 "foobar"
+constexpr const char* f2 = file2 ();
+A (0 == __builtin_strcmp (f2, FILE_2));
+
+#define FILE_3 "this_file_name_right_here.this_suffix"
+#line 1 FILE_3
+constexpr const char* f3 = this_file ();
+A (0 == __builtin_strcmp (f3, FILE_3));
+
+#define FILE_4 "next_file_name.another_suffix"
+#line 1 "foobar"
+constexpr const char* f4 = this_file
+  (
+#line 1 FILE_4
+   )
+#line 1 "foobar"
+  ;
+A (0 == __builtin_strcmp (f4, FILE_4));
+
+
+// Exercise __builtin_FUNCTION().
+
+// Verify that __builtin_FUNCTION() returns the name of the function
+// in which it is called.
+constexpr const char* fun1 = function ();
+A (0 == __builtin_strcmp (fun1, "function"));
+
+// Verify that __builtin_FUNCTION() returns the empty string when
+// it's invoked to set the default argument value in a function
+// called at file scope.
+constexpr const char* fun2 = this_function ();
+A (0 == __builtin_strcmp (fun2, ""));
+
+constexpr const char*
+named_function ()
+{
+  return this_function ();
+}
+
+constexpr const char* fun3 = named_function ();
+A (0 == __builtin_strcmp (fun3, "named_function"));
+
+
+// Exercise __builtin_LINE().
+// Verify the line numbe returned by the built-in.
+#line 4
+constexpr int n1 = __builtin_LINE ();
+A (n1 == 4);
+
+// Verify the line number obtained by a constexpr function.
+#line 5
+constexpr int n2 = line ();
+A (n2 == 124);
+
+// Verify the line number determined by the default argument.
+#line 6
+constexpr int n3 = this_line ();
+A (n3 == 6);
+
+// Verify that the line number accounts for each of the calls.
+#line 7
+constexpr int n4 = this_line () + this_line ();
+A (n4 == 14);
+
+// Verify that the line number accounts for each of the calls when
+// split over multiple lines.
+#line 1
+constexpr int n5 = this_line ()
+#line 8
+  + this_line ();
+A (n5 == 9);
+
+// Verify that the line number corresponds to the closing parenthesis
+// of the function call.
+#line 1
+constexpr int n6 = this_line
+  (
+#line 99
+   )
+#line 1
+  ;
+A (n6 == 99);