Skip to content

Commit

Permalink
c++: constexpr error with fn redecl in local scope [PR111132]
Browse files Browse the repository at this point in the history
We evaluate constexpr functions on the original, pre-genericization bodies.
That means that the function body we're evaluating will not have gone
through cp_genericize_r's "Map block scope extern declarations to visible
declarations with the same name and type in outer scopes if any".  Here:

  constexpr bool bar() { return true; } // #1
  constexpr bool foo() {
    constexpr bool bar(void); // rust-lang#2
    return bar();
  }

it means that we:
1) register_constexpr_fundef (#1)
2) cp_genericize (#1)
   nothing interesting happens
3) register_constexpr_fundef (foo)
   does copy_fn, so we have two copies of the BIND_EXPR
4) cp_genericize (foo)
   this remaps rust-lang#2 to #1, but only on one copy of the BIND_EXPR
5) retrieve_constexpr_fundef (foo)
   we find it, no problem
6) retrieve_constexpr_fundef (rust-lang#2)
   and here rust-lang#2 isn't found in constexpr_fundef_table, because
   we're working on the BIND_EXPR copy where rust-lang#2 wasn't mapped to #1
   so we fail.  We've only registered #1.

It should work to use DECL_LOCAL_DECL_ALIAS (which used to be
extern_decl_map).  We evaluate constexpr functions on pre-cp_fold
bodies to avoid diagnostic problems, but the remapping I'm proposing
should not interfere with diagnostics.

This is not a problem for a global scope redeclaration; there we go
through duplicate_decls which keeps the DECL_UID:
  DECL_UID (olddecl) = olddecl_uid;
and DECL_UID is what constexpr_fundef_hasher::hash uses.

	PR c++/111132

gcc/cp/ChangeLog:

	* constexpr.cc (get_function_named_in_call): Use
	cp_get_fndecl_from_callee.
	* cvt.cc (cp_get_fndecl_from_callee): If there's a
	DECL_LOCAL_DECL_ALIAS, use it.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/constexpr-redeclaration3.C: New test.
	* g++.dg/cpp0x/constexpr-redeclaration4.C: New test.
  • Loading branch information
mpolacek committed Apr 5, 2024
1 parent a844095 commit 8c90638
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 8 deletions.
10 changes: 4 additions & 6 deletions gcc/cp/constexpr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -702,16 +702,14 @@ build_constexpr_constructor_member_initializers (tree type, tree body)

/* We have an expression tree T that represents a call, either CALL_EXPR
or AGGR_INIT_EXPR. If the call is lexically to a named function,
retrun the _DECL for that function. */
return the _DECL for that function. */

static tree
get_function_named_in_call (tree t)
{
tree fun = cp_get_callee (t);
if (fun && TREE_CODE (fun) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (fun, 0)) == FUNCTION_DECL)
fun = TREE_OPERAND (fun, 0);
return fun;
tree callee = cp_get_callee (t);
tree fun = cp_get_fndecl_from_callee (callee, /*fold*/false);
return fun ? fun : callee;
}

/* Subroutine of check_constexpr_fundef. BODY is the body of a function
Expand Down
18 changes: 16 additions & 2 deletions gcc/cp/cvt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1001,8 +1001,22 @@ cp_get_fndecl_from_callee (tree fn, bool fold /* = true */)
{
if (fn == NULL_TREE)
return fn;

/* We evaluate constexpr functions on the original, pre-genericization
bodies. So block-scope extern declarations have not been mapped to
declarations in outer scopes. Use the namespace-scope declaration,
if any, so that retrieve_constexpr_fundef can find it (PR111132). */
auto fn_or_local_alias = [] (tree f)
{
if (DECL_LOCAL_DECL_P (f))
if (tree alias = DECL_LOCAL_DECL_ALIAS (f))
if (alias != error_mark_node)
return alias;
return f;
};

if (TREE_CODE (fn) == FUNCTION_DECL)
return fn;
return fn_or_local_alias (fn);
tree type = TREE_TYPE (fn);
if (type == NULL_TREE || !INDIRECT_TYPE_P (type))
return NULL_TREE;
Expand All @@ -1013,7 +1027,7 @@ cp_get_fndecl_from_callee (tree fn, bool fold /* = true */)
|| TREE_CODE (fn) == FDESC_EXPR)
fn = TREE_OPERAND (fn, 0);
if (TREE_CODE (fn) == FUNCTION_DECL)
return fn;
return fn_or_local_alias (fn);
return NULL_TREE;
}

Expand Down
13 changes: 13 additions & 0 deletions gcc/testsuite/g++.dg/cpp0x/constexpr-redeclaration3.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// PR c++/111132
// { dg-do compile { target c++11 } }

constexpr bool bar(void) {
return true;
}

constexpr bool foo() {
constexpr bool bar(void);
return bar();
}

static_assert(foo(), "");
14 changes: 14 additions & 0 deletions gcc/testsuite/g++.dg/cpp0x/constexpr-redeclaration4.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// PR c++/111132
// { dg-do compile { target c++11 } }

constexpr bool bar(void) {
return true;
}

constexpr bool bar(void);

constexpr bool foo() {
return bar();
}

static_assert(foo(), "");

0 comments on commit 8c90638

Please sign in to comment.