Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
-- >8 --
In
template<class> struct Y {};
namespace N { }
template<auto ns>
void f () {
typename [:ns:]::template Y<int> b; // #1
}
void g () { f<^^N>(); }
no error is given for #1. The problem is that we do lookup_template_class
first which does:
push_decl_namespace (context);
templ = lookup_name (d1, LOOK_where::NAMESPACE, LOOK_want::NORMAL);
pop_decl_namespace ();
which is an unqualified lookup that goes out through the enclosing
namespaces. We should do a qualified lookup in N only. This patch
makes us use lookup_qualified_name to find the TEMPLATE_DECL and then
pass that to lookup_template_class with a null context.
We already have a call to lookup_qualified_name so I just shuffled
the code a bit. Also guard the qualified_name_lookup_error call
with a complain check. And give an error if we didn't get a type
for the cp_build_qualified_type call.
Note that the UNBOUND_CLASS_TEMPLATE case will also need something
similar.
The diagnostic for t9 is currently technically imprecise because
fn is a function template; we should say that it isn't a type template
instead.
PR c++/127349
gcc/cp/ChangeLog:
* pt.cc (lookup_template_class): Print %qE if d1 is not a type.
(tsubst) <case TYPENAME_TYPE>: Do lookup_qualified_name first
before lookup_template_class. Guard qualified_name_lookup_error
with a complain check. Use gcc_checking_assert instead of
gcc_assert. Use identifier_p. Give an error if we didn't get
a type.
gcc/testsuite/ChangeLog:
* g++.dg/reflect/ns7.C: New test.
---
gcc/cp/pt.cc | 51 +++++++++++++++++++-----------
gcc/testsuite/g++.dg/reflect/ns7.C | 38 ++++++++++++++++++++++
2 files changed, 71 insertions(+), 18 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/reflect/ns7.C
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 53e81d8006c..527e2b25b56 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10399,7 +10399,12 @@ lookup_template_class (tree d1, tree arglist, tree
in_decl, tree context,
if (! templ)
{
if (complain & tf_error)
- error ("%qT is not a template", d1);
+ {
+ if (TYPE_P (d1))
+ error ("%qT is not a template", d1);
+ else
+ error ("%qE is not a template", d1);
+ }
return error_mark_node;
}
@@ -17935,30 +17940,40 @@ tsubst (tree t, tree args, tsubst_flags_t complain,
tree in_decl)
a type. */
if (TREE_CODE (ctx) == NAMESPACE_DECL)
{
+ tree id;
+ tree targs = NULL_TREE;
if (TREE_CODE (f) == TEMPLATE_ID_EXPR)
{
- tree d = TREE_OPERAND (f, 0);
- tree n = TREE_OPERAND (f, 1);
- f = lookup_template_class (d, n, in_decl, ctx, complain);
+ id = TREE_OPERAND (f, 0);
+ targs = TREE_OPERAND (f, 1);
+ }
+ else
+ id = f;
+
+ gcc_checking_assert (identifier_p (id));
+ tree decl = lookup_qualified_name (ctx, id);
+ if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
+ {
+ if (complain & tf_error)
+ qualified_name_lookup_error (ctx, id, decl, input_location);
+ return error_mark_node;
+ }
+ if (targs)
+ {
+ f = lookup_template_class (decl, targs, in_decl, NULL_TREE,
+ complain);
if (f == error_mark_node)
return error_mark_node;
}
+ else if (TREE_CODE (decl) == NAMESPACE_DECL)
+ return decl;
+ else if (TREE_CODE (decl) == TYPE_DECL)
+ f = TREE_TYPE (decl);
else
{
- gcc_assert (TREE_CODE (f) == IDENTIFIER_NODE);
- tree decl = lookup_qualified_name (ctx, f);
- if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
- {
- qualified_name_lookup_error (ctx, f, decl, input_location);
- return error_mark_node;
- }
- if (TREE_CODE (decl) == NAMESPACE_DECL)
- return decl;
- else
- {
- gcc_checking_assert (TREE_CODE (decl) == TYPE_DECL);
- f = TREE_TYPE (decl);
- }
+ if (complain & tf_error)
+ error ("%qD is not a type", decl);
+ return error_mark_node;
}
return cp_build_qualified_type
(f, cp_type_quals (f) | cp_type_quals (t), complain);
diff --git a/gcc/testsuite/g++.dg/reflect/ns7.C
b/gcc/testsuite/g++.dg/reflect/ns7.C
new file mode 100644
index 00000000000..a9ba862d77b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/ns7.C
@@ -0,0 +1,38 @@
+// PR c++/127349
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template<class> struct Y {};
+namespace M { template<class> struct W {}; }
+namespace N {
+ template<class> struct X {};
+ template<class T> using A = X<T>;
+ inline namespace I { template<class> struct V {}; }
+ using namespace M;
+ template<class, class> struct Z {};
+ int v;
+ template<class T> void fn ();
+}
+
+template<template<class> class> struct S {};
+
+template<auto ns>
+void
+f ()
+{
+ typename [:ns:]::template X<int> t1;
+ typename [:ns:]::template A<int> t2;
+ typename [:ns:]::template V<int> t3;
+ typename [:ns:]::template W<int> t4;
+ typename [:ns:]::template Y<int> t5; // { dg-error "'Y' is not a member of
'N'" }
+ typename [:ns:]::template v<int> t6; // { dg-error "'N::v' is not a
template" }
+ typename [:ns:]::v t7; // { dg-error "'N::v' is not a type" }
+ typename [:ns:]::X t8; // { dg-error "is not a type" }
+ typename [:ns:]::template fn<int> t9; // { dg-error "not a template" }
+}
+
+void
+h ()
+{
+ f<^^N>();
+}
base-commit: 6e6249fc9e9932909089bc5b8cb3618650c9e662
--
2.55.0