From: Martin Sebor Date: Tue, 3 May 2016 21:15:28 +0000 (+0000) Subject: PR c++/66561 - __builtin_LINE at al. should yield constant expressions X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b25aad5fda6c3efbb83980fb0f4fb0e2ddd38216;p=gcc.git 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 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 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 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f9950c420f8..36b57ac9620 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2016-05-03 Martin Sebor + + 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 Richard Biener diff --git a/gcc/builtins.c b/gcc/builtins.c index 7d876199bca..476feb1eb16 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -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: diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3bc37e1ba70..b7375189214 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2016-05-03 Martin Sebor + + 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 PR c/70859 diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index d7e9c7b8048..57fc5c1c54c 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -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; diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index daf1297350d..802845dc66f 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -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}) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 9fe9bd5ed89..f13980d80be 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -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: ; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 59e5be84d8c..b83de7369fd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2016-05-03 Martin Sebor + + PR c++/66561 + * c-c++-common/builtin_location.c: New test. + * g++.dg/cpp1y/builtin_location.C: New test. + 2016-05-03 Marek Polacek 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 index 00000000000..f3bcd17d84d --- /dev/null +++ b/gcc/testsuite/c-c++-common/builtin_location.c @@ -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 index 00000000000..b3b9b435b2c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/builtin_location.C @@ -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);