re PR c++/64266 (Can GCC produce local mergeable symbols for *.__FUNCTION__ and *.__PRETTY_FUNCTION__ functions?)
PR c++/64266 PR c++/70353 Core issue 1962 * decl.c (cp_fname_init): Decay the initializer to pointer. (cp_make_fname_decl): Set DECL_DECLARED_CONSTEXPR_P, DECL_VALUE_EXPR, DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P. Don't call cp_finish_decl. * pt.c (tsubst_expr) [DECL_EXPR]: Set DECL_VALUE_EXPR, DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P. Don't call cp_finish_decl. * constexpr.c (cxx_eval_constant_expression) [VAR_DECL]: Handle DECL_VALUE_EXPR. Co-Authored-By: Martin Liska <mliska@suse.cz> From-SVN: r234484
This commit is contained in:
parent
31ce75c698
commit
d7796e23a4
@ -1,3 +1,18 @@
|
||||
2016-03-25 Jason Merrill <jason@redhat.com>
|
||||
Martin Liška <mliska@suse.cz>
|
||||
|
||||
PR c++/64266
|
||||
PR c++/70353
|
||||
Core issue 1962
|
||||
* decl.c (cp_fname_init): Decay the initializer to pointer.
|
||||
(cp_make_fname_decl): Set DECL_DECLARED_CONSTEXPR_P,
|
||||
DECL_VALUE_EXPR, DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P.
|
||||
Don't call cp_finish_decl.
|
||||
* pt.c (tsubst_expr) [DECL_EXPR]: Set DECL_VALUE_EXPR,
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P. Don't call cp_finish_decl.
|
||||
* constexpr.c (cxx_eval_constant_expression) [VAR_DECL]:
|
||||
Handle DECL_VALUE_EXPR.
|
||||
|
||||
2016-03-24 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/70386
|
||||
|
@ -3363,6 +3363,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
|
||||
return (*ctx->values->get (t));
|
||||
|
||||
case VAR_DECL:
|
||||
if (DECL_HAS_VALUE_EXPR_P (t))
|
||||
return cxx_eval_constant_expression (ctx, DECL_VALUE_EXPR (t), lval,
|
||||
non_constant_p, overflow_p);
|
||||
/* Fall through. */
|
||||
case CONST_DECL:
|
||||
/* We used to not check lval for CONST_DECL, but darwin.c uses
|
||||
CONST_DECL for aggregate constants. */
|
||||
|
@ -4185,13 +4185,15 @@ cp_fname_init (const char* name, tree *type_p)
|
||||
type = cp_build_qualified_type (char_type_node, TYPE_QUAL_CONST);
|
||||
type = build_cplus_array_type (type, domain);
|
||||
|
||||
*type_p = type;
|
||||
*type_p = type_decays_to (type);
|
||||
|
||||
if (init)
|
||||
TREE_TYPE (init) = type;
|
||||
else
|
||||
init = error_mark_node;
|
||||
|
||||
init = decay_conversion (init, tf_warning_or_error);
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
@ -4217,12 +4219,20 @@ cp_make_fname_decl (location_t loc, tree id, int type_dep)
|
||||
/* As we're using pushdecl_with_scope, we must set the context. */
|
||||
DECL_CONTEXT (decl) = current_function_decl;
|
||||
|
||||
TREE_STATIC (decl) = 1;
|
||||
TREE_READONLY (decl) = 1;
|
||||
DECL_ARTIFICIAL (decl) = 1;
|
||||
DECL_DECLARED_CONSTEXPR_P (decl) = 1;
|
||||
|
||||
TREE_USED (decl) = 1;
|
||||
|
||||
if (init)
|
||||
{
|
||||
SET_DECL_VALUE_EXPR (decl, init);
|
||||
DECL_HAS_VALUE_EXPR_P (decl) = 1;
|
||||
/* For decl_constant_var_p. */
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
|
||||
}
|
||||
|
||||
if (current_function_decl)
|
||||
{
|
||||
cp_binding_level *b = current_binding_level;
|
||||
@ -4231,13 +4241,12 @@ cp_make_fname_decl (location_t loc, tree id, int type_dep)
|
||||
while (b->level_chain->kind != sk_function_parms)
|
||||
b = b->level_chain;
|
||||
pushdecl_with_scope (decl, b, /*is_friend=*/false);
|
||||
cp_finish_decl (decl, init, /*init_const_expr_p=*/false, NULL_TREE,
|
||||
LOOKUP_ONLYCONVERTING);
|
||||
add_decl_expr (decl);
|
||||
}
|
||||
else
|
||||
{
|
||||
DECL_THIS_STATIC (decl) = true;
|
||||
pushdecl_top_level_and_finish (decl, init);
|
||||
pushdecl_top_level_and_finish (decl, NULL_TREE);
|
||||
}
|
||||
|
||||
return decl;
|
||||
|
26
gcc/cp/pt.c
26
gcc/cp/pt.c
@ -15194,21 +15194,25 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
|
||||
DECL_CONTEXT (decl) = current_function_decl;
|
||||
cp_check_omp_declare_reduction (decl);
|
||||
}
|
||||
else if (VAR_P (decl)
|
||||
&& DECL_PRETTY_FUNCTION_P (decl))
|
||||
{
|
||||
/* For __PRETTY_FUNCTION__ we have to adjust the
|
||||
initializer. */
|
||||
const char *const name
|
||||
= cxx_printable_name (current_function_decl, 2);
|
||||
init = cp_fname_init (name, &TREE_TYPE (decl));
|
||||
SET_DECL_VALUE_EXPR (decl, init);
|
||||
DECL_HAS_VALUE_EXPR_P (decl) = 1;
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
|
||||
maybe_push_decl (decl);
|
||||
}
|
||||
else
|
||||
{
|
||||
int const_init = false;
|
||||
maybe_push_decl (decl);
|
||||
if (VAR_P (decl)
|
||||
&& DECL_PRETTY_FUNCTION_P (decl))
|
||||
{
|
||||
/* For __PRETTY_FUNCTION__ we have to adjust the
|
||||
initializer. */
|
||||
const char *const name
|
||||
= cxx_printable_name (current_function_decl, 2);
|
||||
init = cp_fname_init (name, &TREE_TYPE (decl));
|
||||
}
|
||||
else
|
||||
init = tsubst_init (init, decl, args, complain, in_decl);
|
||||
|
||||
init = tsubst_init (init, decl, args, complain, in_decl);
|
||||
|
||||
if (VAR_P (decl))
|
||||
const_init = (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P
|
||||
|
10
gcc/testsuite/g++.dg/cpp0x/constexpr-__func__2.C
Normal file
10
gcc/testsuite/g++.dg/cpp0x/constexpr-__func__2.C
Normal file
@ -0,0 +1,10 @@
|
||||
// PR c++/70353
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
constexpr const char* ce ()
|
||||
{
|
||||
return __func__;
|
||||
}
|
||||
|
||||
#define SA(X) static_assert((X),#X)
|
||||
SA(ce()[0] == 'c');
|
33
gcc/testsuite/g++.dg/ext/fnname5.C
Normal file
33
gcc/testsuite/g++.dg/ext/fnname5.C
Normal file
@ -0,0 +1,33 @@
|
||||
// PR c++/64266
|
||||
/* { dg-do compile } */
|
||||
|
||||
extern "C" int printf (const char *, ...);
|
||||
|
||||
struct A
|
||||
{
|
||||
void foo(int i)
|
||||
{
|
||||
printf ("__FUNCTION__ = %s\n", __FUNCTION__);
|
||||
printf ("__PRETTY_FUNCTION__ = %s\n", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void foo()
|
||||
{
|
||||
printf ("__FUNCTION__ = %s\n", __FUNCTION__);
|
||||
}
|
||||
};
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
A a;
|
||||
a.foo (0);
|
||||
a.foo ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-assembler-not "_ZZN1A3fooEvE12__FUNCTION__" } } */
|
||||
/* { dg-final { scan-assembler-not "_ZZN1A3fooEiE12__FUNCTION__" } } */
|
||||
/* { dg-final { scan-assembler-not "_ZZN1A3fooEiE19__PRETTY_FUNCTION__" } } */
|
||||
/* { dg-final { scan-assembler ".string \"void A::foo\\(int\\)\"" } } */
|
||||
/* { dg-final { scan-assembler ".string \"foo\"" } } */
|
@ -1,85 +0,0 @@
|
||||
// { dg-do run }
|
||||
// Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
// Contributed by Nathan Sidwell 3 Mar 2000 <nathan@codesourcery.com>
|
||||
|
||||
// __PRETTY_FUNCTION__, __FUNCTION__ and __function__ should have the
|
||||
// type char const [X], where X is the right value for that particular function
|
||||
|
||||
static void const *strings[4];
|
||||
static void const *tpls[4];
|
||||
static unsigned pos = 0;
|
||||
static int fail;
|
||||
static void const *ptr = 0;
|
||||
|
||||
void unover (char const (*)[5]) {}
|
||||
void foo (char const (*)[5]) {}
|
||||
void foo (void *) {fail = 1;}
|
||||
void foo (void const *) {fail = 1;}
|
||||
void baz (char const (&)[5]) {}
|
||||
|
||||
template<unsigned I> void PV (char const (&objRef)[I])
|
||||
{
|
||||
strings[pos] = objRef;
|
||||
tpls[pos] = __PRETTY_FUNCTION__;
|
||||
pos++;
|
||||
}
|
||||
|
||||
void fn ()
|
||||
{
|
||||
PV (__FUNCTION__);
|
||||
PV (__func__);
|
||||
PV (__PRETTY_FUNCTION__);
|
||||
PV ("wibble");
|
||||
}
|
||||
|
||||
void baz ()
|
||||
{
|
||||
ptr = __FUNCTION__;
|
||||
// there should be no string const merging
|
||||
if (ptr == "baz")
|
||||
fail = 1;
|
||||
// but all uses should be the same.
|
||||
if (ptr != __FUNCTION__)
|
||||
fail = 1;
|
||||
}
|
||||
int baz (int)
|
||||
{
|
||||
return ptr == __FUNCTION__;
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
// make sure we actually emit the VAR_DECL when needed, and things have the
|
||||
// expected type.
|
||||
foo (&__FUNCTION__);
|
||||
baz (__FUNCTION__);
|
||||
unover (&__FUNCTION__);
|
||||
if (fail)
|
||||
return 1;
|
||||
|
||||
// __FUNCTION__ should be unique across functions with the same base name
|
||||
// (it's a local static, _not_ a string).
|
||||
baz ();
|
||||
if (fail)
|
||||
return 1;
|
||||
if (baz (1))
|
||||
return 1;
|
||||
fn ();
|
||||
|
||||
// Check the names of fn. They should all be distinct strings (though two
|
||||
// will have the same value).
|
||||
if (strings[0] == strings[1])
|
||||
return 1;
|
||||
if (strings[0] == strings[2])
|
||||
return 1;
|
||||
if (strings[1] == strings[2])
|
||||
return 1;
|
||||
|
||||
// check the names of the template functions so invoked
|
||||
if (tpls[0] != tpls[1])
|
||||
return 1;
|
||||
if (tpls[0] == tpls[2])
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user