On 6/3/25 12:29 PM, Iain Sandoe wrote:
Hi Jason,
a bootstrap + testsuite (but without Ada or D).
Hmm, it looks like make_typename_type wants to call lookup_template_class with
a class as CONTEXT.
But it first does the lookup separately.
So I read that to indicate this does not need addressing (at this point) - we
could extend it to allow class contexts.
So I guess it makes sense to say that passing an identifier and context is only
supported if context is a namespace.
Done.
+ If D1 is an identifier and CONTEXT is non-NULL, then the lookup is
+ carried out in the CONTEXT namespace, otherwise CONTEXT is ignored and
+ lookup is carried out with default priority.
This "otherwise" blurs two different cases: D1 is an id and CONTEXT is NULL (in
which case lookup selects the innermost non-namespace binding), or D1 is not an id (in
which case CONTEXT is ignored and no lookup is performed).
Fixed
Let's also remove the FUNCTION_CONTEXT paragraph.
Done
I guess we should stop passing the CONTEXT argument in non-id+ns cases such as
make_typename_type and tsubst...
I have not tried to address caller-side changes.
+ templ = maybe_get_template_decl_from_type_decl (templ);
This line is unnecessary for namespace lookup, it's just for the
injected-class-name.
Thanks, fixed.
re-tested on x86_64-darwin, powerpc64le is still running, how does it look now?
OK.
thanks
Iain
--- 8< ---
In the reported issues, using lookup_template_class () directly on (for example)
the coroutine_handle identifier fails because a class-local TYPE_DECL is found.
This is because, in the existing code, lookup is called with default parameters
which means that class contexts are examined first.
Fix this, when a context is provided by the caller, by doing lookup in namespace
provided.
PR c++/120495
PR c++/115605
gcc/cp/ChangeLog:
* pt.cc (lookup_template_class): Honour provided namespace contexts
when looking up class templates.
gcc/testsuite/ChangeLog:
* g++.dg/coroutines/pr120495.C: New test.
* g++.dg/pr115605.C: New test.
Signed-off-by: Iain Sandoe <i...@sandoe.co.uk>
---
gcc/cp/pt.cc | 30 +++++++-----
gcc/testsuite/g++.dg/coroutines/pr120495.C | 55 ++++++++++++++++++++++
gcc/testsuite/g++.dg/pr115605.C | 10 ++++
3 files changed, 84 insertions(+), 11 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/coroutines/pr120495.C
create mode 100644 gcc/testsuite/g++.dg/pr115605.C
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index c5a3abe6d8b..3c8fa9a6728 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10052,15 +10052,20 @@ tsubst_entering_scope (tree t, tree args,
tsubst_flags_t complain, tree in_decl)
D1 is the PTYPENAME terminal, and ARGLIST is the list of arguments.
+ If D1 is an identifier and CONTEXT is non-NULL, then the lookup is
+ carried out in CONTEXT. Currently, only namespaces are supported for
+ CONTEXT.
+
+ If D1 is an identifier and CONTEXT is NULL, the lookup is performed
+ in the innermost non-namespace binding.
+
+ Otherwise CONTEXT is ignored and no lookup is carried out.
+
IN_DECL, if non-NULL, is the template declaration we are trying to
instantiate.
Issue error and warning messages under control of COMPLAIN.
- If the template class is really a local class in a template
- function, then the FUNCTION_CONTEXT is the function in which it is
- being instantiated.
-
??? Note that this function is currently called *twice* for each
template-id: the first time from the parser, while creating the
incomplete type (finish_template_type), and the second type during the
@@ -10079,20 +10084,23 @@ lookup_template_class (tree d1, tree arglist, tree
in_decl, tree context,
spec_entry **slot;
spec_entry *entry;
- if (identifier_p (d1))
+ if (identifier_p (d1) && context)
+ {
+ gcc_checking_assert (TREE_CODE (context) == NAMESPACE_DECL);
+ push_decl_namespace (context);
+ templ = lookup_name (d1, LOOK_where::NAMESPACE, LOOK_want::NORMAL);
+ pop_decl_namespace ();
+ }
+ else if (identifier_p (d1))
{
tree value = innermost_non_namespace_value (d1);
if (value && DECL_TEMPLATE_TEMPLATE_PARM_P (value))
templ = value;
else
- {
- if (context)
- push_decl_namespace (context);
+ {
templ = lookup_name (d1);
templ = maybe_get_template_decl_from_type_decl (templ);
- if (context)
- pop_decl_namespace ();
- }
+ }
}
else if (TREE_CODE (d1) == TYPE_DECL && MAYBE_CLASS_TYPE_P (TREE_TYPE (d1)))
{
diff --git a/gcc/testsuite/g++.dg/coroutines/pr120495.C
b/gcc/testsuite/g++.dg/coroutines/pr120495.C
new file mode 100644
index 00000000000..f59c34a8676
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr120495.C
@@ -0,0 +1,55 @@
+// { dg-additional-options "-fsyntax-only" }
+
+#include <coroutine>
+#include <exception>
+
+struct fire_and_forget {
+};
+
+template <typename... Args>
+struct std::coroutine_traits<fire_and_forget, Args...>
+{
+ struct promise_type
+ {
+ fire_and_forget get_return_object() const noexcept
+ {
+ return{};
+ }
+
+ void return_void() const noexcept
+ {
+ }
+
+ suspend_never initial_suspend() const noexcept
+ {
+ return{};
+ }
+
+ suspend_never final_suspend() const noexcept
+ {
+ return{};
+ }
+
+ void unhandled_exception() const noexcept
+ {
+ std::terminate();
+ }
+ };
+};
+
+struct foo
+{
+ fire_and_forget bar()
+ {
+ co_await std::suspend_always{ };
+ }
+
+private:
+ // The line below triggered the error.
+ using coroutine_handle = std::coroutine_handle<>;
+};
+
+int main()
+{
+ foo{}.bar();
+}
diff --git a/gcc/testsuite/g++.dg/pr115605.C b/gcc/testsuite/g++.dg/pr115605.C
new file mode 100644
index 00000000000..9e342555c89
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr115605.C
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++20 } }
+
+#include <array>
+
+int foo() {
+ int const tuple_size = 5;
+ std::array<int, 3> array {1, 2, 3};
+ auto [a, b, c] = array;
+ return c;
+}