aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2021-01-14 22:14:38 -0500
committerMarek Polacek <polacek@redhat.com>2021-01-19 17:13:00 -0500
commitd89b00c095e99cd5cb6d3e05f30d3a61fa592000 (patch)
tree88c70d0ec39f9ee8978aea8ff133a4deed603301 /gcc
parent9693e255ee2536c6823640eba5d0163c2b401161 (diff)
downloadgcc-d89b00c095e99cd5cb6d3e05f30d3a61fa592000.zip
gcc-d89b00c095e99cd5cb6d3e05f30d3a61fa592000.tar.gz
gcc-d89b00c095e99cd5cb6d3e05f30d3a61fa592000.tar.bz2
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/name-lookup.c103
-rw-r--r--gcc/cp/name-lookup.h2
-rw-r--r--gcc/cp/pt.c3
-rw-r--r--gcc/testsuite/g++.dg/lookup/using64.C69
-rw-r--r--gcc/testsuite/g++.dg/lookup/using65.C17
5 files changed, 145 insertions, 49 deletions
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index b4b6c0b..843e5f3 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 bac3fa7..75db5b3 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 9571401..12d0840 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 0000000..a50cd273
--- /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 <typename T>
+ bool operator==(T, int);
+
+ template <typename T>
+ void X(T);
+}
+
+namespace M {
+ template <typename T>
+ bool operator==(T, double);
+}
+
+template<typename T>
+bool fn1 (T t)
+{
+ using N::operator==;
+ return t == 1;
+}
+
+template<typename T>
+bool fn2 (T t)
+{
+ // Redeclaration.
+ using N::operator==;
+ using N::operator==;
+ return t == 1;
+}
+
+template<typename T>
+bool fn3 (T t)
+{
+ // Need update_local_overload.
+ using N::operator==;
+ using M::operator==;
+ return t == 1;
+}
+
+template<typename T>
+void fn4 (T)
+{
+ struct X { };
+ using N::X;
+ X(1);
+}
+
+template<typename T>
+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 0000000..bc6c086
--- /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 <typename> void log1p();
+}
+template <typename> struct log1p_impl {
+ static int run() {
+ using std::log1p;
+ using std_fallback::log1p;
+ return 0;
+ }
+};
+void log1p() { log1p_impl<int>::run(); }