Message ID | 20210115052607.476396-1-polacek@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: ICE with USING_DECL redeclaration [PR98687] | expand |
On 1/15/21 12:26 AM, Marek Polacek wrote: > My recent patch that introduced push_using_decl_bindings didn't > handle USING_DECL redeclaration, therefore things broke. This > patch amends that. Note that I don't know if the other parts of > finish_nonmember_using_decl are needed (e.g. the binding->type > setting) -- I couldn't trigger it by any of my hand-made testcases. I'd expect it to be exercised by something along the lines of struct A { }; void f() { int A; using ::A; struct A a; } Let's factor the code out of finish_nonmember_using_decl rather than copy it. > Sorry for not thinking harder about redeclarations in the original > patch :(. > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? > > gcc/cp/ChangeLog: > > PR c++/98687 > * name-lookup.c (push_using_decl_bindings): If we found an > existing local binding, update it if it's not identical. > > 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 | 20 ++++++++- > gcc/testsuite/g++.dg/lookup/using64.C | 60 +++++++++++++++++++++++++++ > gcc/testsuite/g++.dg/lookup/using65.C | 17 ++++++++ > 3 files changed, 95 insertions(+), 2 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..857d90914ca 100644 > --- a/gcc/cp/name-lookup.c > +++ b/gcc/cp/name-lookup.c > @@ -9285,8 +9285,24 @@ push_operator_bindings () > void > push_using_decl_bindings (tree decl) > { > - push_local_binding (DECL_NAME (decl), USING_DECL_DECLS (decl), > - /*using*/true); > + tree name = DECL_NAME (decl); > + tree value = USING_DECL_DECLS (decl); > + > + cxx_binding *binding = find_local_binding (current_binding_level, name); > + if (binding) > + { > + if (value == binding->value) > + /* Redeclaration of this USING_DECL. */; > + else if (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 (DECL_NAME (decl), value, /*using*/true); > } > > #include "gt-cp-name-lookup.h" > diff --git a/gcc/testsuite/g++.dg/lookup/using64.C b/gcc/testsuite/g++.dg/lookup/using64.C > new file mode 100644 > index 00000000000..42bce331e19 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/lookup/using64.C > @@ -0,0 +1,60 @@ > +// 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 t) > +{ > + struct X { }; > + using N::X; > + X(1); > +} > + > +void > +g () > +{ > + S s; > + fn1 (s); > + fn2 (s); > + fn3 (s); > + fn4 (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 <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(); } > > base-commit: 5fff80fd79c36a1a940b331d20905061d61ee5e6 >
On Mon, Jan 18, 2021 at 05:18:46PM -0500, Jason Merrill wrote: > On 1/15/21 12:26 AM, Marek Polacek wrote: > > My recent patch that introduced push_using_decl_bindings didn't > > handle USING_DECL redeclaration, therefore things broke. This > > patch amends that. Note that I don't know if the other parts of > > finish_nonmember_using_decl are needed (e.g. the binding->type > > setting) -- I couldn't trigger it by any of my hand-made testcases. > > I'd expect it to be exercised by something along the lines of > > struct A { }; > > void f() > { > int A; > using ::A; > struct A a; > } Hmm, I already had a test for the struct stat hack, but I've added this one to using64.C, thanks. > Let's factor the code out of finish_nonmember_using_decl rather than copy > it. Done here. A small complication was that name_lookup is local to name-lookup.c so I had to add an overload to handle this. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? -- >8 -- 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 <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 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 <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(); } base-commit: 7266ff2a243715e20882850b2fc4211ac7db4d34
On 1/19/21 3:47 PM, Marek Polacek wrote: > On Mon, Jan 18, 2021 at 05:18:46PM -0500, Jason Merrill wrote: >> On 1/15/21 12:26 AM, Marek Polacek wrote: >>> My recent patch that introduced push_using_decl_bindings didn't >>> handle USING_DECL redeclaration, therefore things broke. This >>> patch amends that. Note that I don't know if the other parts of >>> finish_nonmember_using_decl are needed (e.g. the binding->type >>> setting) -- I couldn't trigger it by any of my hand-made testcases. >> >> I'd expect it to be exercised by something along the lines of >> >> struct A { }; >> >> void f() >> { >> int A; >> using ::A; >> struct A a; >> } > > Hmm, I already had a test for the struct stat hack, but I've added this one > to using64.C, thanks. > >> Let's factor the code out of finish_nonmember_using_decl rather than copy >> it. > > Done here. A small complication was that name_lookup is local to > name-lookup.c so I had to add an overload to handle this. > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? > > -- >8 -- > 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)); There could still be an overload of push_using_decl_bindings that takes a single argument. OK either way. > } > 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 <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 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 <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(); } > > base-commit: 7266ff2a243715e20882850b2fc4211ac7db4d34 >
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index b4b6c0b81b5..857d90914ca 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -9285,8 +9285,24 @@ push_operator_bindings () void push_using_decl_bindings (tree decl) { - push_local_binding (DECL_NAME (decl), USING_DECL_DECLS (decl), - /*using*/true); + tree name = DECL_NAME (decl); + tree value = USING_DECL_DECLS (decl); + + cxx_binding *binding = find_local_binding (current_binding_level, name); + if (binding) + { + if (value == binding->value) + /* Redeclaration of this USING_DECL. */; + else if (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 (DECL_NAME (decl), value, /*using*/true); } #include "gt-cp-name-lookup.h" diff --git a/gcc/testsuite/g++.dg/lookup/using64.C b/gcc/testsuite/g++.dg/lookup/using64.C new file mode 100644 index 00000000000..42bce331e19 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/using64.C @@ -0,0 +1,60 @@ +// 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 t) +{ + struct X { }; + using N::X; + X(1); +} + +void +g () +{ + S s; + fn1 (s); + fn2 (s); + fn3 (s); + fn4 (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 <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(); }