From: Jason Merrill Date: Thu, 10 Nov 2016 21:42:36 +0000 (-0500) Subject: PR c++/77337 - auto return and lambda X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f065303fcf9aa29bf376cf9db985b81d338d7709;p=gcc.git PR c++/77337 - auto return and lambda * pt.c (tsubst_friend_function): Don't set DECL_INITIAL. (instantiate_decl): It's OK to defer a constexpr function. * cp-tree.h (DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION): Check DECL_LANG_SPECIFIC. * decl2.c (decl_defined_p): Use it. No longer static. * decl.c (redeclaration_error_message): Use decl_defined_p. * constexpr.c (cxx_eval_call_expression): Set input_location around call to instantiate_decl. From-SVN: r242056 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b19a236f215..678c44d5d40 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2016-11-10 Jason Merrill + + PR c++/77337 + * pt.c (tsubst_friend_function): Don't set DECL_INITIAL. + (instantiate_decl): It's OK to defer a constexpr function. + * cp-tree.h (DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION): Check + DECL_LANG_SPECIFIC. + * decl2.c (decl_defined_p): Use it. No longer static. + * decl.c (redeclaration_error_message): Use decl_defined_p. + * constexpr.c (cxx_eval_call_expression): Set input_location around + call to instantiate_decl. + 2016-11-10 Jakub Jelinek * mangle.c (mangle_decl): Only emit -Wc++1z-compat warnings for diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 43457d2463f..f75f0b039fa 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1464,9 +1464,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, if (!DECL_INITIAL (fun) && DECL_TEMPLOID_INSTANTIATION (fun)) { + location_t save_loc = input_location; + input_location = loc; ++function_depth; instantiate_decl (fun, /*defer_ok*/false, /*expl_inst*/false); --function_depth; + input_location = save_loc; } /* If in direct recursive call, optimize definition search. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9b5b5bc9bdb..8183775b49e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4380,7 +4380,8 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) instantiated will not be a DECL_TEMPLATE_INSTANTIATION, but will be a DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION. */ #define DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION(DECL) \ - (DECL_TEMPLATE_INFO (DECL) && !DECL_USE_TEMPLATE (DECL)) + (DECL_LANG_SPECIFIC (DECL) && DECL_TEMPLATE_INFO (DECL) \ + && !DECL_USE_TEMPLATE (DECL)) /* Nonzero if DECL is a function generated from a function 'temploid', i.e. template, member of class template, or dependent friend. */ @@ -5895,6 +5896,7 @@ extern void import_export_decl (tree); extern tree build_cleanup (tree); extern tree build_offset_ref_call_from_tree (tree, vec **, tsubst_flags_t); +extern bool decl_defined_p (tree); extern bool decl_constant_var_p (tree); extern bool decl_maybe_constant_var_p (tree); extern void no_linkage_error (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 4b18d4ea761..185c98bebb8 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2778,8 +2778,8 @@ redeclaration_error_message (tree newdecl, tree olddecl) warn_extern_redeclared_static. */ /* Defining the same name twice is no good. */ - if (DECL_INITIAL (olddecl) != NULL_TREE - && DECL_INITIAL (newdecl) != NULL_TREE) + if (decl_defined_p (olddecl) + && decl_defined_p (newdecl)) { if (DECL_NAME (olddecl) == NULL_TREE) return G_("%q#D not declared in class"); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index e0fff1e81c5..4ebc7dca8d6 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -80,7 +80,6 @@ static void import_export_class (tree); static tree get_guard_bits (tree); static void determine_visibility_from_class (tree, tree); static bool determine_hidden_inline (tree); -static bool decl_defined_p (tree); static void maybe_instantiate_decl (tree); /* A list of static class variables. This is needed, because a @@ -4085,11 +4084,15 @@ collect_ada_namespace (tree namespc, const char *source_file) /* Returns true iff there is a definition available for variable or function DECL. */ -static bool +bool decl_defined_p (tree decl) { if (TREE_CODE (decl) == FUNCTION_DECL) - return (DECL_INITIAL (decl) != NULL_TREE); + return (DECL_INITIAL (decl) != NULL_TREE + /* A pending instantiation of a friend temploid is defined. */ + || (DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl) + && DECL_INITIAL (DECL_TEMPLATE_RESULT + (DECL_TI_TEMPLATE (decl))))); else { gcc_assert (VAR_P (decl)); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index e8b6afd13ab..d4855d5bc35 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -9383,10 +9383,6 @@ tsubst_friend_function (tree decl, tree args) else new_friend_result_template_info = NULL_TREE; - /* Make the init_value nonzero so pushdecl knows this is a defn. */ - if (new_friend_is_defn) - DECL_INITIAL (new_friend) = error_mark_node; - /* Inside pushdecl_namespace_level, we will push into the current namespace. However, the friend function should go into the namespace of the template. */ @@ -22086,8 +22082,7 @@ instantiate_decl (tree d, int defer_ok, case that an expression refers to the value of the variable -- if the variable has a constant value the referring expression can take advantage of that fact. */ - if (VAR_P (d) - || DECL_DECLARED_CONSTEXPR_P (d)) + if (VAR_P (d)) defer_ok = 0; /* Don't instantiate cloned functions. Instead, instantiate the diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn33.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn33.C new file mode 100644 index 00000000000..cfd84981503 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn33.C @@ -0,0 +1,27 @@ +// PR c++/77337 +// { dg-do compile { target c++14 } } + +template +struct fix_type { + Functor functor; + + decltype(auto) operator()() + { return functor(*this); } +}; + +template +fix_type fix(Functor functor) +{ return { functor }; } + +int main() +{ + auto zero = fix + ([](auto& self) -> int // N.B. non-deduced, non-dependent return type + { + return 0; + + self(); // error: use of 'decltype(auto) fix_type::operator()() [with Functor = main()::]' before deduction of 'auto' + }); + + return zero(); +}