In a subsequent patch we'll add another flag to
tsubst_typename_type controlling whether we want to ignore non-types
during the qualified lookup.
gcc/cp/ChangeLog:
* cp-tree.h (enum tsubst_flags): Remove tf_keep_type_decl
and tf_tst_ok.
(make_typename_type): Add two trailing boolean parameters
defaulted to false.
* decl.cc (make_typename_type): Replace uses of
tf_keep_type_decl and tf_tst_ok with the corresponding new
boolean parameters.
* pt.cc (tsubst_typename_type): New, factored out from tsubst
and adjusted after removing tf_keep_type_decl and tf_tst_ok.
(tsubst_decl) <case VAR_DECL>: Conditionally call
tsubst_typename_type directly instead of using tf_tst_ok.
(tsubst) <case TYPENAME_TYPE>: Call tsubst_typename_type.
(tsubst_copy) <case CAST_EXPR>: Conditionally call
tsubst_typename_type directly instead of using tf_tst_ok.
(tsubst_copy_and_build) <case CAST_EXPR>: Likewise.
<case CONSTRUCTOR>: Likewise.
---
gcc/cp/cp-tree.h | 9 +-
gcc/cp/decl.cc | 17 ++--
gcc/cp/pt.cc | 223 +++++++++++++++++++++++++----------------------
3 files changed, 134 insertions(+), 115 deletions(-)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 06bc64a6b8d..a7c5765fc33 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5573,8 +5573,7 @@ enum tsubst_flags {
tf_error = 1 << 0, /* give error messages */
tf_warning = 1 << 1, /* give warnings too */
tf_ignore_bad_quals = 1 << 2, /* ignore bad cvr qualifiers */
- tf_keep_type_decl = 1 << 3, /* retain typedef type decls
- (make_typename_type use) */
+ /* 1 << 3 available */
tf_ptrmem_ok = 1 << 4, /* pointers to member ok (internal
instantiate_type use) */
tf_user = 1 << 5, /* found template must be a user template
@@ -5594,8 +5593,7 @@ enum tsubst_flags {
(build_target_expr and friends) */
tf_norm = 1 << 11, /* Build diagnostic information during
constraint normalization. */
- tf_tst_ok = 1 << 12, /* Allow a typename-specifier to name
- a template (C++17 or later). */
+ /* 1 << 12 available */
tf_dguide = 1 << 13, /* Building a deduction guide from a
ctor. */
/* Convenient substitution flags combinations. */
tf_warning_or_error = tf_warning | tf_error
@@ -6846,7 +6844,8 @@ extern tree declare_local_label (tree);
extern tree define_label (location_t, tree);
extern void check_goto (tree);
extern bool check_omp_return (void);
-extern tree make_typename_type (tree, tree, enum
tag_types, tsubst_flags_t);
+extern tree make_typename_type (tree, tree, enum
tag_types, tsubst_flags_t,
+ bool = false, bool = false);
extern tree build_typename_type (tree, tree, tree,
tag_types);
extern tree make_unbound_class_template (tree, tree, tree,
tsubst_flags_t);
extern tree make_unbound_class_template_raw (tree, tree, tree);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index d606b31d7a7..430533606b0 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -4228,14 +4228,17 @@ build_typename_type (tree context, tree name,
tree fullname,
/* Resolve `typename CONTEXT::NAME'. TAG_TYPE indicates the tag
provided to name the type. Returns an appropriate type, unless an
error occurs, in which case error_mark_node is returned. If we
- locate a non-artificial TYPE_DECL and TF_KEEP_TYPE_DECL is set, we
+ locate a non-artificial TYPE_DECL and KEEP_TYPE_DECL is true, we
return that, rather than the _TYPE it corresponds to, in other
- cases we look through the type decl. If TF_ERROR is set, complain
- about errors, otherwise be quiet. */
+ cases we look through the type decl. If TEMPLATE_OK is true and
+ we found a TEMPLATE_DECL then we return a CTAD placeholder for the
+ TEMPLATE_DECL. If TF_ERROR is set, complain about errors, otherwise
+ be quiet. */
tree
make_typename_type (tree context, tree name, enum tag_types tag_type,
- tsubst_flags_t complain)
+ tsubst_flags_t complain, bool keep_type_decl /* = false */,
+ bool template_ok /* = false */)
{
tree fullname;
tree t;
@@ -4352,8 +4355,8 @@ make_typename_type (tree context, tree name,
enum tag_types tag_type,
}
if (!want_template && TREE_CODE (t) != TYPE_DECL)
{
- if ((complain & tf_tst_ok) && cxx_dialect >= cxx17
- && DECL_TYPE_TEMPLATE_P (t))
+ if (template_ok && DECL_TYPE_TEMPLATE_P (t)
+ && cxx_dialect >= cxx17)
/* The caller permits this typename-specifier to name a template
(because it appears in a CTAD-enabled context). */;
else
@@ -4383,7 +4386,7 @@ make_typename_type (tree context, tree name,
enum tag_types tag_type,
t = TYPE_NAME (t);
}
- if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
+ if (DECL_ARTIFICIAL (t) || !keep_type_decl)
t = TREE_TYPE (t);
maybe_record_typedef_use (t);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e89dbf47097..bc47bf15d38 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -13949,6 +13949,94 @@ tsubst_aggr_type_1 (tree t,
return t;
}
+/* Substitute ARGS into the TYPENAME_TYPE T. The flag TEMPLATE_OK
+ is passed to make_typename_type. */
+
+static tree
+tsubst_typename_type (tree t, tree args, tsubst_flags_t complain,
tree in_decl,
+ bool template_ok = false)
+{
+ tree ctx = TYPE_CONTEXT (t);
+ if (TREE_CODE (ctx) == TYPE_PACK_EXPANSION)
+ {
+ ctx = tsubst_pack_expansion (ctx, args, complain, in_decl);
+ if (ctx == error_mark_node
+ || TREE_VEC_LENGTH (ctx) > 1)
+ return error_mark_node;
+ if (TREE_VEC_LENGTH (ctx) == 0)
+ {
+ if (complain & tf_error)
+ error ("%qD is instantiated for an empty pack",
+ TYPENAME_TYPE_FULLNAME (t));
+ return error_mark_node;
+ }
+ ctx = TREE_VEC_ELT (ctx, 0);
+ }
+ else
+ ctx = tsubst_aggr_type (ctx, args, complain, in_decl,
+ /*entering_scope=*/1);
+ if (ctx == error_mark_node)
+ return error_mark_node;
+
+ tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args,
+ complain, in_decl);
+ if (f == error_mark_node)
+ return error_mark_node;
+
+ if (!MAYBE_CLASS_TYPE_P (ctx))
+ {
+ if (complain & tf_error)
+ error ("%qT is not a class, struct, or union type", ctx);
+ return error_mark_node;
+ }
+ else if (!uses_template_parms (ctx) && !TYPE_BEING_DEFINED (ctx))
+ {
+ /* Normally, make_typename_type does not require that the CTX
+ have complete type in order to allow things like:
+
+ template <class T> struct S { typename S<T>::X Y; };
+
+ But, such constructs have already been resolved by this
+ point, so here CTX really should have complete type, unless
+ it's a partial instantiation. */
+ if (!complete_type_or_maybe_complain (ctx, NULL_TREE, complain))
+ return error_mark_node;
+ }
+
+ f = make_typename_type (ctx, f, typename_type, complain,
+ /*keep_type_decl=*/true, template_ok);
+ if (f == error_mark_node)
+ return f;
+ if (TREE_CODE (f) == TYPE_DECL)
+ {
+ complain |= tf_ignore_bad_quals;
+ f = TREE_TYPE (f);
+ }
+
+ if (TREE_CODE (f) != TYPENAME_TYPE)
+ {
+ if (TYPENAME_IS_ENUM_P (t) && TREE_CODE (f) != ENUMERAL_TYPE)
+ {
+ if (complain & tf_error)
+ error ("%qT resolves to %qT, which is not an enumeration type",
+ t, f);
+ else
+ return error_mark_node;
+ }
+ else if (TYPENAME_IS_CLASS_P (t) && !CLASS_TYPE_P (f))
+ {
+ if (complain & tf_error)
+ error ("%qT resolves to %qT, which is not a class type",
+ t, f);
+ else
+ return error_mark_node;
+ }
+ }
+
+ return cp_build_qualified_type
+ (f, cp_type_quals (f) | cp_type_quals (t), complain);
+}
+
/* Map from a FUNCTION_DECL to a vec of default argument
instantiations,
indexed in reverse order of the parameters. */
@@ -15193,10 +15281,13 @@ tsubst_decl (tree t, tree args,
tsubst_flags_t complain)
&& VAR_HAD_UNKNOWN_BOUND (t)
&& type != error_mark_node)
type = strip_array_domain (type);
- tsubst_flags_t tcomplain = complain;
- if (VAR_P (t))
- tcomplain |= tf_tst_ok;
- type = tsubst (type, args, tcomplain, in_decl);
+ if (VAR_P (t)
+ && TREE_CODE (type) == TYPENAME_TYPE
+ && !typedef_variant_p (type))
+ type = tsubst_typename_type (type, args, complain, in_decl,
+ /*template_ok=*/true);
+ else
+ type = tsubst (type, args, complain, in_decl);
/* Substituting the type might have recursively instantiated
this
same alias (c++/86171). */
if (gen_tmpl && DECL_ALIAS_TEMPLATE_P (gen_tmpl)
@@ -15889,9 +15980,6 @@ tsubst (tree t, tree args, tsubst_flags_t
complain, tree in_decl)
bool fndecl_type = (complain & tf_fndecl_type);
complain &= ~tf_fndecl_type;
- bool tst_ok = (complain & tf_tst_ok);
- complain &= ~tf_tst_ok;
-
if (type
&& code != TYPENAME_TYPE
&& code != TEMPLATE_TYPE_PARM
@@ -16424,89 +16512,7 @@ tsubst (tree t, tree args, tsubst_flags_t
complain, tree in_decl)
}
case TYPENAME_TYPE:
- {
- tree ctx = TYPE_CONTEXT (t);
- if (TREE_CODE (ctx) == TYPE_PACK_EXPANSION)
- {
- ctx = tsubst_pack_expansion (ctx, args, complain, in_decl);
- if (ctx == error_mark_node
- || TREE_VEC_LENGTH (ctx) > 1)
- return error_mark_node;
- if (TREE_VEC_LENGTH (ctx) == 0)
- {
- if (complain & tf_error)
- error ("%qD is instantiated for an empty pack",
- TYPENAME_TYPE_FULLNAME (t));
- return error_mark_node;
- }
- ctx = TREE_VEC_ELT (ctx, 0);
- }
- else
- ctx = tsubst_aggr_type (ctx, args, complain, in_decl,
- /*entering_scope=*/1);
- if (ctx == error_mark_node)
- return error_mark_node;
-
- tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args,
- complain, in_decl);
- if (f == error_mark_node)
- return error_mark_node;
-
- if (!MAYBE_CLASS_TYPE_P (ctx))
- {
- if (complain & tf_error)
- error ("%qT is not a class, struct, or union type", ctx);
- return error_mark_node;
- }
- else if (!uses_template_parms (ctx) && !TYPE_BEING_DEFINED (ctx))
- {
- /* Normally, make_typename_type does not require that the CTX
- have complete type in order to allow things like:
-
- template <class T> struct S { typename S<T>::X Y; };
-
- But, such constructs have already been resolved by this
- point, so here CTX really should have complete type, unless
- it's a partial instantiation. */
- if (!complete_type_or_maybe_complain (ctx, NULL_TREE, complain))
- return error_mark_node;
- }
-
- tsubst_flags_t tcomplain = complain | tf_keep_type_decl;
- if (tst_ok)
- tcomplain |= tf_tst_ok;
- f = make_typename_type (ctx, f, typename_type, tcomplain);
- if (f == error_mark_node)
- return f;
- if (TREE_CODE (f) == TYPE_DECL)
- {
- complain |= tf_ignore_bad_quals;
- f = TREE_TYPE (f);
- }
-
- if (TREE_CODE (f) != TYPENAME_TYPE)
- {
- if (TYPENAME_IS_ENUM_P (t) && TREE_CODE (f) != ENUMERAL_TYPE)
- {
- if (complain & tf_error)
- error ("%qT resolves to %qT, which is not an enumeration
type",
- t, f);
- else
- return error_mark_node;
- }
- else if (TYPENAME_IS_CLASS_P (t) && !CLASS_TYPE_P (f))
- {
- if (complain & tf_error)
- error ("%qT resolves to %qT, which is not a class type",
- t, f);
- else
- return error_mark_node;
- }
- }
-
- return cp_build_qualified_type
- (f, cp_type_quals (f) | cp_type_quals (t), complain);
- }
+ return tsubst_typename_type (t, args, complain, in_decl);
case UNBOUND_CLASS_TEMPLATE:
{
@@ -17391,10 +17397,14 @@ tsubst_copy (tree t, tree args,
tsubst_flags_t complain, tree in_decl)
case IMPLICIT_CONV_EXPR:
CASE_CONVERT:
{
- tsubst_flags_t tcomplain = complain;
- if (code == CAST_EXPR)
- tcomplain |= tf_tst_ok;
- tree type = tsubst (TREE_TYPE (t), args, tcomplain, in_decl);
+ tree type = TREE_TYPE (t);
+ if (code == CAST_EXPR
+ && TREE_CODE (type) == TYPENAME_TYPE
+ && !typedef_variant_p (type))
+ type = tsubst_typename_type (type, args, complain, in_decl,
+ /*template_ok=*/true);
+ else
+ type = tsubst (type, args, complain, in_decl);
tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain,
in_decl);
return build1 (code, type, op0);
}
@@ -20430,13 +20440,16 @@ tsubst_copy_and_build (tree t,
case DYNAMIC_CAST_EXPR:
case STATIC_CAST_EXPR:
{
- tree type;
+ tree type = TREE_TYPE (t);
tree op, r = NULL_TREE;
- tsubst_flags_t tcomplain = complain;
- if (TREE_CODE (t) == CAST_EXPR)
- tcomplain |= tf_tst_ok;
- type = tsubst (TREE_TYPE (t), args, tcomplain, in_decl);
+ if (TREE_CODE (t) == CAST_EXPR
+ && TREE_CODE (type) == TYPENAME_TYPE
+ && !typedef_variant_p (type))
+ type = tsubst_typename_type (type, args, complain, in_decl,
+ /*template_ok=*/true);
+ else
+ type = tsubst (type, args, complain, in_decl);
op = RECUR (TREE_OPERAND (t, 0));
@@ -21421,10 +21434,14 @@ tsubst_copy_and_build (tree t,
bool need_copy_p = false;
tree r;
- tsubst_flags_t tcomplain = complain;
- if (COMPOUND_LITERAL_P (t))
- tcomplain |= tf_tst_ok;
- tree type = tsubst (TREE_TYPE (t), args, tcomplain, in_decl);
+ tree type = TREE_TYPE (t);
+ if (COMPOUND_LITERAL_P (t)
+ && TREE_CODE (type) == TYPENAME_TYPE
+ && !typedef_variant_p (type))
+ type = tsubst_typename_type (type, args, complain, in_decl,
+ /*template_ok=*/true);
+ else
+ type = tsubst (type, args, complain, in_decl);
if (type == error_mark_node)
RETURN (error_mark_node);