PR c++/66561 - __builtin_LINE at al. should yield constant expressions
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
This commit is contained in:
parent
9663f8f748
commit
b25aad5fda
|
@ -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>
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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:
|
||||
;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ()));
|
|
@ -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);
|
Loading…
Reference in New Issue