This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] PR c++/55663 - constexpr function templ instantiation considered non-const as alias templ arg
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
> I read your reply. I am now even more puzzled
> than before. The call to uses_template_parm indicates that
> we expect that code to work when are also when processing a template
> (e.g. for non-dependent cases inside a template.)
> That makes me wonder how it could possibly work for the
> cases at hand because for non-type template arguments we need
> full instantiation information to determine convertibility and
> "constant"ness.
I introduced the confusion, sorry. I overlooked the fact that this is
actually happening while calling instantiate_alias_template on Alias
with the argument the_thruth<int> non folded. In that code patch, we
didn't even go through convert_template_argument like what I was saying.
More on this below.
Jason Merrill <jason@redhat.com> writes:
> On 01/09/2013 10:02 AM, Dodji Seketeli wrote:
>> As the argument 'the_truth<T>()' we care about is type dependant,
>> uses_template_parms returns true and so convert_nontype_argument is
>> never called.
>
> Right, but we should call it for the instantiated argument, too. We
> do that for class templates by calling lookup_template_class again,
> which calls coerce_template_parms. We need to make sure we call
> coerce_template_parms when instantiating alias templates, too.
Indeed.
The problem is happening during the instantiation of test<int> using
instantiate_class_template. In that case the argument {int} was
previously properly coerced and stored in CLASSTYPE_TI_ARGS by
lookup_class_template, as you are saying. So instantiate_class_template
always uses coerced arguments.
But during the instantiation of the *members* of test<int>, we try to
instantiate Alias<the_truth<int>>, without coercing (and thus without
folding) the argument {the_truth<int>}. We do this using
instantiate_alias_template, called from tsubst.
The patch below makes sure instantiate_alias_template coerces the
arguments it uses to instantiate the alias template, like what I
understood you are suggesting. I have tested it without boostrap and a
full boostrap is currently running.
If this approach looks acceptable, could I replace (part of) the
template argument coercing code in lookup_class_template_1 with the new
coerce_template_parms_all_level I introduced in this patch?
Also, I am not sure if this patch would be appropriate for commit, now
that we are in 'regression-only' mode. But seeing this alias-template
related thing not working hurts me. :) So at worst I'll schedule the
patch for when stage1 opens again.
Thanks.
gcc/cp/
PR c++/55663
* pt.c (coerce_template_parms_all_levels): New static function.
(instantiate_alias_template): Use it here.
gcc/testsuite/
PR c++/55663
* g++.dg/cpp0x/alias-decl-31.C: New test.
---
gcc/cp/pt.c | 64 +++++++++++++++++++++++++++++-
gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C | 20 ++++++++++
2 files changed, 83 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 30bafa0..aadc173 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -130,6 +130,8 @@ static tree tsubst_initializer_list (tree, tree);
static tree get_class_bindings (tree, tree, tree, tree);
static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t,
bool, bool);
+static tree coerce_template_parms_all_levels (tree, tree, tree, tsubst_flags_t,
+ bool, bool);
static void tsubst_enum (tree, tree, tree);
static tree add_to_template_args (tree, tree);
static tree add_outermost_template_args (tree, tree);
@@ -6742,6 +6744,58 @@ coerce_template_parms (tree parms,
return new_inner_args;
}
+/* Like coerce_template_parms. If PARMS represents all template
+ parameters levels, this function returns a vector of vectors
+ representing all the resulting argument levels. Note that in this
+ case, only the innermost arguments are coerced because the
+ outermost ones are supposed to have been coerced already.
+
+ Otherwise, if PARMS represents only (the innermost) vectors of
+ parameters, returns a vector containing just the innermost
+ resulting arguments. */
+
+static tree
+coerce_template_parms_all_levels (tree parms,
+ tree args,
+ tree in_decl,
+ tsubst_flags_t complain,
+ bool require_all_args,
+ bool use_default_args)
+{
+ int parms_depth = TMPL_PARMS_DEPTH (parms);
+ int args_depth = TMPL_ARGS_DEPTH (args);
+ tree coerced_args;
+
+ if (parms_depth > 1)
+ {
+ coerced_args = make_tree_vec (parms_depth);
+ tree level;
+ int cur_depth;
+
+ for (level = parms, cur_depth = parms_depth;
+ parms_depth > 0 && level != NULL_TREE;
+ level = TREE_CHAIN (level), --cur_depth)
+ {
+ tree l;
+ if (cur_depth == args_depth)
+ l = coerce_template_parms (TREE_VALUE (level),
+ args, in_decl, complain,
+ require_all_args,
+ use_default_args);
+ else
+ l = TMPL_ARGS_LEVEL (args, cur_depth);
+
+ SET_TMPL_ARGS_LEVEL (coerced_args, cur_depth, l);
+ }
+ }
+ else
+ coerced_args = coerce_template_parms (INNERMOST_TEMPLATE_PARMS (parms),
+ args, in_decl, complain,
+ require_all_args,
+ use_default_args);
+ return coerced_args;
+}
+
/* Returns 1 if template args OT and NT are equivalent. */
static int
@@ -14637,7 +14691,15 @@ instantiate_alias_template (tree tmpl, tree args, tsubst_flags_t complain)
ggc_free (tinst);
return error_mark_node;
}
- tree r = instantiate_template (tmpl, args, complain);
+
+ tree coerced_args =
+ coerce_template_parms_all_levels (DECL_TEMPLATE_PARMS (tmpl),
+ args, tmpl, complain,
+ /*require_all_args=*/true,
+ /*use_default_args=*/true);
+
+ tree r = instantiate_template (tmpl, coerced_args, complain);
+
pop_tinst_level ();
/* We can't free this if a pending_template entry or last_error_tinst_level
is pointing at it. */
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C
new file mode 100644
index 0000000..83eea47
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C
@@ -0,0 +1,20 @@
+// Origin: PR c++/55663
+// { dg-do compile { target c++11 } }
+
+template <typename>
+constexpr bool the_truth () { return true; }
+
+template <bool>
+ struct Takes_bool { };
+
+template<bool B>
+ using Alias = Takes_bool<B>;
+
+template<typename T>
+ struct test { using type = Alias<the_truth<T>()>; };
+
+int main () {
+ test<int> a;
+
+ return 0;
+}
--
Dodji