From 1b5695e6100dec3f7c1e86ba5594471987cda466 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 19 Nov 2014 22:25:26 -0500 Subject: [PATCH] re PR c++/56041 (Constexpr conversion function definition not found in template argument context) PR c++/56041 * cp-tree.h (struct processing_template_decl_sentinel): New. * pt.c (instantiate_non_dependent_expr_internal): Split out from... (instantiate_non_dependent_expr_sfinae): Here. (convert_nontype_argument): Use them. * constexpr.c (fold_non_dependent_expr): Use them. From-SVN: r217823 --- gcc/cp/ChangeLog | 7 +++ gcc/cp/constexpr.c | 13 +----- gcc/cp/cp-tree.h | 23 +++++++++- gcc/cp/pt.c | 45 ++++++++++++++------ gcc/testsuite/g++.dg/cpp0x/constexpr-conv1.C | 34 +++++++++++++++ 5 files changed, 96 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-conv1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8f21d8b1146..09781410a19 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,12 @@ 2014-11-19 Jason Merrill + PR c++/56041 + * cp-tree.h (struct processing_template_decl_sentinel): New. + * pt.c (instantiate_non_dependent_expr_internal): Split out from... + (instantiate_non_dependent_expr_sfinae): Here. + (convert_nontype_argument): Use them. + * constexpr.c (fold_non_dependent_expr): Use them. + PR c++/63885 * constexpr.c (cxx_eval_constant_expression) [PARM_DECL]: Don't complain yet about a reference. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 41867b8dc28..2678223a603 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3506,17 +3506,8 @@ fold_non_dependent_expr (tree t) if (!instantiation_dependent_expression_p (t) && potential_constant_expression (t)) { - HOST_WIDE_INT saved_processing_template_decl; - - saved_processing_template_decl = processing_template_decl; - processing_template_decl = 0; - t = tsubst_copy_and_build (t, - /*args=*/NULL_TREE, - tf_none, - /*in_decl=*/NULL_TREE, - /*function_p=*/false, - /*integral_constant_expression_p=*/true); - processing_template_decl = saved_processing_template_decl; + processing_template_decl_sentinel s; + t = instantiate_non_dependent_expr_internal (t, tf_none); if (type_unknown_p (t) || BRACE_ENCLOSED_INITIALIZER_P (t)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 1e09629b4af..b3781ab7a72 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1082,6 +1082,8 @@ struct GTY(()) saved_scope { struct saved_scope *prev; }; +extern GTY(()) struct saved_scope *scope_chain; + /* The current open namespace. */ #define current_namespace scope_chain->old_namespace @@ -1123,6 +1125,24 @@ struct GTY(()) saved_scope { #define processing_specialization scope_chain->x_processing_specialization #define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation +/* RAII sentinel to handle clearing processing_template_decl and restoring + it when done. */ + +struct processing_template_decl_sentinel +{ + int saved; + processing_template_decl_sentinel (bool reset = true) + : saved (processing_template_decl) + { + if (reset) + processing_template_decl = 0; + } + ~processing_template_decl_sentinel() + { + processing_template_decl = saved; + } +}; + /* The cached class binding level, from the most recently exited class, or NULL if none. */ @@ -1140,8 +1160,6 @@ struct GTY(()) saved_scope { /* A list of private types mentioned, for deferred access checking. */ -extern GTY(()) struct saved_scope *scope_chain; - struct GTY((for_user)) cxx_int_tree_map { unsigned int uid; tree to; @@ -5716,6 +5734,7 @@ extern void make_args_non_dependent (vec *); extern bool reregister_specialization (tree, tree, tree); extern tree instantiate_non_dependent_expr (tree); extern tree instantiate_non_dependent_expr_sfinae (tree, tsubst_flags_t); +extern tree instantiate_non_dependent_expr_internal (tree, tsubst_flags_t); extern bool alias_type_or_template_p (tree); extern bool alias_template_specialization_p (const_tree); extern bool dependent_alias_template_spec_p (const_tree); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 0b8fd7fd37f..05ca7062865 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5212,6 +5212,24 @@ redeclare_class_template (tree type, tree parms) return true; } +/* The actual substitution part of instantiate_non_dependent_expr_sfinae, + to be used when the caller has already checked + (processing_template_decl + && !instantiation_dependent_expression_p (expr) + && potential_constant_expression (expr)) + and cleared processing_template_decl. */ + +tree +instantiate_non_dependent_expr_internal (tree expr, tsubst_flags_t complain) +{ + return tsubst_copy_and_build (expr, + /*args=*/NULL_TREE, + complain, + /*in_decl=*/NULL_TREE, + /*function_p=*/false, + /*integral_constant_expression_p=*/true); +} + /* Simplify EXPR if it is a non-dependent expression. Returns the (possibly simplified) expression. */ @@ -5232,17 +5250,8 @@ instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain) && !instantiation_dependent_expression_p (expr) && potential_constant_expression (expr)) { - HOST_WIDE_INT saved_processing_template_decl; - - saved_processing_template_decl = processing_template_decl; - processing_template_decl = 0; - expr = tsubst_copy_and_build (expr, - /*args=*/NULL_TREE, - complain, - /*in_decl=*/NULL_TREE, - /*function_p=*/false, - /*integral_constant_expression_p=*/true); - processing_template_decl = saved_processing_template_decl; + processing_template_decl_sentinel s; + expr = instantiate_non_dependent_expr_internal (expr, complain); } return expr; } @@ -5736,11 +5745,15 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) so that access checking can be performed when the template is instantiated -- but here we need the resolved form so that we can convert the argument. */ + bool non_dep = false; if (TYPE_REF_OBJ_P (type) && has_value_dependent_address (expr)) /* If we want the address and it's value-dependent, don't fold. */; - else if (!type_unknown_p (expr)) - expr = instantiate_non_dependent_expr_sfinae (expr, complain); + else if (!type_unknown_p (expr) + && processing_template_decl + && !instantiation_dependent_expression_p (expr) + && potential_constant_expression (expr)) + non_dep = true; if (error_operand_p (expr)) return error_mark_node; expr_type = TREE_TYPE (expr); @@ -5749,6 +5762,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) else expr = mark_rvalue_use (expr); + /* If the argument is non-dependent, perform any conversions in + non-dependent context as well. */ + processing_template_decl_sentinel s (non_dep); + if (non_dep) + expr = instantiate_non_dependent_expr_internal (expr, complain); + /* 14.3.2/5: The null pointer{,-to-member} conversion is applied to a non-type argument of "nullptr". */ if (expr == nullptr_node && TYPE_PTR_OR_PTRMEM_P (type)) diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-conv1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-conv1.C new file mode 100644 index 00000000000..fd34f23f9ee --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-conv1.C @@ -0,0 +1,34 @@ +// PR c++/56041 +// { dg-do compile { target c++11 } } + +template< class T, T v > +struct integral_constant +{ + using type = integral_constant; + using value_type = T; + static constexpr T value = v; + constexpr operator T ( ) noexcept { return value; } +}; + +using true_type = integral_constant; +using false_type = integral_constant; + +template< bool b, class T = void > struct enable_if { using type = T; }; +template< class T > struct enable_if { }; + + +template< class T, + class = typename enable_if< true_type{} // should compile; doesn't + , T>::type + > +T try_it( ) { return T{}; } + +int main( ) +{ + static_assert( true_type{} , "failed test 1!" ); + static_assert( true_type{} , "failed test 2!" ); + static_assert( ! false_type{} , "failed test 3!" ); + static_assert( !! true_type{} , "failed test 4!" ); + + return try_it(); +} -- 2.30.2