The problem in this testcase was that we were calling get_nsdmi from
template context, and then calling set_flags_from_callee on the
resulting CALL_EXPR, which doesn't work in a template.  Furthermore,
we would then store the template-context trees for the NSDMI in the
hash table, where they would confuse a later user from non-template
context.

Fixed by setting up the proper context when instantiating an NSDMI.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 8cf9e07d2c9b9825cc39fb13673f846ba0703e07
Author: Jason Merrill <ja...@redhat.com>
Date:   Thu May 24 13:41:41 2018 -0400

            PR c++/85807 - ICE with call in template NSDMI.
    
            * init.c (get_nsdmi): Use push_to/pop_from_top_level.
            * tree.c (bot_manip): Don't set_flags_from_callee in a template.

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 24119d18802..acf9c9b7c32 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -577,6 +577,16 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain)
 
 	  DECL_INSTANTIATING_NSDMI_P (member) = 1;
 
+	  bool pushed = false;
+	  if (!currently_open_class (DECL_CONTEXT (member)))
+	    {
+	      push_to_top_level ();
+	      push_nested_class (DECL_CONTEXT (member));
+	      pushed = true;
+	    }
+
+	  gcc_checking_assert (!processing_template_decl);
+
 	  inject_this_parameter (DECL_CONTEXT (member), TYPE_UNQUALIFIED);
 
 	  start_lambda_scope (member);
@@ -599,6 +609,12 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain)
 	      nsdmi_inst->put (member, init);
 	    }
 
+	  if (pushed)
+	    {
+	      pop_nested_class ();
+	      pop_from_top_level ();
+	    }
+
 	  input_location = sloc;
 	  cp_unevaluated_operand = un;
 	}
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 53bc9c7176f..4bb2879dc59 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -3015,7 +3015,8 @@ bot_manip (tree* tp, int* walk_subtrees, void* data_)
   /* Make a copy of this node.  */
   t = copy_tree_r (tp, walk_subtrees, NULL);
   if (TREE_CODE (*tp) == CALL_EXPR || TREE_CODE (*tp) == AGGR_INIT_EXPR)
-    set_flags_from_callee (*tp);
+    if (!processing_template_decl)
+      set_flags_from_callee (*tp);
   if (data.clear_location && EXPR_HAS_LOCATION (*tp))
     SET_EXPR_LOCATION (*tp, input_location);
   return t;
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice14.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice14.C
index 77203794133..d386f871a2e 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice14.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice14.C
@@ -8,7 +8,7 @@ template<typename R, typename... Args>
 struct function<R (Args...)>
 {
   template<typename F>
-  function(const F&);
+  function(const F&) { }
 };
 
 template<typename T>
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nsdmi8.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nsdmi8.C
index 8c0adfad45f..5f58991b5d4 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nsdmi8.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nsdmi8.C
@@ -6,7 +6,7 @@ class A {
 
 public:
   template <typename _Functor, typename = _Requires<_Functor, void>>
-  A(_Functor);
+  A(_Functor) { }
 };
 template <class T> class B {
   A f = [](T) {};
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-template17.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-template17.C
new file mode 100644
index 00000000000..6a5c5e48f20
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-template17.C
@@ -0,0 +1,25 @@
+// PR c++/85807
+// { dg-do compile { target c++11 } }
+
+template <class T>
+struct limits
+{
+  static T max();
+};
+
+template< class ScalarT = double >
+struct value_statistics_t
+{
+  double median = limits<double>::max();
+};
+
+template< class T > // required
+value_statistics_t<> calc()
+{
+  return {};
+}
+
+int main()
+{
+  value_statistics_t<> wstats = calc<double>();
+}

Reply via email to