From d89b00c095e99cd5cb6d3e05f30d3a61fa592000 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Thu, 14 Jan 2021 22:14:38 -0500 Subject: [PATCH] c++: ICE with USING_DECL redeclaration [PR98687] My recent patch that introduced push_using_decl_bindings didn't handle USING_DECL redeclaration, therefore things broke. This patch amends that by breaking out a part of finish_nonmember_using_decl out to a separate function, push_using_decl_bindings, and calling it. It needs an overload, because name_lookup is only available inside of name-lookup.c. gcc/cp/ChangeLog: PR c++/98687 * name-lookup.c (push_using_decl_bindings): New, broken out of... (finish_nonmember_using_decl): ...here. * name-lookup.h (push_using_decl_bindings): Update declaration. * pt.c (tsubst_expr): Update the call to push_using_decl_bindings. gcc/testsuite/ChangeLog: PR c++/98687 * g++.dg/lookup/using64.C: New test. * g++.dg/lookup/using65.C: New test. --- gcc/cp/name-lookup.c | 103 ++++++++++++++------------ gcc/cp/name-lookup.h | 2 +- gcc/cp/pt.c | 3 +- gcc/testsuite/g++.dg/lookup/using64.C | 69 +++++++++++++++++ gcc/testsuite/g++.dg/lookup/using65.C | 17 +++++ 5 files changed, 145 insertions(+), 49 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lookup/using64.C create mode 100644 gcc/testsuite/g++.dg/lookup/using65.C diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index b4b6c0b81b5..843e5f305c0 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -6279,6 +6279,61 @@ pushdecl_namespace_level (tree x, bool hiding) return t; } +/* Wrapper around push_local_binding to push the bindings for + a non-member USING_DECL with NAME and VALUE. LOOKUP, if non-null, + is the result of name lookup during template parsing. */ + +static void +push_using_decl_bindings (name_lookup *lookup, tree name, tree value) +{ + tree type = NULL_TREE; + + cxx_binding *binding = find_local_binding (current_binding_level, name); + if (binding) + { + value = binding->value; + type = binding->type; + } + + /* DR 36 questions why using-decls at function scope may not be + duplicates. Disallow it, as C++11 claimed and PR 20420 + implemented. */ + if (lookup) + do_nonmember_using_decl (*lookup, true, true, &value, &type); + + if (!value) + ; + else if (binding && value == binding->value) + /* Redeclaration of this USING_DECL. */; + else if (binding && binding->value && TREE_CODE (value) == OVERLOAD) + { + /* We already have this binding, so replace it. */ + update_local_overload (IDENTIFIER_BINDING (name), value); + IDENTIFIER_BINDING (name)->value = value; + } + else + /* Install the new binding. */ + push_local_binding (name, value, /*using=*/true); + + if (!type) + ; + else if (binding && type == binding->type) + ; + else + { + push_local_binding (name, type, /*using=*/true); + set_identifier_type_value (name, type); + } +} + +/* Overload for push_using_decl_bindings that doesn't take a name_lookup. */ + +void +push_using_decl_bindings (tree name, tree value) +{ + push_using_decl_bindings (nullptr, name, value); +} + /* Process a using declaration in non-class scope. */ void @@ -6395,43 +6450,7 @@ finish_nonmember_using_decl (tree scope, tree name) else { add_decl_expr (using_decl); - - cxx_binding *binding = find_local_binding (current_binding_level, name); - tree value = NULL; - tree type = NULL; - if (binding) - { - value = binding->value; - type = binding->type; - } - - /* DR 36 questions why using-decls at function scope may not be - duplicates. Disallow it, as C++11 claimed and PR 20420 - implemented. */ - do_nonmember_using_decl (lookup, true, true, &value, &type); - - if (!value) - ; - else if (binding && value == binding->value) - ; - else if (binding && binding->value && TREE_CODE (value) == OVERLOAD) - { - update_local_overload (IDENTIFIER_BINDING (name), value); - IDENTIFIER_BINDING (name)->value = value; - } - else - /* Install the new binding. */ - push_local_binding (name, value, true); - - if (!type) - ; - else if (binding && type == binding->type) - ; - else - { - push_local_binding (name, type, true); - set_identifier_type_value (name, type); - } + push_using_decl_bindings (&lookup, name, NULL_TREE); } } @@ -9279,14 +9298,4 @@ push_operator_bindings () } } -/* Wrapper around push_local_binding to push the bindings for - a non-member USING_DECL DECL that was found during template parsing. */ - -void -push_using_decl_bindings (tree decl) -{ - push_local_binding (DECL_NAME (decl), USING_DECL_DECLS (decl), - /*using*/true); -} - #include "gt-cp-name-lookup.h" diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index bac3fa71fc9..75db5b38061 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -478,7 +478,7 @@ extern void push_to_top_level (void); extern void pop_from_top_level (void); extern void maybe_save_operator_binding (tree); extern void push_operator_bindings (void); -extern void push_using_decl_bindings (tree); +extern void push_using_decl_bindings (tree, tree); extern void discard_operator_bindings (tree); /* Lower level interface for modules. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 957140115e4..12d084031b1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -18136,7 +18136,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, == tsubst (scope, args, complain, in_decl)); /* We still need to push the bindings so that we can look up this name later. */ - push_using_decl_bindings (decl); + push_using_decl_bindings (DECL_NAME (decl), + USING_DECL_DECLS (decl)); } else if (is_capture_proxy (decl) && !DECL_TEMPLATE_INSTANTIATION (current_function_decl)) diff --git a/gcc/testsuite/g++.dg/lookup/using64.C b/gcc/testsuite/g++.dg/lookup/using64.C new file mode 100644 index 00000000000..a50cd273c89 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/using64.C @@ -0,0 +1,69 @@ +// PR c++/98687 +// { dg-do compile } + +struct S { }; + +namespace N { + template + bool operator==(T, int); + + template + void X(T); +} + +namespace M { + template + bool operator==(T, double); +} + +template +bool fn1 (T t) +{ + using N::operator==; + return t == 1; +} + +template +bool fn2 (T t) +{ + // Redeclaration. + using N::operator==; + using N::operator==; + return t == 1; +} + +template +bool fn3 (T t) +{ + // Need update_local_overload. + using N::operator==; + using M::operator==; + return t == 1; +} + +template +void fn4 (T) +{ + struct X { }; + using N::X; + X(1); +} + +template +void fn5 (T) +{ + int S; + using ::S; + struct S s; +} + +void +g () +{ + S s; + fn1 (s); + fn2 (s); + fn3 (s); + fn4 (s); + fn5 (s); +} diff --git a/gcc/testsuite/g++.dg/lookup/using65.C b/gcc/testsuite/g++.dg/lookup/using65.C new file mode 100644 index 00000000000..bc6c086197f --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/using65.C @@ -0,0 +1,17 @@ +// PR c++/98687 +// { dg-do compile } + +extern "C" namespace std { + double log1p(double); +} +namespace std_fallback { + template void log1p(); +} +template struct log1p_impl { + static int run() { + using std::log1p; + using std_fallback::log1p; + return 0; + } +}; +void log1p() { log1p_impl::run(); } -- 2.30.2