On 9/13/26 3:27 PM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
OK.
-- >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
