Here we're neglecting to clear cp_unevaluated_operand when substituting
into the arguments of the alias template-id skip<(T(), 0), T> with T=A,
which means cp_unevaluated_operand remains set during mark_used for
A::A() and so we never synthesize it.  Later constant evaluation for
the substituted template argument (A(), 0) (during coerce_template_parms)
fails with "'constexpr A::A()' used before its definition" since it was
never synthesized.

This minimal patch makes us clear cp_unevaluated_operand when
substituting into the template arguments of an alias template-id, as in
tsubst_aggr_type.

(A few lines below we also substitute into the template arguments of a
class-scope typedef, during which we arguably also should clear
cp_unevaluated_operand, but I wasn't able to come up with a testcase for
which this mattered, because if we've named a class-scope typedef, then
at some point tsubst_aggr_type must have already substituted the class
scope, which performs the same substitution with cp_unevaluated_operand
cleared.)

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

        PR c++/101906

gcc/cp/ChangeLog:

        * pt.cc (tsubst): Clear cp_unevaluated_operand when substituting
        the template arguments of an alias template specialization.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp0x/alias-decl-75.C: New test.
        * g++.dg/cpp0x/alias-decl-75a.C: New test.
---
 gcc/cp/pt.cc                                |  6 +++++-
 gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C  | 15 +++++++++++++++
 gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C | 16 ++++++++++++++++
 3 files changed, 36 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 7697615ac64..c7116849551 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -15545,7 +15545,11 @@ tsubst (tree t, tree args, tsubst_flags_t complain, 
tree in_decl)
          /* DECL represents an alias template and we want to
             instantiate it.  */
          tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
-         tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
+         tree gen_args;
+           {
+             cp_evaluated ev;
+             gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
+           }
          r = instantiate_alias_template (tmpl, gen_args, complain);
        }
       else if (DECL_CLASS_SCOPE_P (decl)
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C 
b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C
new file mode 100644
index 00000000000..c6176751283
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C
@@ -0,0 +1,15 @@
+// PR c++/101906
+// { dg-do compile { target c++11 } }
+
+template<int, class T> using skip = T;
+
+template<class T>
+constexpr unsigned sizeof_() {
+  return sizeof(skip<(T(), 0), T>);
+}
+
+struct A {
+  int m = -1;
+};
+
+static_assert(sizeof_<A>() == sizeof(A), "");
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C 
b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C
new file mode 100644
index 00000000000..ce08a84f6d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C
@@ -0,0 +1,16 @@
+// PR c++/101906
+// Similar to alias-decl-75.C, but where the unevaluated context is a
+// constraint instead of sizeof.
+// { dg-do compile { target c++20 } }
+
+template<int> using voidify = void;
+
+template<class T>
+concept constant_value_initializable
+  = requires { typename voidify<(T(), 0)>; };
+
+struct A {
+  int m = -1;
+};
+
+static_assert(constant_value_initializable<A>);
-- 
2.35.1.607.gf01e51a7cf

Reply via email to