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>(); +}