This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: C++ PATCH for c++/85200, ICE with constexpr if in generic lambda


On Wed, Apr 4, 2018 at 2:57 PM, Jason Merrill <jason@redhat.com> wrote:
> Since, during partial instantiation of a generic lambda, we don't
> substitute into the body of a constexpr if, we don't do lambda capture
> as part of substitution.  But extract_locals_r is supposed to do it as
> part of remembering the substitution context to be used later.
>
> As it turns out, this was failing because walk_tree_1 expects the
> DECL_INITIAL of a local variable to be walked in the context of the
> BIND_EXPR, but we don't build BIND_EXPRs for compound-statements in a
> template.  So in a template, let's walk the fields of a VAR_DECL from
> its DECL_EXPR.

...but I forgot to also check the original testcase, which was also
failing for a different reason: we were remembering the mapping from
fully general to partially instantiated even for the condition
variable of the constexpr if, which is wrong because we are discarding
that instantiation at this point, so using it in a later instantiation
breaks.

I also considered specifically removing the condition variable from
local_instantiations, but this more general approach seems safer.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit a4b63e3bd89af40e316b1f16f0bba9001cf8b351
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Apr 5 09:12:05 2018 -0400

            PR c++/85200 - ICE with constexpr if in generic lambda.
    
            * pt.c (extract_locals_r): Don't record the local specs of variables
            declared within the pattern.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 741c578b65b..204e390353c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11597,8 +11597,12 @@ tsubst_binary_right_fold (tree t, tree args, tsubst_flags_t complain,
 
 struct el_data
 {
+  hash_set<tree> internal;
   tree extra;
   tsubst_flags_t complain;
+
+  el_data (tsubst_flags_t c)
+    : extra(NULL_TREE), complain(c) {}
 };
 static tree
 extract_locals_r (tree *tp, int */*walk_subtrees*/, void *data_)
@@ -11606,8 +11610,13 @@ extract_locals_r (tree *tp, int */*walk_subtrees*/, void *data_)
   el_data &data = *reinterpret_cast<el_data*>(data_);
   tree *extra = &data.extra;
   tsubst_flags_t complain = data.complain;
-  if (tree spec = retrieve_local_specialization (*tp))
+  if (TREE_CODE (*tp) == DECL_EXPR)
+    data.internal.add (DECL_EXPR_DECL (*tp));
+  else if (tree spec = retrieve_local_specialization (*tp))
     {
+      if (data.internal.contains (*tp))
+	/* Don't mess with variables declared within the pattern.  */
+	return NULL_TREE;
       if (TREE_CODE (spec) == NONTYPE_ARGUMENT_PACK)
 	{
 	  /* Maybe pull out the PARM_DECL for a partial instantiation.  */
@@ -11658,7 +11667,7 @@ extract_locals_r (tree *tp, int */*walk_subtrees*/, void *data_)
 static tree
 extract_local_specs (tree pattern, tsubst_flags_t complain)
 {
-  el_data data = { NULL_TREE, complain };
+  el_data data (complain);
   cp_walk_tree_without_duplicates (&pattern, extract_locals_r, &data);
   return data.extra;
 }
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if19.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if19.C
new file mode 100644
index 00000000000..40016a5b7e1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if19.C
@@ -0,0 +1,17 @@
+// PR c++/85200
+// { dg-additional-options -std=c++17 }
+
+struct A{
+    constexpr operator int(){ return 0; }
+};
+
+template < typename >
+void f(){
+    [](auto known){
+        if constexpr(constexpr int k = known);
+    }(A{});
+}
+
+int main(){
+    f<int>();
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]